1# SPDX-License-Identifier: GPL-2.0+
2# This Dockerfile is used to build an image containing basic stuff to be used
3# to build U-Boot and run our test suites.
4
5FROM ubuntu:jammy-20250714
6LABEL org.opencontainers.image.authors="Tom Rini <trini@konsulko.com>"
7LABEL org.opencontainers.image.description=" This image is for building U-Boot inside a container"
8
9# Used by docker to set the target platform: valid values are linux/arm64/v8
10# and linux/amd64
11ARG TARGETPLATFORM
12
13# Used by docker to set the build platform: the only valid value is linux/amd64
14ARG BUILDPLATFORM
15
16# Make sure apt is happy
17ENV DEBIAN_FRONTEND=noninteractive
18
19# Set architectures to build for (leaving out ARM which is an exception)
20ENV ARCHS="aarch64 arc i386 m68k mips microblaze nios2 powerpc riscv64 riscv32 sh2 x86_64"
21
22# Mirror containing the toolchains
23ENV MIRROR=https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin
24
25# Toolchain version
26ENV TCVER=14.2.0
27
28RUN echo "Building on $BUILDPLATFORM, for target $TARGETPLATFORM"
29
30# Add LLVM repository
31RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
32    --mount=type=cache,target=/var/lib/apt,sharing=locked \
33    apt-get update && apt-get install -y gnupg2 wget xz-utils
34RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
35RUN echo deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main | tee /etc/apt/sources.list.d/llvm.list
36
37# Create a list of URLs to process, then pass them into a 'while read' loop
38RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then HOSTARCH=x86_64; else HOSTARCH=arm64; fi; ( \
39	# Manually install the kernel.org "Crosstool"-based toolchains
40	for arch in $ARCHS; do \
41		echo $MIRROR/$HOSTARCH/$TCVER/${HOSTARCH}-gcc-$TCVER-nolibc-${arch}-linux.tar.xz; \
42	done; \
43	\
44	# Deal with ARM, which has a 'gnueabi' suffix
45	echo $MIRROR/${HOSTARCH}/$TCVER/${HOSTARCH}-gcc-$TCVER-nolibc-arm-linux-gnueabi.tar.xz; \
46	\
47	) | while read url; do \
48		# Read the URL and unpack it into /opt
49		wget -O - $url | tar -C /opt -xJ; \
50	done
51
52# Manually install other toolchains
53RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
54		wget -O - https://github.com/foss-xtensa/toolchain/releases/download/2020.07/x86_64-2020.07-xtensa-dc233c-elf.tar.gz | tar -C /opt -xz; \
55	fi
56
57# Update and install things from apt now
58RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
59    --mount=type=cache,target=/var/lib/apt,sharing=locked \
60    apt-get update && apt-get install -y \
61	automake \
62	autopoint \
63	bc \
64	binutils-dev \
65	bison \
66	build-essential \
67	byacc \
68	cgpt \
69	clang-18 \
70	coreutils \
71	cpio \
72	curl \
73	device-tree-compiler \
74	dosfstools \
75	e2fsprogs \
76	efitools \
77	erofs-utils \
78	exfatprogs \
79	expect \
80	fakeroot \
81	fdisk \
82	flex \
83	gawk \
84	gdisk \
85	gettext \
86	git \
87	gnu-efi \
88	gnutls-dev \
89	graphviz \
90	help2man \
91	iasl \
92	imagemagick \
93	inetutils-telnet \
94	iputils-ping \
95	libconfuse-dev \
96	libgit2-dev \
97	libjson-glib-dev \
98	libgnutls28-dev \
99	libgnutls30 \
100	libpixman-1-dev \
101	libpython3-dev \
102	libsdl1.2-dev \
103	libsdl2-dev \
104	libseccomp-dev \
105	libslirp-dev \
106	libssl-dev \
107	libtool \
108	libudev-dev \
109	libusb-1.0-0-dev \
110	lz4 \
111	lzma-alone \
112	lzop \
113	mount \
114	mtd-utils \
115	mtools \
116	net-tools \
117	ninja-build \
118	openssl \
119	picocom \
120	parted \
121	pkg-config \
122	python-is-python3 \
123	python2.7 \
124	python3 \
125	python3-dev \
126	python3-pip \
127	python3-sphinx \
128	python3-tomli \
129	python3-venv \
130	rpm2cpio \
131	sbsigntool \
132	socat \
133	softhsm2 \
134	sparse \
135	srecord \
136	sudo \
137	swig \
138	texinfo \
139	util-linux \
140	uuid-dev \
141	vboot-kernel-utils \
142	vboot-utils \
143	xilinx-bootgen \
144	xxd \
145	zip
146
147# Build GRUB UEFI targets for ARM & RISC-V, 32-bit and 64-bit
148RUN git clone git://git.savannah.gnu.org/grub.git /tmp/grub && \
149	cd /tmp/grub && \
150	git checkout grub-2.12 && \
151	git config --global user.name "GitLab CI Runner" && \
152	git config --global user.email trini@konsulko.com && \
153	./bootstrap && \
154	mkdir -p /opt/grub && \
155	./configure --target=aarch64 --with-platform=efi \
156	CC=gcc \
157	TARGET_CC=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux-gcc \
158	TARGET_OBJCOPY=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux-objcopy \
159	TARGET_STRIP=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux-strip \
160	TARGET_NM=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux-nm \
161	TARGET_RANLIB=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux-ranlib && \
162	make -j$(nproc) && \
163	./grub-mkimage -O arm64-efi -o /opt/grub/grubaa64.efi --prefix= -d \
164	grub-core cat chain configfile echo efinet ext2 fat halt help linux \
165	lsefisystab loadenv lvm minicmd normal part_msdos part_gpt reboot \
166	search search_fs_file search_fs_uuid search_label serial sleep test \
167	true && \
168	make clean && \
169	./configure --target=arm --with-platform=efi \
170	CC=gcc \
171	TARGET_CC=/opt/gcc-${TCVER}-nolibc/arm-linux-gnueabi/bin/arm-linux-gnueabi-gcc \
172	TARGET_OBJCOPY=/opt/gcc-${TCVER}-nolibc/arm-linux-gnueabi/bin/arm-linux-gnueabi-objcopy \
173	TARGET_STRIP=/opt/gcc-${TCVER}-nolibc/arm-linux-gnueabi/bin/arm-linux-gnueabi-strip \
174	TARGET_NM=/opt/gcc-${TCVER}-nolibc/arm-linux-gnueabi/bin/arm-linux-gnueabi-nm \
175	TARGET_RANLIB=/opt/gcc-${TCVER}-nolibc/arm-linux-gnueabi/bin/arm-linux-gnueabi-ranlib && \
176	make -j$(nproc) && \
177	./grub-mkimage -O arm-efi -o /opt/grub/grubarm.efi --prefix= -d \
178	grub-core cat chain configfile echo efinet ext2 fat halt help linux \
179	lsefisystab loadenv lvm minicmd normal part_msdos part_gpt reboot \
180	search search_fs_file search_fs_uuid search_label serial sleep test \
181	true && \
182	make clean && \
183	grub_cv_cc_mcmodel=no ./configure --target=riscv64 --with-platform=efi \
184	CC=gcc \
185	TARGET_CC=/opt/gcc-${TCVER}-nolibc/riscv64-linux/bin/riscv64-linux-gcc \
186	TARGET_OBJCOPY=/opt/gcc-${TCVER}-nolibc/riscv64-linux/bin/riscv64-linux-objcopy \
187	TARGET_STRIP=/opt/gcc-${TCVER}-nolibc/riscv64-linux/bin/riscv64-linux-strip \
188	TARGET_NM=/opt/gcc-${TCVER}-nolibc/riscv64-linux/bin/riscv64-linux-nm \
189	TARGET_RANLIB=/opt/gcc-${TCVER}-nolibc/riscv64-linux/bin/riscv64-linux-ranlib && \
190	make -j$(nproc) && \
191	./grub-mkimage -O riscv64-efi -o /opt/grub/grubriscv64.efi --prefix= -d \
192	grub-core cat chain configfile echo efinet ext2 fat halt help linux \
193	lsefisystab loadenv lvm minicmd normal part_msdos part_gpt reboot \
194	search search_fs_file search_fs_uuid search_label serial sleep test \
195	true && \
196	make clean && \
197	./configure --target=i386 --with-platform=efi \
198	CC=gcc \
199	TARGET_CC=/opt/gcc-${TCVER}-nolibc/i386-linux/bin/i386-linux-gcc \
200	TARGET_OBJCOPY=/opt/gcc-${TCVER}-nolibc/i386-linux/bin/i386-linux-objcopy \
201	TARGET_STRIP=/opt/gcc-${TCVER}-nolibc/i386-linux/bin/i386-linux-strip \
202	TARGET_NM=/opt/gcc-${TCVER}-nolibc/i386-linux/bin/i386-linux-nm \
203	TARGET_RANLIB=/opt/gcc-${TCVER}-nolibc/i386-linux/bin/i386-linux-ranlib && \
204	make -j$(nproc) && \
205	./grub-mkimage -O i386-efi -o /opt/grub/grub_x86.efi --prefix= -d \
206	grub-core normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd && \
207	make clean && \
208	./configure --target=x86_64 --with-platform=efi \
209	CC=gcc \
210	TARGET_CC=/opt/gcc-${TCVER}-nolibc/x86_64-linux/bin/x86_64-linux-gcc \
211	TARGET_OBJCOPY=/opt/gcc-${TCVER}-nolibc/x86_64-linux/bin/x86_64-linux-objcopy \
212	TARGET_STRIP=/opt/gcc-${TCVER}-nolibc/x86_64-linux/bin/x86_64-linux-strip \
213	TARGET_NM=/opt/gcc-${TCVER}-nolibc/x86_64-linux/bin/x86_64-linux-nm \
214	TARGET_RANLIB=/opt/gcc-${TCVER}-nolibc/x86_64-linux/bin/x86_64-linux-ranlib && \
215	make -j$(nproc) && \
216	./grub-mkimage -O x86_64-efi -o /opt/grub/grub_x64.efi --prefix= -d \
217	grub-core normal echo lsefimmap lsefi lsefisystab efinet tftp minicmd && \
218	rm -rf /tmp/grub
219
220RUN git clone https://gitlab.com/qemu-project/qemu.git /tmp/qemu && \
221	cd /tmp/qemu && \
222	git checkout v10.0.2 && \
223	# config user.name and user.email to make 'git am' happy
224	git config user.name u-boot && \
225	git config user.email u-boot@denx.de && \
226	./configure --prefix=/opt/qemu --target-list="aarch64-softmmu,arm-softmmu,i386-softmmu,m68k-softmmu,mips-softmmu,mips64-softmmu,mips64el-softmmu,mipsel-softmmu,ppc-softmmu,riscv32-softmmu,riscv64-softmmu,sh4-softmmu,x86_64-softmmu,xtensa-softmmu" && \
227	make -j$(nproc) all install && \
228	rm -rf /tmp/qemu
229
230# Build fiptool
231RUN git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git /tmp/tf-a && \
232	cd /tmp/tf-a/ && \
233	git checkout v2.12.0 && \
234	make CROSS_COMPILE=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux- \
235		PLAT=fvp BL33=/dev/null -j$(nproc) all fip && \
236	mkdir -p /usr/local/bin /opt/tf-a/vexpress_fvp && \
237	cp tools/fiptool/fiptool /usr/local/bin && \
238	cp build/fvp/release/fip.bin build/fvp/release/bl1.bin \
239		/opt/tf-a/vexpress_fvp/ && \
240	rm -rf build/fvp && \
241	make CROSS_COMPILE=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux- \
242		PLAT=fvp BL33=/dev/null TRANSFER_LIST=1 -j$(nproc) all fip && \
243	mkdir -p /opt/tf-a/vexpress_fvp_bloblist && \
244	cp build/fvp/release/fip.bin build/fvp/release/bl1.bin \
245		/opt/tf-a/vexpress_fvp_bloblist/ && \
246	rm -rf /tmp/tf-a
247
248# Download the Arm Architecture FVP platform. This file is double compressed.
249RUN wget -O - https://developer.arm.com/-/cdn-downloads/permalink/FVPs-Architecture/FM-11.28/FVP_Base_RevC-2xAEMvA_11.28_23_Linux64.tgz | gunzip -dc | tar -C /opt -x
250
251# Build genimage (required by some targets to generate disk images)
252RUN wget -O - https://github.com/pengutronix/genimage/releases/download/v14/genimage-14.tar.xz | tar -C /tmp -xJ && \
253	cd /tmp/genimage-14 && \
254	./configure && \
255	make -j$(nproc) && \
256	make install && \
257	rm -rf /tmp/genimage-14
258
259# Build libtpms
260RUN git clone https://github.com/stefanberger/libtpms /tmp/libtpms && \
261	cd /tmp/libtpms && \
262	./autogen.sh && \
263	./configure && \
264	make -j$(nproc) && \
265	make install && \
266	ldconfig && \
267	rm -rf /tmp/libtpms
268
269# Build swtpm
270RUN git clone https://github.com/stefanberger/swtpm /tmp/swtpm && \
271	cd /tmp/swtpm && \
272	./autogen.sh && \
273	./configure && \
274	make -j$(nproc) && \
275	make install && \
276	rm -rf /tmp/swtpm
277
278# Build trace-cmd
279RUN mkdir /tmp/trace && \
280    git clone https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git /tmp/trace/libtraceevent && \
281    cd /tmp/trace/libtraceevent && \
282    make -j$(nproc) && \
283    sudo make install && \
284    git clone https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git /tmp/trace/libtracefs && \
285    cd /tmp/trace/libtracefs && \
286    make -j$(nproc) && \
287    sudo make install && \
288    git clone https://github.com/rostedt/trace-cmd.git /tmp/trace/trace-cmd && \
289    cd /tmp/trace/trace-cmd && \
290    make -j$(nproc) && \
291    sudo make install && \
292    rm -rf /tmp/trace
293
294# Build coreboot
295RUN wget -O - https://coreboot.org/releases/coreboot-25.03.tar.xz | tar -C /tmp -xJ && \
296    cd /tmp/coreboot-25.03 && \
297    make crossgcc-i386 CPUS=$(nproc) && \
298    make -C payloads/coreinfo olddefconfig && \
299    make -C payloads/coreinfo && \
300    make olddefconfig && \
301    echo CONFIG_GENERIC_LINEAR_FRAMEBUFFER=y | tee -a .config && \
302    echo CONFIG_USE_OPTION_TABLE=y | tee -a .config && \
303    make olddefconfig && \
304    make -j $(nproc) && \
305    sudo mkdir /opt/coreboot && \
306    sudo cp build/coreboot.rom build/cbfstool /opt/coreboot/ && \
307    rm -rf /tmp/coreboot-25.03
308
309# Create our user/group
310RUN echo uboot ALL=NOPASSWD: ALL > /etc/sudoers.d/uboot
311RUN useradd -m -U uboot
312USER uboot:uboot
313
314# Populate the cache for pip to use. Get these via wget as the
315# COPY / ADD directives don't work as we need them to.
316RUN wget -O /tmp/pytest-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/test/py/requirements.txt
317RUN wget -O /tmp/sphinx-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/doc/sphinx/requirements.txt
318RUN wget -O /tmp/binman-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/binman/requirements.txt
319RUN wget -O /tmp/buildman-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/buildman/requirements.txt
320RUN wget -O /tmp/patman-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/patman/requirements.txt
321RUN wget -O /tmp/u_boot_pylib-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/u_boot_pylib/requirements.txt
322RUN python3 -m venv /tmp/venv && \
323	. /tmp/venv/bin/activate && \
324	pip install -r /tmp/pytest-requirements.txt \
325		-r /tmp/sphinx-requirements.txt \
326		-r /tmp/binman-requirements.txt \
327		-r /tmp/buildman-requirements.txt \
328		-r /tmp/patman-requirements.txt \
329		-r /tmp/u_boot_pylib-requirements.txt && \
330	deactivate && \
331	rm -rf /tmp/venv /tmp/*-requirements.txt
332
333# Create the buildman config file
334RUN /bin/echo -e "[toolchain]\nkernelorg = /opt/gcc-${TCVER}-nolibc/*" > ~/.buildman
335RUN /bin/echo -e "root = /usr" >> ~/.buildman
336RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
337        /bin/echo -e "\n[toolchain-prefix]\nxtensa = /opt/2020.07/xtensa-dc233c-elf/bin/xtensa-dc233c-elf-" >> ~/.buildman; \
338    fi
339RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
340        /bin/echo -e "\n[toolchain-prefix]\naarch64 = /opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux-" >> ~/.buildman; \
341    fi
342RUN /bin/echo -e "\n[toolchain-alias]\nsh = sh2" >> ~/.buildman
343RUN /bin/echo -e "\nx86 = i386" >> ~/.buildman;
344
345# Add mkbootimg tool
346RUN git clone https://android.googlesource.com/platform/system/tools/mkbootimg /home/uboot/mkbootimg
347ENV PYTHONPATH="${PYTHONPATH}:/home/uboot/mkbootimg"
348