- Notifications
You must be signed in to change notification settings - Fork428
A fully Go userland with Linux bootloaders! u-root can create a one-binary root file system (initramfs) containing a busybox-like set of tools written in Go.
License
u-root/u-root
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
u-root embodies four different projects.
Go versions of many standard Linux tools, such asls,cp, orshutdown. Seecmds/core for most of these.
A way to compile many Go programs into a single binary withbusybox mode.
A way to create initramfs (an archive of files) to use with Linux kernels,embeddable into firmware.
Gobootloaders that use
kexec
to boot Linux or multibootkernels such as ESXi, Xen, or tboot. They are meant to be used withLinuxBoot.
For u-root on Linux, certain Kconfig options are necessary. Basic defconfigs areinconfigs/
. See also theconfigs README.
Make sure your Go version is >= 1.21.
Download and install u-root either via git:
git clone https://github.com/u-root/u-rootcd u-rootgo install
Or install directly with go:
go install github.com/u-root/u-root@latest
Note
Theu-root
command will end up in$GOPATH/bin/u-root
, so you mayneed to add$GOPATH/bin
to your$PATH
.
Here are some examples of using theu-root
command to build an initramfs.
git clone https://github.com/u-root/u-rootcd u-root# Build an initramfs of all the Go cmds in ./cmds/core/... (default)u-root# Generate an archive with bootloaders## core and boot are templates that expand to sets of commandsu-root core boot# Generate an archive with only these given commandsu-root ./cmds/core/{init,ls,ip,dhclient,wget,cat,gosh}# Generate an archive with all of the core tools with some exceptionsu-root core -cmds/core/{ls,losetup}
Important
u-root
works exactly whengo build
andgo list
work as well.
See also the section below discussing theAMD64 architecture level.
Note
Theu-root
tool is the same as themkuimage tool with some defaultsapplied.
In the near future,uimage
will replaceu-root
.
Tip
To just build Go busybox binaries, try outgobusybox'smakebb
tool.
There are several ways to build multi-module command images using standard Gotooling.
$ mkdir workspace$cd workspace$ git clone https://github.com/u-root/u-root$ git clone https://github.com/u-root/cpu$ go work init ./u-root$ go work use ./cpu$ u-root ./u-root/cmds/core/{init,gosh} ./cpu/cmds/cpud$ cpio -ivt< /tmp/initramfs.linux_amd64.cpio...-rwxr-x--- 0 root root 6365184 Jan 1 1970 bbin/bblrwxrwxrwx 0 root root 2 Jan 1 1970 bbin/cpud -> bblrwxrwxrwx 0 root root 2 Jan 1 1970 bbin/gosh -> bblrwxrwxrwx 0 root root 2 Jan 1 1970 bbin/init -> bb...# Works for offline vendored builds as well.$ go work vendor# Go 1.22 feature.$ u-root ./u-root/cmds/core/{init,gosh} ./cpu/cmds/cpud
When creating a new Go workspace is too much work, thegoanywhere
tool cancreate one on the fly. This worksonly with local file system paths:
$ go install github.com/u-root/gobusybox/src/cmd/goanywhere@latest$ goanywhere ./u-root/cmds/core/{init,gosh} ./cpu/cmds/cpud -- u-root
goanywhere
creates a workspace in a temporary directory with the givenmodules, and then execsu-root
in the workspace passing along the commandnames.
Tip
While workspaces are good for local compilation, they are not meant to bechecked in to version control systems.
For a non-workspace way of building multi-module initramfs images, read morein themkuimage README. (Theu-root
tool ismkuimage
with more defaults applied.)
You may also include additional files in the initramfs using the-files
flag.
If you add binaries with-files
are listed, their ldd dependencies will beincluded as well by default. See below for how to disable.
$ u-root -files /bin/bash$ cpio -ivt< /tmp/initramfs.linux_amd64.cpio...-rwxr-xr-x 0 root root 1277936 Jan 1 1970 bin/bash...drwxr-xr-x 0 root root 0 Jan 1 1970 lib/x86_64-linux-gnu-rwxr-xr-x 0 root root 210792 Jan 1 1970 lib/x86_64-linux-gnu/ld-linux-x86-64.so.2-rwxr-xr-x 0 root root 1926256 Jan 1 1970 lib/x86_64-linux-gnu/libc.so.6lrwxrwxrwx 0 root root 15 Jan 1 1970 lib/x86_64-linux-gnu/libtinfo.so.6 -> libtinfo.so.6.4-rw-r--r-- 0 root root 216368 Jan 1 1970 lib/x86_64-linux-gnu/libtinfo.so.6.4drwxr-xr-x 0 root root 0 Jan 1 1970 lib64lrwxrwxrwx 0 root root 42 Jan 1 1970 lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2...
You can determine placement with colons:
$ u-root -files"/bin/bash:sbin/sh"$ cpio -ivt< /tmp/initramfs.linux_amd64.cpio...-rwxr-xr-x 0 root root 1277936 Jan 1 1970 sbin/sh...
For example on Debian, if you want to add two kernel modules for testing,executing your currently booted kernel:
$ u-root -files"$HOME/hello.ko:etc/hello.ko" -files"$HOME/hello2.ko:etc/hello2.ko"$ qemu-system-x86_64 -kernel /boot/vmlinuz-$(uname -r) -initrd /tmp/initramfs.linux_amd64.cpio
Use-skip-ldd
to not automatically include ldd dependencies for binary files. This can be useful for
- Reproducible Builds: Ensures builds don't depend on the host system's libraries
- Cross-compilation: When host libraries are incompatible with target architecture
- Controlled Dependencies: When you want to manually specify exact library versions
u-root has a very simple (exchangable) init system controlled by the-initcmd
and-uinitcmd
command-line flags.
-initcmd
determines what/init
is symlinked to.-initcmd
may be au-root command name or a symlink target.-uinitcmd
is run by the default u-rootinit after somebasic file system setup. There is no default, users should optionally supplytheir own.-uinitcmd
may be a u-root command name with arguments or asymlink target with arguments.After running a uinit (if there is one),init will start ashell determined by the
-defaultsh
argument.
We expect most users to keep their-initcmd
asinit, but tosupply their own uinit for additional initialization or to immediately loadanother operating system.
All three command-line args accept both a u-root command name or a targetsymlink path.Only-uinitcmd
accepts command-line arguments, however. Forexample,
u-root -uinitcmd="echo Go Gopher" ./cmds/core/{init,echo,gosh}cpio -ivt< /tmp/initramfs.linux_amd64.cpio# ...# lrwxrwxrwx 0 root root 12 Dec 31 1969 bin/uinit -> ../bbin/echo# lrwxrwxrwx 0 root root 9 Dec 31 1969 init -> bbin/initqemu-system-x86_64 -kernel$KERNEL -initrd /tmp/initramfs.linux_amd64.cpio -nographic -append"console=ttyS0"# ...# [ 0.848021] Freeing unused kernel memory: 896K# 2020/05/01 04:04:39 Welcome to u-root!# _# _ _ _ __ ___ ___ | |_# | | | |____| '__/ _ \ / _ \| __|# | |_| |____| | | (_) | (_) | |_# \__,_| |_| \___/ \___/ \__|## Go Gopher# ~/>
Passing command line arguments like above is equivalent to passing the argumentsto uinit via a flags file in/etc/uinit.flags
, seeExtra Files.
Additionally, you can pass arguments to uinit via theuroot.uinitargs
kernelparameters, for example:
u-root -uinitcmd="echo Gopher" ./cmds/core/{init,echo,gosh}cpio -ivt< /tmp/initramfs.linux_amd64.cpio# ...# lrwxrwxrwx 0 root root 12 Dec 31 1969 bin/uinit -> ../bbin/echo# lrwxrwxrwx 0 root root 9 Dec 31 1969 init -> bbin/initqemu-system-x86_64 -kernel$KERNEL -initrd /tmp/initramfs.linux_amd64.cpio -nographic -append"console=ttyS0 uroot.uinitargs=Go"# ...# [ 0.848021] Freeing unused kernel memory: 896K# 2020/05/01 04:04:39 Welcome to u-root!# _# _ _ _ __ ___ ___ | |_# | | | |____| '__/ _ \ / _ \| __|# | |_| |____| | | (_) | (_) | |_# \__,_| |_| \___/ \___/ \__|## Go Gopher# ~/>
Note the order of the passed arguments in the above example.
The command you name must be present in the command set. The following willnotwork:
u-root -uinitcmd="echo Go Gopher" ./cmds/core/{init,gosh}# 21:05:57 could not create symlink from "bin/uinit" to "echo": command or path "echo" not included in u-root build: specify -uinitcmd="" to ignore this error and build without a uinit
You can also refer to non-u-root-commands; they will be added as symlinks. Wedon't presume to know whether your symlink target is correct or not.
This will build, but not work unless you add a /bin/foobar to the initramfs.
u-root -uinitcmd="/bin/foobar Go Gopher" ./cmds/core/{init,gosh}
This will boot the same as the above.
u-root -uinitcmd="/bin/foobar Go Gopher" -files /bin/echo:bin/foobar -files your-hosts-file:/etc/hosts ./cmds/core/{init,gosh}
The effect of the above command:
- Sets up the uinit command to be /bin/foobar, with 2 arguments: Go Gopher
- Adds /bin/echo as bin/foobar
- Adds your-hosts-file as etc/hosts
- builds in the cmds/core/init, and cmds/core/gosh commands.
This will bypass the regular u-root init and just launch a shell:
u-root -initcmd=gosh ./cmds/core/{gosh,ls}cpio -ivt< /tmp/initramfs.linux_amd64.cpio# ...# lrwxrwxrwx 0 root root 9 Dec 31 1969 init -> bbin/goshqemu-system-x86_64 -kernel$KERNEL -initrd /tmp/initramfs.linux_amd64.cpio -nographic -append"console=ttyS0"# ...# [ 0.848021] Freeing unused kernel memory: 896K# failed to put myself in foreground: ioctl: inappropriate ioctl for device# ~/>
(It fails to do that because some initialization is missing when the shell isstarted without a proper init.)
Before building an initramfs for AMD64 withu-root
, verify that the command
go env GOAMD64
printsv1
. AGOAMD64
settingof any higher version may produce such binaries that don't execute on old AMD64processors (including the default CPU model of QEMU).
GOAMD64
can be reset tov1
with one of the following methods:
through the
GOAMD64
environment variable:export GOAMD64=v1
through
go env
(only takes effect if theGOAMD64
environment variableis not set):go env -w GOAMD64=v1
Cross-OS and -architecture compilation comes for free with Go. In fact, every PRto the u-root repo is built against the following architectures: amd64, x86(i.e. 32bit), mipsle, armv7, arm64, and ppc64le.
Further, we run integration tests on linux/amd64, and linux/arm64, using severalCI systems. If you need to add another CI system, processor or OS, please let usknow.
To cross compile for an ARM, on Linux:
GOARCH=arm u-root
If you are on OSX, and wish to build for Linux on AMD64:
GOOS=linux GOARCH=amd64 u-root
A good way to test the initramfs generated by u-root is with qemu:
qemu-system-x86_64 -nographic -kernel path/to/kernel -initrd /tmp/initramfs.linux_amd64.cpio
Note that you do not have to build a special kernel on your own, it issufficient to use an existing one. Usually you can find one in/boot
.
If you don't have a kernel handy, you can also get the one we use for VM testing:
go install github.com/hugelgupf/vmtest/tools/runvmtest@latestrunvmtest -- bash -c"cp\$VMTEST_KERNEL ./kernel"
It may not have all features you require, however.
For framebuffer support, append a VESA mode via thevga
kernel parameter:
qemu-system-x86_64 \ -kernel path/to/kernel \ -initrd /tmp/initramfs.linux_amd64.cpio \ -append"vga=786"
For a list of modes, refer to theLinux kernel documentation.
Some utilities, such asdhclient
, require entropy to be present. Withoutsufficient entropy, they may take a while to succeed, possibly half a minute.
If your platform has a hardware random number generator, enable it withCONFIG_ARCH_RANDOM
and trust it withCONFIG_RANDOM_TRUST_CPU
.Otherwise, adduroot.nohwrng
to your kernel command line so u-root uses anon-blocking software random number generator implementation.
For a speedy virtualized random number generator, the kernel should have thefollowing:
CONFIG_VIRTIO_PCI=yCONFIG_HW_RANDOM_VIRTIO=yCONFIG_CRYPTO_DEV_VIRTIO=y
Then you can run your kernel in QEMU with avirtio-rng-pci
device:
qemu-system-x86_64 \ -device virtio-rng-pci \ -kernel vmlinuz \ -initrd /tmp/initramfs.linux_amd64.cpio
In addition, you can pass your host's RNG:
qemu-system-x86_64 \ -object rng-random,filename=/dev/urandom,id=rng0 \ -device virtio-rng-pci,rng=rng0 \ -kernel vmlinuz \ -initrd /tmp/initramfs.linux_amd64.cpio
SystemBoot is a set of bootloaders written in Go. It is meant to be adistribution for LinuxBoot to create a system firmware + bootloader. All ofthese usekexec
to boot. The commands are incmds/boot.Parsers are available forGRUB,syslinux,and other config files to make the transition to LinuxBoot easier.
pxeboot
: a network boot client that uses DHCP and HTTP or TFTP to get aboot configuration which can be parsed as PXELinux or iPXE configurationfiles to get a boot program.boot
: finds all bootable kernels on local disk, shows a menu, and bootsthem. Supports (basic) GRUB, (basic) syslinux, (non-EFI) BootLoaderSpec, andESXi configurations.
More detailed information about the build process for a full LinuxBoot firmwareimage using u-root/systemboot and coreboot can be found in theLinuxBoot book chapter aboutLinuxBoot using coreboot, u-root and systemboot.
This project started as a loose collection of programs in u-root by variousLinuxBoot contributors, as well as a personal experiment byAndrea Barberio that has since been mergedin. It is now an effort of a broader community and graduated to a real projectfor system firmwares.
You can compress the initramfs. However, for xz compression, the kernel has somerestrictions on the compression options and it is suggested to align the file to512 byte boundaries:
xz --check=crc32 -9 --lzma2=dict=1MiB \ --stdout /tmp/initramfs.linux_amd64.cpio \| dd conv=sync bs=512 \ of=/tmp/initramfs.linux_amd64.cpio.xz
Using thetcz
command included in u-root, you can install tinycore linuxpackages for things you want.
You can use QEMU NAT to allow you to fetch packages. Let's suppose, for example,you want bash. Once u-root is running, you can do this:
% tcz bash
The tcz command computes and fetches all dependencies. If you can't get totinycorelinux.net, or you want package fetching to be faster, you can run yourown server for tinycore packages.
You can do this to get a local server using the u-root srvfiles command:
% srvfiles -p 80 -d path-to-local-tinycore-packages
Of course you have to fetch all those packages first somehow :-)
You can build the cpio image created by u-root into a Linux kernel via theCONFIG_INITRAMFS_SOURCE
config variable or coreboot config variable, andfurther embed the kernel image into firmware as a coreboot payload.
In the kernel and coreboot case, you may need to configure ethernet. We have adhclient
command that works for both ipv4 and ipv6. Since v6 does not yet workthat well for most people, a typical invocation looks like this:
% dhclient -ipv4 -ipv6=false
Or, on newer linux kernels (> 4.x) boot with ip=dhcp in the command line,assuming your kernel is configured to work that way.
u-root can create an initramfs in two different modes, specified by-build
:
gbb
mode: One busybox-like binary comprising all the Go tools you ask toinclude.Seethe gobusybox README for how it works.In this mode, u-root copies and rewrites the source of the tools you askedto include to be able to compile everything into one busybox-like binary.binary
mode: each specified binary is compiled separately and all binariesare added to the initramfs.
go get -ugo mod tidygo mod vendor
The u-root command supports building with workspace vendoring and modulevendoring. In both of those cases, if all dependencies are found in the vendoreddirectories, the build happens completely offline.
Read more in themkuimage README.
u-root also still supportsGO111MODULE=off
builds.
If you want to see u-root on real hardware, thisboard is a good start.
U-root works with Plan 9. The best distro to use for it is 9front, as the9front cpiofs works with newc-format cpio (the format of Linux initramfs, whichu-root generates).
Here is a script for Plan 9. Once this script runs, all the u-root commandsappear in /bin. You will need to have go1.22 installed on Plan 9; orcreate the u-root initramfs on some other system and copy it to Plan 9.
#!/bin/rcu-root'-defaultsh=''-initcmd=''-shellbang=true'fs/cpiofs /tmp/initram*cpiobind -a /n/tapefs /bind -a /bbin /bin
For information about contributing, including how we sign off commits, pleaseseeCONTRIBUTING.md.
Improving existing commands (e.g., additional currently unsupported flags) isvery welcome. In this case it is not even required to build an initramfs, justenter thecmds/
directory and start coding. A list of commands that are on theroadmap can be foundhere.
The sources ofu-root.org are inside thedocs/
directory andare deployed to the gh-pages branch. The CNAME file is currently not part of the CIwhich deploys to the branch which shall be evaluated if this makes futures deployments easier.
About
A fully Go userland with Linux bootloaders! u-root can create a one-binary root file system (initramfs) containing a busybox-like set of tools written in Go.
Topics
Resources
License
Contributing
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.