ELBE: automated building of Ubuntu images for a Raspberry Pi 3B

Building embedded Linux systems

ELBETypical embedded Linux systems include a wide number of software components, which all need to be compiled and integrated together. Two main approaches are used in the industry to integrate such embedded Linux systems: build systems such as Yocto/OpenEmbedded, Buildroot or OpenWrt, and binary distributions such as Debian, Ubuntu or Fedora. Of course, both options have their own advantages and drawbacks.

One of the benefits of using standard binary distributions such as Debian or Ubuntu is their widespread use, their serious and long-term security maintenance and their large number of packages. However, they often lack appropriate tools to automate the process of creating a complete Linux system image that combines existing binary packages and custom packages.

In this blog post, we introduce ELBE (Embedded Linux Build Environment), which is a build system designed to build Debian distributions and images for the embedded world. While ELBE was initially focused on Debian only, Bootlin contributed support for building Ubuntu images with ELBE, and this blog post will show as an example how to build an Ubuntu image with ELBE for a Raspberry Pi 3B.

ELBE base principle

When you first run ELBE, it creates a Virtual Machine (VM) for building root filesystems. This VM is called initvm. The process of building the root filesystem for your image is to submit and XML file to the initvm, which triggers the building of an image.

The ELBE XML file can contain an archive, which can contain configuration files, and additional software. It uses pre-built software in the form of Debian/Ubuntu packages (.deb). It is also possible to use custom repositories to get special packages into the root filesystem. The resulting root file system (a customized Debian or Ubuntu distribution) can still be upgraded and maintained through Debian’s tools such as APT (Advanced Package Tool). This is the biggest difference between ELBE and other build systems like the Yocto Project and Buildroot.

Bootlin contributions

As mentioned in this blog post introduction, Bootlin contributed support for building Ubuntu images to ELBE, which led to the following upstream commits:

Build an Ubuntu image for the Raspberry Pi 3B

We are now going to illustrate how to use ELBE by showing how to build an image for the popular RaspberryPi 3B platform.

Add required packages

This was tested on Ubuntu 20.04. Install the below packages if needed, and make sure you are in the libvirt, libvirt-qemu and kvm groups:

$ sudo apt install python3 python3-debian python3-mako \
  python3-lxml python3-apt python3-gpg python3-suds \
  python3-libvirt qemu-utils qemu-kvm p7zip-full \
  make libvirt-daemon libvirt-daemon-system \
  libvirt-clients python3-urwid
$ sudo adduser youruser libvirt 
$ sudo adduser youruser libvirt-qemu
$ sudo adduser youruser kvm
$ newgrp libvirt
$ newgrp libvirt-qemu
$ newgrp kvm

Prepare ELBE initvm

First, you need to clone ELBE’s git reposority:

git clone https://github.com/Linutronix/elbe.git

We need to use the v13.2 version because our latest contributions for Ubuntu support made it to 13.2:

$ cd elbe
$ git checkout v13.2

To create the initvm:

$ PATH=$PATH:$(pwd)
$ elbe initvm create --devel

The --devel parameter allows to use ELBE from the current working directory into the initvm.

If the command fails with the Signature with unknown key: message you need to add these keys to apt. Use the following command where XXX is the key to be added:

$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys XXX

Creating your initvm should take at least 10 to 20 minutes.

In case you rebooted your computer or stopped the VM, you will need to start it:

$ elbe initvm start

Create an ELBE project for our Ubuntu image.

To begin with, we will base our image on the armhf-ubuntu example. We create an ELBE pbuilder project and not a simple ELBE project because we later want to build our own Linux kernel package for our board:

$ elbe pbuilder create --xmlfile=examples/armhf-ubuntu.xml \
  --writeproject rpi.prj --cross

The project identifier is written to rpi.prj. We save the identifier to a shell variable to simplify the next ELBE commands:

$ PRJ=$(cat rpi.prj)

Build the Linux package

As explained earlier we want to use ELBE to build our package for the Linux kernel. ELBE uses the standard Debian tool pbuilder to build packages. Therefore, we need to have debianized sources (i.e sources with the appropriate Debian metadata in a debian/ subfolder) to build a package with pbuilder.

First clone the Linux repositories:

$ git clone -b rpi-5.10.y https://github.com/raspberrypi/linux.git
$ cd linux

