-
-
Notifications
You must be signed in to change notification settings - Fork 605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modularization/"Librarization" - create toolchain to optionally build custom kernel tailored to specific hypervisor or app #1110
Comments
wkozaczuk
added a commit
that referenced
this issue
Mar 11, 2022
V2: Comparing to the previous version this one improves the gen-drivers-config-header by using awk mechanism to evaluate environment variables. It also addresses couple of nitpicks. This patch introduces new build mechanism that allows creating custom kernel with specific list of device drivers intended to target given hypervisor. Such kernel benefits from smaller size and better security as all unneeded code is removed. This patch partially addresses the modularization/librarization functionality as explained by the issue #1110 and this part of the roadmap - https://github.com/cloudius-systems/osv/wiki/Roadmap#modularizationlibrarization. This idea was also mentioned in the P99 OSv presentation - see slide 11. In essence, we introduce new build script and makefile parameter: `drivers_profile`. This new parameter is intended to specify a drivers profile which is simply a list of device drivers to be linked into kernel with some extra functionality like PCI or ACPI these drivers depend on. Each profile is specified in a tiny make include file (*.mk) under new conf/profiles/$(arch) directory and included by the main makefile as requested by drivers_profile parameter. The main makefile has number of new ifeq conditions that add given driver object file to the linked objects list depending on the value (0 or 1) of given conf_drivers_* variable specified in the relevant profile file. Sometimes it is necessary to conditionally enable/disable given code depending on the drivers selected. The good example of it is arch-setup.cc which actually registers individual drivers and this is where we need some kind of #if-way of registering given driver. To that end, this patch adds new script gen-drivers-config-header and new rule to the makefile, which automatically generates driver-config.h header file under build/$(mode)/gen/include/osv. The driver-config.h is comprised of the #define CONF_drivers_* macros that specify if given driver is enabled or not (1, 0) and is included by relatively few source file like arch-setup.cc. The extra benefit of this approach is that every time we change value of drivers_profile, all relevant files are recompiled and new kernel linked. Most of the patch are changes to the relevant source file to include new #if CONF_drivers_* conditional logic, changes to the main makefile to conditionality link specific object files and new makefile include file under conf/profiles/. The benefits of using drivers are most profound when building kernel with most symbols hidden. Below you can see examples of some build commands along with the kernel size produced: ./scripts/build fs=rofs conf_hide_symbols=1 image=native-example #all 3632K build/release/kernel-stripped.elf ./scripts/build fs=rofs conf_hide_symbols=1 image=native-example drivers_profile=virtio-pci 3380K build/release/kernel-stripped.elf ./scripts/build fs=rofs conf_hide_symbols=1 image=native-example drivers_profile=vmware 3308K build/release/kernel-stripped.elf ./scripts/build fs=rofs conf_hide_symbols=1 image=native-example drivers_profile=virtio-mmio 3120K build/release/kernel-stripped.elf ./scripts/build fs=rofs conf_hide_symbols=1 image=native-example drivers_profile=base #most drivers out 3036K build/release/kernel-stripped.elf It is also possible to enable or disable individual drivers on top of what given profiles defines like so: ./scripts/build fs=rofs conf_hide_symbols=1 image=native-example drivers_profile=base \ conf_drivers_acpi=1 conf_drivers_virtio_fs=1 conf_drivers_virtio_net=1 conf_drivers_pvpanic=1 Partially addresses #1110 Signed-off-by: Waldemar Kozaczuk <jwkozaczuk@gmail.com>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Currently, OSv kernel provides quite a significant subset of the functionality of some standard Linux libraries listed here - https://github.com/cloudius-systems/osv#kernel-size. In reality, many applications do not need all of this functionality, but they "get it" whether they need it or not. Even Java, which used to need lots of symbols from standard libraries, has become way more modular, and with the advent of GraalVM and other AOT-type technologies, OSv kernel does not need to provide all this functionality universally to every app. Worse, if you run an app on Firecracker which needs console, non-PCI virtio-blk and virtio-net drivers only, one gets all other drivers including ones for VirtualBox, Xen, VMware, etc. This actually makes OSv barely a unikernel or at best a "fat" one. This has some real negative consequences - higher memory utilization (kernel needs to be loaded in memory), larger kernel file (makes decompression longer), and poorer security because of the fairly vast number of exported symbols (at this moment everything non-static gets exported) and finally possibly less optimized code. On the other hand, because of this "universality", it is quite easy, comparing to other unikernels, to run an arbitrary Linux app on OSv. And no matter what we do to make OSv more modular, we should preserve that "ease" and not make it harder, at least by default, to run an app on OSv.
So in general, what I am advocating for, is an ability (and a mechanism) to create more "stripped-down" versions of kernels tailored to the need of specific app and/or specific hypervisor OSv will run on while preserving the default universal kernel. And also shrinking the universal kernel by extracting optional functionality from it, where it makes sense and is relatively easy to do so, as a shared library to be loaded during the boot process. The latter should also ideally involve the build process (compile/link) optimizations.
In the end, what I am proposing could be organized into the following three categories:
Addressing 3) could help us with another issue - Combining pre-compiled OSv kernel with pre-compiled executable. To that end, we could also consider creating a mechanism that would let us build a stripped-down version of the kernel with functionality exposed through SYSCALL instruction only and no built-in musl (except for dynamic linker function (
dlopen
, etc)) and libc and let one mix in original pre-built musl library which would interact with kernel through those SYSCALL calls. This would require probably exposing more functions as SYSCALL than we have now in linux.cc - at least brk and clone. I am not sure if that is even feasible but I think I think at least one of the unikernels does just this - Hermitux.Please note that addressing this issue depends on #97.
The text was updated successfully, but these errors were encountered: