\documentclass[aspectratio=169,obeyspaces,spaces,hyphens,dvipsnames]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}% http://ctan.org/pkg/lm
\usepackage{minted}
\usepackage{hyperref}
\usepackage{xcolor}
\usepackage{pgfplots}
\usepackage{tikz}
\usepackage[normalem]{ulem}

\mode<presentation>
\usetheme{Bootlin}

\def\signed #1{{\leavevmode\unskip\nobreak\hfil\penalty50\hskip2em
  \hbox{}\nobreak\hfil(#1)
  \parfillskip=0pt \finalhyphendemerits=0 \endgraf}}

\newsavebox\mybox
\newenvironment{aquote}[1]
  {\savebox\mybox{#1}\begin{quotation}}
  {\signed{\usebox\mybox}\end{quotation}}

\title{Embedded Linux from scratch in 45 minutes (on RISC-V)}
\authors{Michael Opdenacker}
\email{michael.opdenacker@bootlin.com}
\slidesurl{https://bootlin.com/pub/conferences/2021/fosdem/}
\institute{Bootlin}
\conference{Fosdem 2021}

\begin{document}

\section{Embedded Linux from scratch in 45 minutes}

\begin{frame}{Welcome to the special edition of FOSDEM for Covid}
    \begin{center}
    \includegraphics[height=0.7\textheight]{graphics/FOSDEM_logo.pdf}\\
    \small
    <conspiracy>Note that this is the FOSDEM logo since 2014. Weird, isn't it?</conspiracy>\\
    \tiny Image credits: \url{https://commons.wikimedia.org/wiki/File:FOSDEM_logo.svg}
    \end{center}
\end{frame}

\begin{frame}{Michael Opdenacker}
\begin{columns}
  \column{0.7\textwidth}
  \begin{itemize}
  \item Founder and Embedded Linux engineer at Bootlin:
    \begin{itemize}
    \item Embedded Linux {\bf expertise}
    \item {\bf Development}, consulting and training
    \item Focusing {\bf only on Free and Open Source Software}
    \end{itemize}
  \item Free Software contributor:
    \begin{itemize}
      \item Current maintainer of the Elixir Cross Referencer, making it
            easier to study the sources of big C projects like the Linux kernel.
            See \url{https://elixir.bootlin.com}
      \item Co-author of Bootlin's freely available embedded Linux and
	    kernel training materials (\url{https://bootlin.com/docs/})
      \item Former maintainer of \href{https://www.gnu.org/software/gtypist/}{GNU Typist}
    \end{itemize}
  \end{itemize}
  \column{0.3\textwidth}
    \begin{center}
    \vspace{1cm}
    \includegraphics[width=0.5\textwidth]{graphics/logo-cc.pdf}\\
    \vspace{0.5cm}
    \includegraphics[width=\textwidth]{graphics/elixir.pdf}
    \end{center}
\end{columns}
\end{frame}

\subsection{Introduction}

\begin{frame}{What I like in embedded Linux}
\begin{itemize}
  \item Linux is perfect for operating devices with a fixed set of
        features.\\
         Unlike on the desktop, Linux is almost in every existing embedded system.
  \item Embedded Linux makes Linux easy to learn: just a few programs and
        libraries are sufficient. {\bf You can understand the usefulness of each
        file in your filesystem}.
  \item The Linux kernel is standalone: no complex dependencies against
	external software. The code is in C!
  \item Linux works with just a few MB of RAM and storage
  \item There's a new version of Linux every 2-3 months.
  \item Relatively small development community. You end up meeting lots
        of familiar faces at technical conferences (like the Embedded
	Linux Conference).
  \item Lots of opportunities (and funding available) for becoming a
        contributor (Linux kernel, bootloader, build systems...).
\end{itemize}
\end{frame}

\begin{frame}{Reviving an old presentation}
\begin{columns}
  \column{0.5\textwidth}
    \begin{itemize}
      \item First shown in 2005 at the Libre Software Meeting in Dijon, France.
      \item Showing a 2.6 Linux kernel booting on a QEMU emulated ARM board.
      \item One of our most downloaded presentations at that time.
    \end{itemize}
  \column{0.5\textwidth}
    \vspace{1cm}
    \includegraphics[width=\textwidth]{graphics/old-elfs-presentation.png}
\end{columns}
\end{frame}

\begin{frame}{Things that changed since 2005}
\begin{columns}
  \column{0.6\textwidth}
  In the Linux kernel:
  \begin{itemize}
     \item Linux 2.6.x \textrightarrow 5.x
     \item {\em Bitkeeper} \textrightarrow {\em git}
     \item Linux is now everywhere, no need to convince customers to use
	   it. It's even easier and easier to convince then to fund
	   contributions to the official version.
     \item {\em devtmpfs}: automatically creates device files
     \item ARM and other architectures: devices described by the {\em Device Tree} instead of C code
  \end{itemize}
  And many more!
  \column{0.4\textwidth}
  \vspace{1cm}\\
  In the embedded environment:
  \begin{itemize}
     \item The Maker movement
     \item Cheap development boards\\
           500+ EUR \textrightarrow 50-100 EUR
     \item The rise of Open Hardware\\
           (Arduino, Beaglebone Black...)
     \item {\em RISC-V}: a new open-source hardware instruction set architecture
  \end{itemize}
\end{columns}
\end{frame}

\begin{frame}{RISC-V: a new open-source ISA}
  \includegraphics[height=0.1\textheight]{graphics/RISC-V-logo.pdf}\\
  \begin{itemize}
     \item ISA: {\em Instruction Set Architecture}
     \item Created by the University of California Berkeley, in a world
           dominated by proprietary ISAs with heavy royalties (ARM, x86)
     \item Exists in 32, 64 and 128 bit variants, from microcontrollers
	   to powerful server hardware.
     \item Anyone can use and extend it to create their own SoCs
	   and CPUs.
     \item This reduces costs and promotes reuse and collaboration
     \item Implementations can be proprietary. Many hardware vendors
	   are using RISC-V CPUs in their hardware (examples:
	   Microchip, Western Digital, Nvidia)
     \item Free implementations are being created
  \end{itemize}
  See \url{https://en.wikipedia.org/wiki/RISC-V}
\end{frame}

\begin{frame}{How to use RISC-V with Linux?}
  \small
  \begin{columns}
  \column{0.85\textwidth}
  Hardware is now getting available
  \begin{itemize}
  \item Last minute news: BeagleV. The first affordable RISC-V board for
        the community, should be available at 150 USD in April:
        \url{http://beagleboard.org/beaglev}.
  \item Icicle kit: with Microchip's PolarFire SoC and
	an FPGA with 254 K gates. Sold at 499 USD at CrowdSupply:
        \url{https://frama.link/dK1oanrd}
  \item Boards with the Kendryte K210 SoC. Sipeed MAix BiT only costs 13
        USD at Seed Studio: \url{https://frama.link/QhBdPjsm}.
        Supported by Linux 5.8 but very limited, as its MMU is not supported by Linux.
  \item You can also synthetize RISC-V cores on FPGAs
  \item Before more hardware is available in 2021, you
        can get started with the QEMU emulator, which simulates a
        virtual board with {\em virtio} hardware
  \end{itemize}
  Already try it with JSLinux: \url{https://bellard.org/jslinux/}
  \column{0.15\textwidth}
    \tiny
    \vspace{1cm}
    \includegraphics[width=\textwidth]{graphics/beaglev.jpg}
    BeagleV
    \includegraphics[width=\textwidth]{graphics/icicle-kit.jpg}
    Microchip PolarFire SoC Icicle kit
    \includegraphics[width=\textwidth]{graphics/sipeed-k210.png}
    Seed Studio Sipeed MAix BiT
  \end{columns}
\end{frame}

\begin{frame}{Goals}
Show you the most important aspects of embedded Linux development work
\begin{itemize}
  \item Building a cross-compiling toolchain
  \item Creating a disk image
  \item Booting a using a bootloader
  \item Loading and starting the Linux kernel
  \item Building a root filesystem populated with basic utilities
  \item Configuring the way the system starts
  \item Setting up networking and controlling the system via a web interface
\end{itemize}
\end{frame}

\begin{frame}{Things to build today}
\begin{itemize}
  \item Cross-compiling toolchain: {\em Buildroot 2020.11.1}
  \item Firmware / first stage bootloader: {\em OpenSBI}
  \item Bootloader: {\em U-Boot 2021.01}
  \item Kernel: {\em Linux 5.11-rc3}
  \item Root filesystem and application: {\em BusyBox 1.33.0}
\end{itemize}
That's possible to compile and assemble in less than 45 minutes!
\end{frame}

\subsection{Cross-compiling toolchain}

\begin{frame}
  \frametitle{What's a cross-compiling toolchain?}
  \begin{center}
    \includegraphics[width=0.8\textwidth]{graphics/cross-toolchain.pdf}
  \end{center}
\end{frame}

\begin{frame}
  \frametitle{Why generate your own cross-compiling toolchain?}
  Compared to ready-made toolchains:
  \begin{itemize}
    \item You can choose your compiler version
    \item You can choose your C library (glibc, uClibc, musl)
    \item You can tweak other features
    \item You gain reproducibility: if a bug is found, just apply a fix.\\
          Don't need to get another toolchain (different bugs)
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{Choosing the C library}
  \begin{columns}
    \column{0.7\textwidth}
    \begin{itemize}
    \item The C library is an essential component of a Linux system
      \begin{itemize}
      \item Interface between the applications and the kernel
      \item Provides the well-known standard C API to ease application
        development
      \end{itemize}
    \item Several C libraries are available:
      \begin{itemize}
      \item {\em glibc}: full featured, but rather big (2 MB on ARM)
      \item {\em uClibc}: better adapted to embedded use, smaller and
	    supporting RISC-V 64.
      \item {\em musl}: great for embedded use too, more recent
      \end{itemize}
    \item The choice of the C library must be made at
      cross-compiling toolchain generation time, as the GCC compiler is
      compiled against a specific C library.
    \end{itemize}
    \column{0.3\textwidth}
    \includegraphics[width=\textwidth]{graphics/Linux_kernel_System_Call_Interface_and_uClibc.pdf}\\
    {\tiny Source: Wikipedia (\url{http://bit.ly/2zrGve2})}
  \end{columns}
\end{frame}

\begin{frame}{Generating a RISC-V musl toolchain with Buildroot}
  \small
  \begin{columns}
    \column{0.75\textwidth}
    \begin{itemize}
      \item Download Buildroot 2020.11.1 from \url{https://buildroot.org}
      \item Extract the sources (\code{tar xf})
      \item Run \code{make menuconfig}
      \item In \code{Target options} \textrightarrow \code{Target
	    Architecture}, choose \code{RISCV}
      \item In \code{Toolchain} \textrightarrow \code{C library},
	    choose \code{musl}.
      \item Save your configuration and run:\\
	    \code{make sdk}
      \item At the end, you have an toolchain archive in
            \code{output/images/riscv64-buildroot-linux-musl_sdk-buildroot.tar.gz}
      \item Extract the archive in a suitable directory, and
	    in the extracted directory, run: \code{./relocate-sdk.sh}
    \end{itemize}
    \column{0.35\textwidth}
    \includegraphics[width=\textwidth]{asciinema/383836.png}\\
    \tiny \url{https://asciinema.org/a/383836}
  \end{columns}
\end{frame}

\begin{frame}[fragile]{Testing the toolchain}
\begin{itemize}
\item Create a new \code{riscv64-env.sh} file you can source to set\\
    environment variables for your project:
\begin{block}{}
\scriptsize
\begin{verbatim}
export PATH=$HOME/toolchain/riscv64-buildroot-linux-musl_sdk-buildroot/bin:$PATH
\end{verbatim}
\end{block}
\item Run \code{source riscv64-env.sh}, take a \code{hello.c} file and test your new compiler:
\begin{block}{}
\scriptsize
\begin{verbatim}
$ riscv64-linux-gcc -static -o hello hello.c
$ file hello
hello: ELF 64-bit LSB executable, UCB RISC-V, version 1 (SYSV), statically linked, not stripped
\end{verbatim}
\end{block}
     We are compiling statically so far to avoid having to deal with shared
     libraries.
\item Test your executable with QEMU in user mode:
\begin{block}{}
\begin{verbatim}
$ qemu-riscv64 hello
Hello world!
\end{verbatim}
\end{block}
\end{itemize}
\end{frame}

\subsection{Hardware emulator}

\begin{frame}[fragile]{Finding which machines are emulated by QEMU}
Tests made with QEMU 4.2.1 (Ubuntu 20.04)
\begin{block}{}
\small
\begin{verbatim}
sudo apt install qemu-system-misc
$ qemu-system-riscv64 -M ?
Supported machines are:
none                 empty machine
sifive_e             RISC-V Board compatible with SiFive E SDK
sifive_u             RISC-V Board compatible with SiFive U SDK
spike                RISC-V Spike Board (default)
spike_v1.10          RISC-V Spike Board (Privileged ISA v1.10)
spike_v1.9.1         RISC-V Spike Board (Privileged ISA v1.9.1)
virt                 RISC-V VirtIO board
\end{verbatim}
\end{block}
We are going to use the \code{virt} one, emulating VirtIO peripherals
(more efficient than emulating real hardware).
\end{frame}

\subsection{Booting process and privileges}

\begin{frame}
  \frametitle{RISC-V privilege modes}
  \begin{columns}
  \column{0.65\textwidth}
  RISC-V has three privilege modes:
  \begin{itemize}
    \item {\bf U}ser (U-Mode): applications
    \item {\bf S}upervisor (S-Mode): OS kernel
    \item {\bf M}achine (M-Mode): bootloader and firmware
  \end{itemize}
  Here are typical combinations:
  \begin{itemize}
    \item {\bf M}: simple embedded systems
    \item {\bf M}, {\bf U}: embedded systems with memory protection
    \item {\bf M}, {\bf S}, {\bf U}: Unix-style operating systems with virtual memory
  \end{itemize}
  \column{0.35\textwidth}
    \includegraphics[width=\textwidth]{graphics/privilege-modes.pdf}
  \end{columns}
\end{frame}

\subsection{U-Boot bootloader}

\begin{frame}[fragile]
  \frametitle{Environment for U-Boot cross-compiling}
  \begin{itemize}
  \item Download U-Boot 2021.01 sources
  \item Let's add an environment variable to our \code{riscv64-env.sh}
        file for cross-compiling:
  \begin{block}{}
  \begin{verbatim}
export CROSS_COMPILE=riscv64-linux-
\end{verbatim}
  \end{block}{}
  \item \code{CROSS_COMPILE} is the cross-compiler prefix, as our
      cross-compiler is {\bf \tt{riscv64-linux-}}\code{gcc}.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Cross-compiling U-Boot}
  \begin{itemize}
     \item Find U-Boot ready-made configurations for RISC-V:
  \begin{block}{}
  \begin{verbatim}
ls configs | grep riscv
\end{verbatim}
  \end{block}{}
  \item We will choose the configuration for QEMU and U-Boot running in S Mode:
  \begin{block}{}
  \begin{verbatim}
make qemu-riscv64_smode_defconfig
\end{verbatim}
  \end{block}{}
  \item Now let's compile U-Boot (\code{-j8}: 8 jobs compile jobs in parallel)
  \begin{block}{}
  \begin{verbatim}
make -j8
\end{verbatim}
  \end{block}{}
  \end{itemize}
\end{frame}

\subsection{Firmware}

\begin{frame}[fragile]
  \frametitle{OpenSBI: Open Supervisor Binary Interface}
  \begin{itemize}
  \item Required to start an OS (S mode) from the Supervisor/Firmware (M mode)
  \begin{block}{}
  \small
  \begin{verbatim}
git clone https://github.com/riscv/opensbi.git
cd opensbi
git checkout v0.8
make PLATFORM=generic FW_PAYLOAD_PATH=../u-boot-2021.01/u-boot.bin
\end{verbatim}
  \end{block}
  \item Run the above command every time you update U-Boot
  \item This generates the
        \code{build/platform/generic/firmware/fw_payload.elf} file which
        is a binary that QEMU can boot.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Starting U-Boot in QEMU}
  \begin{block}{}
  \begin{verbatim}
qemu-system-riscv64 -m 2G \
    -nographic \
    -machine virt \
    -smp 8 \
    -bios opensbi/build/platform/generic/firmware/fw_payload.elf \
\end{verbatim}
  \end{block}{}
  \begin{itemize}
    \item \code{-m}: amount of RAM in the emulated machine
    \item \code{-smp}: number of CPUs in the emulated machine
  \end{itemize}
  Exit QEMU with \code{[Ctrl][a]} followed by \code{[x]}
\end{frame}

\subsection{Linux kernel}

\begin{frame}[fragile]
  \frametitle{Environment for kernel cross-compiling}
  \begin{itemize}
  \item Download Linux 5.11-rc3 sources from \url{https://kernel.org}
  \item Let's add two environment variables for kernel cross-compiling to our
  \code{riscv64-env.sh} file:
  \begin{block}{}
  \begin{verbatim}
export CROSS_COMPILE=riscv64-linux-
export ARCH=riscv
\end{verbatim}
  \end{block}{}
  \item \code{CROSS_COMPILE} is the cross-compiler prefix, as our
      cross-compiler is {\bf \tt{riscv64-linux-}}\code{gcc}.
  \item \code{ARCH} is the name of the subdirectory in \kdir{arch} corresponding
      to the target architecture.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Kernel configuration}
  \begin{itemize}
  \item Lets take the default Linux kernel configuration for RISCV:
    \begin{block}{}
    \small
    \begin{verbatim}
$ make help | grep defconfig
  defconfig       - New config with default from ARCH supplied defconfig
  savedefconfig   - Save current config as ./defconfig (minimal config)
  alldefconfig    - New config with all symbols set to default
  olddefconfig    - Same as oldconfig but sets new symbols to their
  nommu_k210_defconfig        - Build for nommu_k210
  nommu_virt_defconfig        - Build for nommu_virt
  rv32_defconfig              - Build for rv32
$ make defconfig
\end{verbatim}
    \end{block}{}
  \item We can now further customize the configuration:
    \begin{block}{}
    \begin{verbatim}
make menuconfig
\end{verbatim}
    \end{block}{}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Compiling the kernel}
    \begin{block}{}
    \begin{verbatim}
make
\end{verbatim}
    \end{block}{}
    To compile faster, run multiple {\bf j}obs in parallel:
    \begin{block}{}
    \begin{verbatim}
make -j 8
\end{verbatim}
    \end{block}{}
    To {\bf re}compile faster (7x according to some
    benchmarks), run multiple {\bf j}obs in parallel:
    \begin{block}{}
    \begin{verbatim}
make -j 8 CC="ccache riscv64-linux-gcc"
\end{verbatim}
    \end{block}{}
    At the end, you have these files:\\
    \code{vmlinux}: raw kernel in ELF format (not bootable, for debugging)\\
    \code{arch/riscv/boot/Image}: uncompressed bootable kernel
    \code{arch/riscv/boot/Image.gz}: compressed kernel
\end{frame}

\subsection{Booting the kernel}

\begin{frame}[fragile]
  \frametitle{Booting the Linux kernel directly}
  \small
  We could boot the Linux kernel directly as follows
  \begin{block}{}
  \begin{verbatim}
cd opensbi
make PLATFORM=generic FW_PAYLOAD_PATH=../linux-5.11-rc3/arch/riscv/boot/Image
cd ..

qemu-system-riscv64 -m 2G \
    -nographic \
    -machine virt \
    -smp 8 \
    -bios opensbi/build/platform/generic/firmware/fw_payload.elf \
    -append "console=ttyS0" \
\end{verbatim}
  \end{block}{}
  However, what we want to demonstrate is the normal booting process:\\
  OpenSBI \textrightarrow U-Boot \textrightarrow Linux \textrightarrow Userspace
\end{frame}

\begin{frame}[fragile]
  \frametitle{Booting the Linux kernel from U-Boot}
  \begin{itemize}
  \item We want to show how to set the U-Boot environment to load the
        Linux kernel and to specify the Linux kernel command line
  \item For this purpose, we will need some storage space to store the
        U-Boot environment, load the kernel binary, and also to
        contain the filesystem that Linux will boot on.
  \item Therefore, let's create a disk image to give some storage space
        for QEMU
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Disk image creation (1)}
  \begin{itemize}
  \item Let's create a 128 MB disk image:
    \begin{block}{}
    \begin{verbatim}
dd if=/dev/zero of=disk.img bs=1M count=128
\end{verbatim}
    \end{block}{}
  \item Let's create two partitions in this image
    \begin{block}{}
    \begin{verbatim}
cfdisk disk.img
\end{verbatim}
    \end{block}{}
    \begin{itemize}
      \item A first 64 MB primary partition (type \code{W95 FAT32 (LBA)}), marked as bootable
      \item A second partition with remaining space (default type: \code{Linux}) 
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Disk image creation (2)}
  \begin{itemize}
  \item Let's access the partitions in this disk image:
    \begin{block}{}
    \begin{verbatim}
sudo losetup -f --show --partscan disk.img
/dev/loop2

ls -la /dev/loop2*
brw-rw---- 1 root disk   7,  2 Jan 14 10:50 /dev/loop2
brw-rw---- 1 root disk 259, 11 Jan 14 10:50 /dev/loop2p1
brw-rw---- 1 root disk 259, 12 Jan 14 10:50 /dev/loop2p2
\end{verbatim}
    \end{block}{}
  \item We can now format the partitions:
    \begin{block}{}
    \begin{verbatim}
sudo mkfs.vfat -F 32 -n boot /dev/loop2p1
sudo mkfs.ext4 -L rootfs /dev/loop2p2
\end{verbatim}
    \end{block}{}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Copying the Linux image to the FAT partition}
  \begin{itemize}
  \item Let's create a mount point for the FAT partition:
    \begin{block}{}
    \begin{verbatim}
mkdir /mnt/boot
\end{verbatim}
    \end{block}{}
  \item Let's mount it:
    \begin{block}{}
    \begin{verbatim}
sudo mount /dev/loop2p1 /mnt/boot
\end{verbatim}
    \end{block}{}
  \item Let's copy the kernel image to it:
    \begin{block}{}
    \begin{verbatim}
sudo cp linux-5.11-rc3/arch/riscv/boot/Image /mnt/boot
\end{verbatim}
    \end{block}{}
  \item And then unmount the filesystem to commit changes:
    \begin{block}{}
    \begin{verbatim}
sudo umount /mnt/boot
\end{verbatim}
    \end{block}{}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Recompiling U-Boot for environment support}
  We want U-Boot be able to use an environment\\
  in a FAT partition on a virtio disk.
  \begin{itemize}
  \item So, let's reconfigure U-Boot with the following settings
    \begin{block}{}
    \begin{verbatim}
make menuconfig
\end{verbatim}
    \end{block}{}
    \begin{itemize}
      \item \code{CONFIG_ENV_IS_IN_FAT=y}
      \item \code{CONFIG_ENV_FAT_INTERFACE="virtio"}
      \item \code{CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"}
    \end{itemize}
  \item Then recompile U-Boot
    \begin{block}{}
    \begin{verbatim}
make -j8
\end{verbatim}
    \end{block}{}
  \item Then update the firmware loader:
    \begin{block}{}
    \begin{verbatim}
cd ../opensbi
make PLATFORM=generic FW_PAYLOAD_PATH=../u-boot-2021.01/u-boot.bin
\end{verbatim}
    \end{block}{}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Run U-Boot with an environment}
  \begin{itemize}
    \item Add a disk to the emulated machine:
    \begin{block}{}
    \begin{verbatim}
qemu-system-riscv64 -m 2G -nographic -machine virt -smp 8 \
    -bios opensbi/build/platform/generic/firmware/fw_payload.elf \
    -drive file=disk.img,format=raw,id=hd0 \
    -device virtio-blk-device,drive=hd0 \
\end{verbatim}
    \end{block}
    \item In U-Boot, you should now be able to save an environment:
    \begin{block}{}
\begin{verbatim}
setenv foo bar
saveenv
\end{verbatim}
    \end{block}
  \end{itemize}
\end{frame}

\subsection{Booting Linux from U-Boot}

\begin{frame}[fragile]
  \frametitle{Requirements for booting Linux}
  To boot the Linux kernel, U-Boot needs to load
  \begin{itemize}
    \item A Linux kernel image. In our case, let's load it from our virtio disk\\
	  to RAM (find a suitable RAM address by using
          the \code{bdinfo} command in U-Boot):
    \begin{block}{}
    \begin{verbatim}
fatload virtio 0:1 84000000 Image
\end{verbatim}
    \end{block}
    \item Possibly the image of an {\em Initramfs}, a filesystem in
          RAM that Linux can use.
    \item A {\em Device Tree Binary (DTB)}, letting the kernel know
          which SoC and devices we have. This allows the same kernel
	  to support many different SoCs and boards.
         \begin{itemize}
            \item {\em DTB} files are compiled from {\em DTS} files in
                  \kdir{arch/riscv/boot/dts}
	    \item However, there is no such {\em DTS} file for the
		  RISC-V QEMU virt board.
	    \item The {\em DTB} for our board is actually passed by QEMU
		  to OpenSBI and then to U-Boot. See
                  \url{https://tinyurl.com/y4ae5ptd}
	    \item In U-Boot, at least in our case, the {\em DTB} is available
		  in RAM at address \code{${fdtcontroladdr}}
         \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Linux kernel command line}
  \begin{itemize}
    \item We need to set the Linux arguments ({\em kernel command line})
    \begin{block}{}
    \small
    \begin{verbatim}
setenv bootargs 'root=/dev/vda2 rootwait console=ttyS0 earlycon=sbi rw'
\end{verbatim}
    \end{block}
    \begin{itemize}
       \item \code{root=/dev/vda2}\\
	     Device for Linux to mount as root filesystem
       \item \code{rootwait}\\
	     Wait for the root device to be ready before
	     trying to mount it
       \item \code{console=ttyS0}\\
	     Device (here first serial line) to send
	     Linux booting messages to
       \item \code{earlycon=sbi}\\
	     Allows to have more messages before
	     the console driver is initialized ({\em Early Console}).
       \item \code{rw}\\
	     Allows to mount the root filesystem in read-write mode.
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Booting Linux}
  \begin{itemize}
    \item Here's the command to boot the Linux \code{Image} file:
    \begin{block}{}
    \begin{verbatim}
booti <Linux address> <Initramfs address> <DTB address>
\end{verbatim}
    \end{block}
    \item In our case:
    \begin{block}{}
    \begin{verbatim}
booti 0x84000000 - ${fdtcontroladdr}
\end{verbatim}
    \end{block}
    \item So, let's define the default series of commands that U-Boot
	  will automatically run after a configurable delay
          (\code{bootdelay} environment variable):
    \begin{block}{}
    \scriptsize
    \begin{verbatim}
setenv bootcmd 'fatload virtio 0:1 84000000 Image; booti 0x84000000 - ${fdtcontroladdr}'
\end{verbatim}
    \end{block}
    \item Finally, we must save these new settings:
    \begin{block}{}
    \begin{verbatim}
saveenv
\end{verbatim}
    \end{block}
    \item ... and boot our system (\code{boot} runs \code{bootcmd}):
    \begin{block}{}
    \begin{verbatim}
boot
\end{verbatim}
    \end{block}
  \end{itemize}
\end{frame}

\subsection{Building the root filesystem}

\begin{frame}[fragile]
  \frametitle{BusyBox - About 10 years ago}
  Most commands in one binary!
  \vspace{0.5cm}
  \begin{spacing}{0}
    \tiny
    \code{[, [[, acpid, addgroup, adduser, adjtimex, ar, arp, arping, ash, awk, basename, beep, blkid, brctl, bunzip2, bzcat, bzip2, cal, cat, catv, chat, chattr, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt, cksum, clear, cmp, comm, cp, cpio, crond, crontab, cryptpw, cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devmem, df, dhcprelay, diff, dirname, dmesg, dnsd, dnsdomainname, dos2unix, dpkg, du, dumpkmap, dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid, expand, expr, fakeidentd, false, fbset, fbsplash, fdflush, fdformat, fdisk, fgrep, find, findfs, flash_lock, flash_unlock, fold, free, freeramdisk, fsck, fsck.minix, fsync, ftpd, ftpget, ftpput, fuser, getopt, getty, grep, gunzip, gzip, hd, hdparm, head, hexdump, hostid, hostname, httpd, hush, hwclock, id, ifconfig, ifdown, ifenslave, ifplugd, ifup, inetd, init, inotifyd, insmod, install, ionice, ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, iproute, iprule, iptunnel, kbd_mode, kill, killall, killall5, klogd, last, length, less, linux32, linux64, linuxrc, ln, loadfont, loadkmap, logger, login, logname, logread, losetup, lpd, lpq, lpr, ls, lsattr, lsmod, lzmacat, lzop, lzopcat, makemime, man, md5sum, mdev, mesg, microcom, mkdir, mkdosfs, mkfifo, mkfs.minix, mkfs.vfat, mknod, mkpasswd, mkswap, mktemp, modprobe, more, mount, mountpoint, mt, mv, nameif, nc, netstat, nice, nmeter, nohup, nslookup, od, openvt, passwd, patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, popmaildir, printenv, printf, ps, pscan, pwd, raidautorun, rdate, rdev, readlink, readprofile, realpath, reformime, renice, reset, resize, rm, rmdir, rmmod, route, rpm, rpm2cpio, rtcwake, run-parts, runlevel, runsv, runsvdir, rx, script, scriptreplay, sed, sendmail, seq, setarch, setconsole, setfont, setkeycodes, setlogcons, setsid, setuidgid, sh, sha1sum, sha256sum, sha512sum, showkey, slattach, sleep, softlimit, sort, split, start-stop-daemon, stat, strings, stty, su, sulogin, sum, sv, svlogd, swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar, taskset, tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time, timeout, top, touch, tr, traceroute, true, tty, ttysize, udhcpc, udhcpd, udpsvd, umount, uname, uncompress, unexpand, uniq, unix2dos, unlzma, unlzop, unzip, uptime, usleep, uudecode, uuencode, vconfig, vi, vlock, volname, watch, watchdog, wc, wget, which, who, whoami, xargs, yes, zcat, zcip}
  \end{spacing}
  \vfill
  Source: run \code{/bin/busybox}
\end{frame}

\begin{frame}[fragile]
  \frametitle{BusyBox - In 2019}
  \vspace{1.3cm}
  \begin{spacing}{0}
    \tiny
    \code{[, [[, acpid, add-shell, addgroup, adduser, adjtimex, ar, arch, arp, arping, awk, base64, basename, bbconfig, bc, beep, blkdiscard, blkid, blockdev, bootchartd, brctl, bunzip2, busybox, bzcat, bzip2, cal, cat, chat, chattr, chcon, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt, cksum, clear, cmp, comm, conspy, cp, cpio, crond, crontab, cryptpw, cttyhack, cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devmem, df, diff, dirname, dmesg, dnsd, dnsdomainname, dos2unix, dpkg, dpkg-deb, du, dumpkmap, dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid, ether-wake, expand, expr, factor, fakeidentd, fallocate, false, fatattr, fbset, fbsplash, fdflush, fdformat, fdisk, fgconsole, fgrep, find, findfs, flash_eraseall, flash_lock, flash_unlock, flashcp, flock, fold, free, freeramdisk, fsck, fsck.minix, fsfreeze, fstrim, fsync, ftpd, ftpget, ftpput, fuser, getenforce, getopt, getsebool, getty, grep, groups, gunzip, gzip, halt, hd, hdparm, head, hexdump, hexedit, hostid, hostname, httpd, hush, hwclock, id, ifconfig, ifdown, ifenslave, ifplugd, ifup, inetd, init, insmod, install, ionice, iostat, ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, ipneigh, iproute, iprule, iptunnel, kbd_mode, kill, killall, killall5, klogd, last, less, link, linux32, linux64, linuxrc, ln, load_policy, loadfont, loadkmap, logger, login, logname, logread, losetup, lpd, lpq, lpr, ls, lsattr, lsmod, lsof, lspci, lsscsi, lsusb, lzcat, lzma, lzop, lzopcat, makedevs, makemime, man, matchpathcon, md5sum, mdev, mesg, microcom, minips, mkdir, mkdosfs, mke2fs, mkfifo, mkfs.ext2, mkfs.minix, mkfs.reiser, mkfs.vfat, mknod, mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount, mountpoint, mpstat, mt, mv, nameif, nanddump, nandwrite, nbd-client, nc, netcat, netstat, nice, nl, nmeter, nohup, nologin, nproc, nsenter, nslookup, ntpd, nuke, od, openvt, partprobe, passwd, paste, patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, pmap, popmaildir, poweroff, printenv, printf, ps, pscan, pstree, pwd, pwdx, raidautorun, rdate, rdev, readahead, readlink, readprofile, realpath, reboot, reformime, remove-shell, renice, reset, resize, restorecon, resume, rev, rfkill, rm, rmdir, rmmod, route, rpm, rpm2cpio, rtcwake, run-init, run-parts, runcon, runlevel, runsv, runsvdir, rx, script, scriptreplay, sed, selinuxenabled, sendmail, seq, sestatus, setarch, setconsole, setenforce, setfattr, setfiles, setfont, setkeycodes, setlogcons, setpriv, setsebool, setserial, setsid, setuidgid, sh, sha1sum, sha256sum, sha3sum, sha512sum, showkey, shred, shuf, slattach, sleep, smemcap, softlimit, sort, split, ssl_client, start-stop-daemon, stat, strings, stty, su, sulogin, sum, sv, svc, svlogd, svok, swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar, taskset, tc, tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time, timeout, top, touch, tr, traceroute, traceroute6, true, truncate, ts, tty, ttysize, tunctl, tune2fs, ubiattach, ubidetach, ubimkvol, ubirename, ubirmvol, ubirsvol, ubiupdatevol, udhcpc, udhcpd, udpsvd, uevent, umount, uname, uncompress, unexpand, uniq, unit, unix2dos, unlink, unlzma, unlzop, unxz, unzip, uptime, users, usleep, uudecode, uuencode, vconfig, vi, vlock, volname, w, wall, watch, watchdog, wc, wget, which, who, whoami, whois, xargs, xxd, xz, xzcat, yes, zcat, zcip}
  \end{spacing}
  \vfill
\end{frame}

\begin{frame}
  \frametitle{BusyBox - Dowloading}
  \begin{itemize}
     \item Download BusyBox 1.33.0 sources from \url{https://busybox.net}
     \item Extract the archive with \code{tar xf}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{BusyBox - Configuring}
  \begin{columns}
  \column{0.7\textwidth}
     \begin{itemize}
        \item Run \code{make allnoconfig}\\
	      Starts with no applet selected
	\item Run \code{make menuconfig}\\
	      \begin{itemize}
	      \item In \code{Settings} \textrightarrow \code{Build
	      Options}, enable \code{Build static binary (no shared libs)}
	      \item In \code{Settings} \textrightarrow \code{Build
	      Options}, set \code{Cross compiler prefix} to \code{riscv64-linux-}
	      \item Then enable support for the following commands:\\
		    \code{ash}, \code{init}, \code{halt}, \code{mount}, \code{cat},
		    \code{mkdir}, \code{echo}, \code{ls}, \code{chmod}, \code{uptime},
		    \code{vi}, \code{ifconfig}, \code{httpd}
	      \end{itemize}
     \end{itemize}
  \column{0.3\textwidth}
    \includegraphics[width=\textwidth]{asciinema/384727.png}\\
    \tiny \url{https://asciinema.org/a/384727}
  \end{columns}
\end{frame}

\begin{frame}[fragile]
  \frametitle{BusyBox - Installing and compiling}
  \begin{columns}
  \column{0.6\textwidth}
  \begin{itemize}
     \item Compiling: \code{make} or \code{make -j 8} (faster)\\
	   Resulting size: only 276344 bytes!\\
	   Funny to see that we're using a 64 bit system to run
	   such small programs!
     \item Installing in \code{_install/}: \code{make install}
     \item See the created directory structure and the symbolic links
	   to \code{/bin/busybox}
     \item Installing to the root filesystem:
    \begin{block}{}
    \begin{verbatim}
sudo mkdir /mnt/rootfs
sudo mount /dev/loop2p2 /mnt/rootfs
sudo rsync -aH _install/ /mnt/rootfs/
sudo umount /mnt/rootfs
\end{verbatim}
    \end{block}
  \end{itemize}
  \column{0.4\textwidth}
    \includegraphics[width=\textwidth]{graphics/busybox-tree.png}\\
  \end{columns}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Completing and configuring the root filesystem (1)}
  \begin{itemize}
  \item We need to create a \code{dev} directory.\\
        The \code{devtmpfs} filesystem will automatically be mounted there\\
        (as \kconfigval{CONFIG_DEVTMPFS_MOUNT}{y})
  \item Let's also create \code{/proc} and \code{/sys} so that we can
        also mount the \code{proc} and \code{sysfs} virtual filesystems
        on the target:
    \begin{block}{}
\begin{verbatim}
mount -t proc nodev /proc
mount -t sysfs nodev /sys
\end{verbatim}
    \end{block}
    Without such virtual filesystems, commands such as \code{ps}
    or \code{top} can't work. 
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Completing and configuring the root filesystem (2)}
  Let's automate the mounting of \code{proc} and \code{sysfs}...
  \begin{itemize}
  \item Let's create an \code{/etc/inittab} file to configure Busybox Init:
    \begin{block}{}
\begin{verbatim}
# This is run first script:
::sysinit:/etc/init.d/rcS
# Start an "askfirst" shell on the console:
::askfirst:/bin/sh
\end{verbatim}
    \end{block}
  \item Let's create and fill \code{/etc/init.d/rcS} to automatically
    mount the virtual filesystems:
    \begin{block}{}
\begin{verbatim}
#!/bin/sh
mount -t proc nodev /proc
mount -t sysfs nodev /sys
\end{verbatim}
    \end{block}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Common mistakes}
  \begin{itemize}
    \item Don't forget to make the \code{rcS} script executable. Linux
          won't allow to execute it otherwise.
    \item Do not forget \code{#!/bin/sh} at the beginning of shell scripts!
          Without the leading \code{#!} characters, the Linux kernel has no
          way to know it is a shell script and will try to execute it as
          a binary file!
    \item Don't forget to specify the execution of a shell in
          \code{/etc/inittab} or at the end of \code{/etc/init.d/rcS}.
          Otherwise, execution will just stop without letting you type new commands!
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Add support for networking (1)}
  \begin{itemize}
    \item Add a network interface to the emulated machine:
    \begin{block}{}
\begin{verbatim}
sudo qemu-system-riscv64 -m 2G -nographic -machine virt -smp 8 \
    -bios opensbi/build/platform/generic/firmware/fw_payload.elf \
    -drive file=disk.img,format=raw,id=hd0 \
    -device virtio-blk-device,drive=hd0 \
    -netdev tap,id=tapnet,ifname=tap2,script=no,downscript=no \
    -device virtio-net-device,netdev=tapnet \
\end{verbatim}
    \end{block}
    \item Need to be \code{root} to bring up the \code{tap2} network
          interface
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Add support for networking (2)}
  \begin{itemize}
    \item On the target machine:
    \begin{block}{}
\begin{verbatim}
ifconfig -a
ifconfig eth0 192.168.2.100
\end{verbatim}
    \end{block}
    \item On the host machine:
    \begin{block}{}
\begin{verbatim}
ifconfig -a
sudo ifconfig tap2 192.168.2.1
ping 192.168.2.100
\end{verbatim}
    \end{block}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Simple CGI script}
    \begin{block}{}
    \small
\begin{verbatim}
#!/bin/sh
echo "Content-type: text/html"
echo
echo "<html>"
echo "<meta http-equiv=\"refresh\" content=\"1\">"
echo "<header></header><body>"
echo "<h1>Uptime information</h1>"
echo "Your embedded device has been running for:<pre><font color=Blue>"
echo `uptime`
echo "</font></pre>"
echo "</body></html>"
\end{verbatim}
    \end{block}
    Store it in \code{/www/cgi-bin/uptime} and make it executable.
\end{frame}

\begin{frame}[fragile]
  \frametitle{Start a web server}
  \begin{itemize}
    \item On the target machine:
    \begin{block}{}
\begin{verbatim}
/usr/sbin/httpd -h /www
\end{verbatim}
    \end{block}
    \item On the host machine, open in your browser:\\
          \url{http://192.168.2.100/cgi-bin/uptime}
  \end{itemize}
\end{frame}

\begin{frame}
  \frametitle{What to remember}
  \begin{itemize}
    \item Embedded Linux is just made out of simple components.
          It makes it easier to get started with Linux.
    \item You just need a toolchain, a bootloader, a kernel and a few executables.
    \item RISC-V is a new, open Instruction Set Architecture, use it and support it!
    \item In embedded Linux, things don't change that much over time.
          You just get more features.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \frametitle{Going further and thanks}
  \begin{itemize}
    \item Drew Fustini's unmatched presentation about Linux on RISC-V:
          \url{https://tinyurl.com/y6j8lfyz}
    \item Our "Embedded Linux system development" training materials
          (500+ pages, CC-BY-SA licence): \\
          \url{https://bootlin.com/doc/training/embedded-linux/}
    \item All our training materials and conference presentations:\\
          \url{https://bootlin.com/docs/}
    \item The Embedded Linux Wiki: presentations, howtos... contribute to it!\\
          \url{https://elinux.org}
    \item Gratitude to Geert Uytterhoeven, my mentor in conference
          fashion, always wearing a smile and the most relevant
          and elegant conference T-shirts.
  \end{itemize}
\end{frame}

\questionslide

\end{document}