Debianize the Linux repositories. We use the elbe debianize command to simplify the generation of the debian folder:

$ elbe debianize

Fill the settings in the UI as follows (make sure you reduce the font size if you don’t see the Confirm button):

Make sure you set Name to rpi. Otherwise, you won’t get the output file names we use in the upcoming instructions.

The debianize command helps to create the skeleton of the debian folder in the sources. It has been pre-configured for a few packages like bootloaders or the Linux kernel, to create the rules to build these packages. It may need further modifications to finish the packaging process. Take a look a the manual to have more information on debianization. In our case, we need to tweak the debian/ folder with the two following steps to cross-build the Raspberry Linux kernel without error.

Append the below lines to the debian/rules file (use tabs instead of spaces):

override_dh_strip:
	dh_strip -Xscripts

override_dh_shlibdeps:
	dh_shlibdeps -Xscripts

Remove the following line from the debian/linux-image-5.10-rpi.install file:

./lib/firmware/*

Update the source format:

$ echo "1.0" > debian/source/format

The Linux kernel sources are now ready, we can run elbe pbuilder to compile them:

$ mkdir ../out
$ elbe pbuilder build --project $PRJ --cross --out ../out

According to how fast your system is, this can run for hours!

If everything ends well without error the out/ directory has been filled with output files:

$ ls ../out
linux-5.10-rpi_1.0_armhf.buildinfo
linux-5.10-rpi_1.0_armhf.changes
linux-5.10-rpi_1.0.dsc
linux-5.10-rpi_1.0.tar.gz
linux-headers-5.10-rpi_1.0_armhf.deb
linux-image-5.10-rpi_1.0_armhf.deb
linux-libc-dev-5.10-rpi_1.0_armhf.deb

Update the Ubuntu XML image description

Now we have our Linux kernel packaged we can move on to the image generation. Since we started from examples/armhf-ubuntu.xml, we will modify this file to fit our needs.

We begin by adding the Linux kernel package to the XML image description in the pkg-list node:


<pkg-list>
...
	<pkg>linux-image-5.10-rpi</pkg>
...
</pkg-list>

We also have to add the Device Tree to the boot/ directory because the Linux kernel package installs all the Device Trees into the /usr/lib directory.

This change is part of the rootfs modifications, therefore it is described under the finetuning XML node. We also rename the kernel image to kernel.img:


<finetuning>
...
	<cp path="/usr/lib/linux-image-5.10-rpi/bcm2710-rpi-3-b.dtb">/boot/bcm2710-rpi-3-b.dtb</cp>
	<cp path="/usr/lib/linux-image-5.10-rpi/overlays">/boot/overlays</cp>
	<mv path="/boot/vmlinuz-5.10-rpi">/boot/kernel.img</mv>
...
</finetuning>

We want to use an SD card on our Raspberry Pi, so we have to describe the partitioning of our image. For this purpose, we add the images and the fstab XML nodes to the target XML node:


<target>
...
	<images>
		<msdoshd>
			<name>sdcard.img</name>
			<size>1500MiB</size>
				<partition>
					<size>50MiB</size>
					<label>boot</label>
					<bootable/>
				</partition>
				<partition>
					<size>remain</size>
					<label>rfs</label>
				</partition>
		</msdoshd>
	</images>
	<fstab>
		<bylabel>
			<label>rfs</label>
			<mountpoint>/</mountpoint>
			<fs>
				<type>ext2</type>
			</fs>
		</bylabel>
		<bylabel>
			<label>boot</label>
			<mountpoint>/boot</mountpoint>
			<fs>
				<type>vfat</type>
			</fs>
		</bylabel>
	</fstab>
...
</target>

The Raspberry Pi board also needs firmware binaries and configurations file to boot properly. We will use the overlay directory to add these Raspberry firmware files to the image:

$ mkdir -p overlay/boot
$ cd overlay/boot
$ wget https://github.com/raspberrypi/firmware/raw/1.20210201/boot/bootcode.bin
$ wget https://github.com/raspberrypi/firmware/raw/1.20210201/boot/start.elf
$ wget https://github.com/raspberrypi/firmware/raw/1.20210201/boot/fixup.dat
$ echo "console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootwait" > cmdline.txt
$ echo "dtoverlay=miniuart-bt" > config.txt

ELBE stores the overlay uuencoded in the XML file using the chg_archive command:

$ elbe chg_archive examples/armhf-ubuntu.xml overlay

The archive node got created in the XML file.

To tell ELBE that the XML file has changed, you need to send it to the initvm:

$ elbe control set_xml $PRJ examples/armhf-ubuntu.xml

Then build the image with ELBE:

$ elbe control build $PRJ
$ elbe control wait_busy $PRJ

Finally, if the build completes successfully, you can retrieve the image file from the initvm:

$ elbe control get_files $PRJ
$ elbe control get_file $PRJ sdcard.img.tar.gz

Now you can flash the SD card image:

$ tar xf sdcard.img.tar.gz
$ dd if=sdcard.img of=/dev/sdX bs=1M

And boot the board with root and foo as login and password:

Ubuntu 18.04.1 LTS myUbuntu ttyAMA0

myUbuntu login: root
Password: 
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 5.10-rpi armv7l)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@myUbuntu:~# 

Note: Ubuntu cannot be built for Raspberry A, B, B+, 0 and 0W according to https://wiki.ubuntu.com/ARM/RaspberryPi, as Ubuntu targets the ARMv7-A architecture, while the older RaspberryPi use an ARMv6 processor.

Further details

LTP: Linux Test Project, Bootlin contributions

Introduction

The Linux Test Project is a project that develops and maintains a large test suite that helps validating the reliability, robustness and stability of the Linux kernel and related features. LTP has been mainly developed by companies such as IBM, Cisco, Fujitsu, SUSE, RedHat, with a focus on desktop distributions.

On the embedded side, both the openembedded-core Yocto layer and Buildroot have packages that allow to use LTP on embedded targets. However, for a recent project, we practically tried to run the full LTP test suite on an i.MX8 based platform running a Linux system built with Yocto. It turned out that LTP was apparently not very often tested on Busybox-based embedded systems, and we faced a number of issues. In addition to reporting various bugs/issues to the upstream LTP project, we also contributed a number of fixes and improvements:

Our contributions received a very warm welcome in the LTP community, which turned out to be very open and responsive. We hope that these contributions will encourage others to use LTP, and hopefully to make sure it continues to work on embedded platforms.

Quick start guide

At the time of this writing, LTP has more than 3800 tests written by the community, including about 1000 network-related tests. The tests are grouped together in categories described by files in the runtest/ folder. Based on this, two scenarios of tests are defined: default and network which are described by two files in the scenario_groups/ folder. These two scenarios simply list the categories of tests that need to be executed.

Here are the contents of the default and network:

$ cat scenario_groups/default 
syscalls
fs
fs_perms_simple
fsx
dio
io
mm
ipc
sched
math
nptl
pty
containers
fs_bind
controllers
filecaps
cap_bounds
fcntl-locktests
connectors
power_management_tests
hugetlb
commands
hyperthreading
can
cpuhotplug
net.ipv6_lib
input
cve
crypto
kernel_misc
uevent
$ cat scenario_groups/network 
can
net.features
net.ipv6
net.ipv6_lib
net.tcp_cmds
net.multicast
net.rpc
net.nfs
net.rpc_tests
net.tirpc_tests
net.sctp
net_stress.appl
net_stress.broken_ip
net_stress.interface
net_stress.ipsec_dccp
net_stress.ipsec_icmp
net_stress.ipsec_sctp
net_stress.ipsec_tcp
net_stress.ipsec_udp
net_stress.multicast
net_stress.route

Once you have LTP built and installed on your board thanks to the appropriate OpenEmbedded or Buildroot package, you can run these two scenarios of test with the following commands (-n specify the network one):

$ cd /opt/ltp
$ ./runltp
$ ./runltp -n

Then take a look at the content of the result and the output directories.

For more information on building or running LTP please read this readme.

Bootlin welcomes Hervé Codina in its team

Welcome on board!Since March 1st, 2021, we’re happy to have an additional engineer, Hervé Codina, in our engineering team based in Toulouse, France.

Hervé has 20 years’ experience working in embedded systems, both bare-metal systems and embedded Linux systems, in a wide range of applications. Hervé has experience working with U-Boot, Barebox, Linux, Buildroot, Yocto, on ARM platforms from various silicon vendors. Hervé will work within our engineering team to deliver ready-to-use Linux Board Support Packages, port bootloaders and the Linux kernel to new platforms, develop Linux kernel device drivers, implement custom Linux systems with Buildroot or Yocto, and more. His 20 years experience will further increase the expertise that Bootlin provides to its worldwide customers.

See Hervé’s page on our site for more details. Hervé is joining our team in Toulouse, who already included Paul Kocialkowski, Miquèl Raynal, Köry Maincent, Maxime Chevallier, Thomas Perrot and Thomas Petazzoni.

CFP open for Live Embedded Event #2

Back in December 2020, together with Smile, Logilin and Theoris, Bootlin organized and participated to the first edition of Live Embedded Event, a new 1-day online conference focused on embedded systems topics. Following the success of this first edition, we are now organizing a second edition of Live Embedded Event, which will take place on June 3rd, 2021. Like the previous edition, this event is free.

Live Embedded Event #2

The call for papers is open, and we are looking for talk proposals on a wide range of topics:

  • Software update and provisioning
  • Network connectivity (Long range / Short range)
  • Edge Computing / ML-AI
  • Security & Safety
  • RTOS and Embedded frameworks
  • Firmware, BSP and Bootloader
  • Internet Of Things / Cyber Physical Systems
  • Hardware: system-on-chips, interfaces, FPGA, open hardware
  • Linux kernel
  • Build systems: Yocto, OpenWrt, Buildroot
  • Development process, methods and tools
  • Embedded Linux
  • Real time

Two talk formats are proposed: 45 minutes talk + 15 minutes of questions, or 25 minutes talk + 5 minutes of questions. If you want to get a feeling of the talks that were accepted for the first edition, look at the Youtube channel of the event.

We look forward to your proposals for Live Embedded Event #2, and of course, to your participation!

Bootlin contributions to Linux 5.11

Linux 5.11 was released quite some time ago now, but it’s never too late to have a look at Bootlin contributions to this release. As usual, we recommend reading the LWN articles on the 5.11 merge window: part 1 and part2. Also of interest is the Kernelnewbies page for 5.11.

Here are the main highlights of our contributions:

  • Alexandre Belloni, as the maintainer of the RTC subsystem, continued making numerous improvements and fixes to RTC drivers
  • On the support for Microchip ARM platforms, Alexandre Belloni switched the PWM atmel-tcb driver to a new Device Tree binding and added SAMA5D2 support, he did some improvements to the IIO driver for the Microchip ADC, and continued to remove platform_data support from Microchip drivers as all platforms are now converted to the Device Tree.
  • Alexandre Belloni contributed a new Simple Audio Mux driver for the ALSA subsystem, which can be used to control simple audio multiplexers driven using GPIOs, that allows to select which of their input line is connected to the output line.
  • Grégory Clement added support for several new MIPS platforms from Microchip: Luton, Serval and Jaguar2. All those platforms include a MIPS core, a few peripherals and more importantly an Ethernet switch. For now the support only includes the base platform support, but we are working on the switchdev driver for the Ethernet switch.
  • Miquèl Raynal, maintainer of the NAND subsystem and co-maintainer of the MTD subsystem, contributed numerous changes to the ECC support in the MTD subsystem, making it more generic so that it can be used not just for parallel NAND flashes, but also SPI NAND flashes. For more details, see the talk from Miquèl Raynal on this topic.

In addition to those 95 patches that we authored and contributed, several Bootlin engineers being maintainers of different subsystems of the Linux kernel reviewed and merged patches from other contributors:

  • Miquèl Raynal, as the NAND maintainer and MTD co-maintainer, reviewed and merged 67 patches from other contributors
  • Alexandre Belloni, as the RTC, I3C and Microchip ARM/MIPS platforms maintainer, reviewed and merged 47 patches from other contributors
  • Grégory Clement, as the Marvell EBU platform co-maintainer, reviewed and merged 33 patches from other contributors

Here is the detailed list of our contributions to Linux 5.11:

Videos and slides of Bootlin presentations at FOSDEM 2021

The videos from Bootlin’s presentations earlier this month at FOSDEM 2021 are now publicly available. Once again, FOSDEM was a busy event, even if it was online for once. As in most technical conferences, Bootlin engineers volunteered to share their experience and research by giving two talks.

Maxime Chevallier – Network Performance in the Linux Kernel, Getting the most out of the Hardware

Abstract: The networking stack is one of the most complex and optimized subsystems in the Linux kernel, and for a good reason. Between the wild range of applications, the complexity and variety of the networking hardware, getting good performance while keeping the stack easily usable from userspace has been a long-standing challenge.

Nowadays, complex Network Interface Controllers (NICs) can be found even on small embedded systems, bringing powerful features that were previously found only in the server world closest to day to day users.

This is a good opportunity to dive into the Linux Networking stack, to discover what is used to make networking as fast as possible, both by using all the features of the hardware and by implementing some clever software tricks.

In this talk, we cover these various techniques, ranging from simple batch processing with NAPI, queue management with RSS, RPS, XPS and so on, flow steering and filtering with ethool and TC, to finish with the newest big change that is XDP.

We dive into these various techniques and see how to configure them to squeeze the most out of your hardware, and discover that what was previously in the realm of datacenters and huge computers can now also be applied to embedded linux development.

Here are PDF slides for this presentation.

Michael Opdenacker – Embedded Linux from Scratch in 45 minutes, on RISC-V

Abstract: Discover how to build your own embedded Linux system completely from scratch. In this presentation and tutorial, we show how to build a custom toolchain (Buildroot), bootloader (opensbi / U-Boot) and kernel (Linux), that one can run on a system with the new RISV-V open Instruction Set Architecture emulated by QEMU. We also show how one can build a minimal root filesystem by oneself thanks to the BusyBox project. The presentation ends by showing how to control the system remotely through a tiny webserver. The approach is to provide only the files that are strictly necessary. That’s all the interest of embedded Linux: one can really control and understand everything that runs on the system, and see how simple the system can be. That’s much easier than trying to understand how a GNU/Linux system works from a distribution as complex as Debian!

The presentation also shares details about what’s specific to the RISC-V architecture, in particular about the various stages of the boot process. This presentation shares all the hardware (!), source code build instructions and demo binaries needed to reproduce everything at home, and add specific improvements. Most of the details are also useful to people using other hardware architectures (in particular arm and arm64).

It’s probably the first time a tutorial manages to show so many aspects of embedded Linux in less than an hour. See by yourself! At least, that’s for sure the first one demonstrating how to boot Linux from U-Boot in a RISC-V system emulated by QEMU.

Here are PDF slides for this presentation.

Bootlin acquired by Bootlin CTO Thomas Petazzoni and engineer Alexandre Belloni

We are happy to announce that Bootlin (formerly Free Electrons) has been acquired by two of its employees, Thomas Petazzoni and Alexandre Belloni.

Bootlin was founded in 2004 by Michael Opdenacker, with the goal of promoting the use of Linux and Free Software in embedded systems worldwide.

Thomas Petazzoni joined Bootlin in 2008, as the first employee. Thomas expanded the company offering by starting an engineering services activity, contributed to the growth of the company and took a CTO position. Thomas has a strong technical, open-source and embedded Linux background: he is the co-maintainer of the Buildroot project, has contributed to the Linux kernel, spoke at multiple international conferences and is the member of several embedded Linux conferences program committees. As Bootlin CTO, Thomas has been in charge of the complete engineering services activity: communication, sales, customer interaction, project management, scheduling and review.

Alexandre Belloni joined Bootlin in 2013, as an embedded Linux engineer. Alexandre has a deep open-source and technical background as well: he is the maintainer of multiple subsystems in the Linux kernel to which he has made significant contributions, and is an expert of the Yocto Project. He has been working closely with Thomas for many years in expanding and managing the engineering services activity.

As part of this acquisition, Thomas Petazzoni will become Bootlin’s CEO, while Alexandre Belloni will take the role of Bootlin’s COO. Michael Opdenacker will stay within Bootlin as an embedded Linux engineer and trainer.

“This acquisition is a logical continuation of my involvement in Bootlin and in the broader embedded Linux community” said Bootlin’s CEO Thomas Petazzoni, who added “I am proud to be leading the excellent engineering team at Bootlin, who will continue to offer the same training and engineering expertise to its customers worldwide”.

Alexandre Belloni, Bootlin’s COO, continued: “with two owners having both a strong technical background and a deep involvement in the open-source community, we intend to continue driving Bootlin with the same core values: technical excellence, open-source contribution and knowledge sharing”

Michael Opdenacker, Bootlin’s founder and former CEO, concluded: “Maria Llavata and I, after more than ten years of dedication to Bootlin’s customers and to the worldwide community of embedded Linux users and developers, are really happy to hand over the baton to Alexandre and Thomas, who have all the energy and enthusiasm needed to continue, expand and renew this beautiful adventure. I believe that Bootlin still has many new things to offer to the world, the fact that I am still on board is a proof of our trust in its new leadership.”

Device Tree 101 webinar slides and videos

As we announced back in January, we have offered in partnership with ST on February 9 a free webinar titled Device Tree 101, which gives a detailed introduction to the Device Tree, an important mechanism used in the embedded Linux ecosystem to describe hardware platforms. We were happy to see the interest around this topic and webinar.

Bootlin has always shared freely and openly all its technical contents, including our training materials, and this webinar is no exception. We are therefore sharing the slides and video recording of both sessions of this webinar:

Thanks to everyone who participated and thanks to ST for the support in organizing this event! Do not hesitate to share and/or like our video, and to suggest us other topics that would be useful to cover in future webinars!

New training course: embedded Linux boot time optimization

For many embedded products, the issue of how much time it takes from power-on to the application being fully usable by the end-user is an important challenge. Bootlin has been providing its expertise and experience in this area to its customers for many years through numerous boot time optimization projects, and we have shared this knowledge through a number of talks at several conferences over the past years.

We are now happy to announce that we have a new training course Embedded Linux boot time optimization, open for public registration. This training course was already given to selected Bootlin customers and is now available for everyone.

Embedded Linux boot time optimization

The training course will be lead by Michael Opdenacker, Bootlin’s founder, and author of several publications on the topic of boot time optimization. The course is organized over 4 sessions of 4 hours, with a significant fraction of time spent on practical demonstrations showing on a real-life example the techniques to measure and reduce the boot time of an embedded Linux system.

As usual with Bootlin, the training materials are fully available: Agenda, Slides and Practical lab instructions.

Boot time optimization slide

Our first course open for public registration will take place from April 6th to April 9th, 2021, from 14:00 to 18:00 UTC+2 (Paris time) on each day. The session cost is 519 EUR if you take advantage of the early bird price available until March 9th. Otherwise, the regular rate is 619 EUR. You can register now for this course on Eventbrite.

Also, if you’re interested in organizing a dedicated session for your company, do not hesitate to contact us.

Online training courses in March/April 2021

Our online training courses of January are now all completed, and were again successful. So we’re happy to announce the next dates for our public training courses in March and April, for all our courses: Embedded Linux system development, Linux kernel driver development, Yocto and OpenEmbedded system development, Buildroot system development and Linux graphics stack.

It is worth mentioning that we now have an Early Bird price, which is valid up to 1 month before the course, so register early if you’re interested!

Type Dates Time Duration Cost and registration
Embedded Linux (agenda) Mar. 8, 9, 10, 11, 12, 15, 16, 2021
+ extra session on Mar. 17 if needed
14:00 – 18:00 (Paris, UTC+1) 28 h Early: 829 EUR*
Regular: 929 EUR*
Register
Linux kernel (agenda) Mar. 9, 10, 11, 12, 16, 17, 18, 2021 13:30 – 17:30 (Paris time, UTC+1) 28 h Early: 829 EUR*
Regular: 929 EUR*
register
Buildroot (agenda) Mar. 8, 9, 10, 11, 2021 14:00 – 18:00 (Paris time, UTC+1) 16 h Early: 519 EUR*
Regular: 619 EUR*
Register
Yocto Project (agenda) Mar. 22, 23, 24, 25, 2021
+ extra session on Mar 26 if needed
14:00 – 18:00 (Paris time, UTC+1) 16 h Early: 519 EUR*
Regular: 619 EUR*
Register
Linux Graphics (agenda) Apr. 6, 7, 8, 9, 2021 14:00 – 18:00 (Paris time, UTC+2) 16 h Early: 519 EUR*
Regular: 619 EUR*
Register