Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion boards/odroid-xu4/board.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ KERNEL_ARCH="arm"
KERNEL_REPO="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git"
KERNEL_TAG="v7.2"
KERNEL_DEFCONFIG="exynos_defconfig"
# Kernel config for Docker support and the USB WiFi dongle.
KERNEL_CONFIG_FRAGMENTS=("docker" "wifi-rtl8188fu")

# Mainline U-Boot. There is no odroid-xu4 defconfig: odroid-xu3_defconfig
# covers XU3/XU3-Lite/XU4/HC1/HC2 and identifies itself as such.
Expand All @@ -31,9 +33,10 @@ U_BOOT_DEFCONFIG="odroid-xu3_defconfig"

# The USB3 gigabit NIC is an RTL8153; r8152 asks for its PHY patch by name and
# logs a load failure without it. The NIC works either way.
# rtlwifi has the WiFi dongle's firmware.
FIRMWARE_REPO="https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git"
FIRMWARE_TAG="20260810"
FIRMWARE_DIRS=("rtl_nic")
FIRMWARE_DIRS=("rtl_nic" "rtlwifi")

# Samsung-signed boot chain: iROM -> BL1 -> BL2 -> TrustZone SW -> U-Boot.
# BL1, BL2 and the TrustZone monitor have no public source and are verified by
Expand Down
3 changes: 3 additions & 0 deletions boards/odroid-xu4/kernel-config/wifi-rtl8188fu
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# USB WiFi dongle: Realtek RTL8188FU (0bda:f179). Handled by mainline's
# rtl8xxxu driver, deps already come from exynos_defconfig.
CONFIG_RTL8XXXU=m
3 changes: 3 additions & 0 deletions boards/odroid-xu4/make.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 32-bit ARM Go defaults to PIE, which needs cgo. Packages that hardcode
# CGO_ENABLED=0 still need a patch -- see post-assemble.sh.
CGO_ENABLED=1
16 changes: 0 additions & 16 deletions boards/odroid-xu4/patches/mesa-arm-llvm22-stringmap.patch

This file was deleted.

34 changes: 34 additions & 0 deletions boards/odroid-xu4/post-assemble.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ for dir in "${FIRMWARE_DIRS[@]}"; do
cp -a "/build/firmware/${dir}/." "/build/gen/root/lib/firmware/${dir}/"
done

# MFC v8 video codec firmware: a top-level file, so FIRMWARE_DIRS doesn't cover it.
mkdir -p /build/gen/root/lib/firmware
cp -a /build/firmware/s5p-mfc-v8.fw /build/gen/root/lib/firmware/

# Mainline U-Boot's odroid-xu3 target keeps CONFIG_DISTRO_DEFAULTS, whose
# BOOT_TARGET_DEVICES walks mmc2 (the SD slot), mmc1 and mmc0 looking for
# extlinux/extlinux.conf. Hardkernel's boot.ini is a fork-only feature and is
Expand Down Expand Up @@ -38,3 +42,33 @@ cat >> /build/gen/root/etc/fstab <<FSTAB
PARTUUID=${BOOT_DISK_ID}-02 / ext4 defaults,noatime 0 1
PARTUUID=${BOOT_DISK_ID}-01 /boot ext4 defaults,noatime 0 2
FSTAB

# Docker install gotchas from real hardware (see README's Known gotchas).
# These two packages hardcode CGO_ENABLED=0, so patch it via a bashrc hook.
cat >> /build/gen/root/etc/portage/bashrc <<'EOF'
post_src_prepare() {
case "${CATEGORY}/${PN}" in
dev-go/go-md2man|app-containers/containerd)
sed -i 's/CGO_ENABLED=0/CGO_ENABLED=1/' Makefile
;;
esac
}
EOF

# containerd needs network for `go mod download`, blocked by network-sandbox.
# SHIM_CGO_ENABLED is a `?=` var, so an env var works directly (no sed).
mkdir -p /build/gen/root/etc/portage/env
cat > /build/gen/root/etc/portage/env/allow-net <<'EOF'
FEATURES="${FEATURES} -network-sandbox"
SHIM_CGO_ENABLED=1
EOF
echo 'app-containers/containerd allow-net' >> /build/gen/root/etc/portage/package.env

# docker-cli's own ebuild hardcodes CGO_ENABLED=0 for its manpages target
# since 29.7.2 (no sed/env fix works against that); docker-29.8.1+ blocks
# older docker-cli, so both are capped at the last good pair.
mkdir -p /build/gen/root/etc/portage/package.mask
cat > /build/gen/root/etc/portage/package.mask/docker-cli <<'EOF'
>app-containers/docker-cli-29.5.2
>app-containers/docker-29.5.2
EOF
8 changes: 0 additions & 8 deletions boards/odroid-xu4/pre-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,3 @@ echo 'media-libs/libglvnd X' > "${cross}/package.use/mesa"
# mesa_clc builds for CBUILD, so the card selection is repeated on the host.
mkdir -p /etc/portage/package.use
echo 'dev-util/mesa_clc video_cards_panfrost' > /etc/portage/package.use/mesa

# eapply_user reads patches from PORTAGE_CONFIGROOT, so they go in the prefix
# too. gallivm names llvm::StringMapIterator, which LLVM 22 removed, inside a
# DETECT_ARCH_ARM block: mesa 26.1.x fails to build for 32-bit ARM and only for
# 32-bit ARM. Fixed in mesa main, not backported.
mkdir -p "${cross}/patches/media-libs/mesa"
cp /scripts/boards/odroid-xu4/patches/mesa-arm-llvm22-stringmap.patch \
"${cross}/patches/media-libs/mesa/"
3 changes: 3 additions & 0 deletions boards/odroid-xu4/sandbox-packages.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# mkeficapsule needs gnutls built with pkcs11 (see sandbox-packages.use).
# Named here too so --changed-use actually rebuilds it.
net-libs/gnutls
2 changes: 2 additions & 0 deletions boards/odroid-xu4/sandbox-packages.use
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# U-Boot's mkeficapsule fails to link without gnutls pkcs11 support.
net-libs/gnutls pkcs11
5 changes: 5 additions & 0 deletions boards/odroid-xu4/target-packages.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ app-portage/gentoolkit
# Mesa for the Mali-T620. Midgard v4 caps at GLES 2.0 and there is no Vulkan,
# so this is panfrost only; VIDEO_CARDS is written by pre-deps.sh.
media-libs/mesa

# USB WiFi dongle support. SSID/PSK are set up on-device, not committed here.
net-wireless/wpa_supplicant
net-wireless/iw
net-wireless/wireless-regdb
9 changes: 7 additions & 2 deletions crossdev-stages/src/board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,14 @@ fn parse(name: &str, path: &Utf8Path, content: &str) -> Result<BoardConfig> {
.map(|v| v.split_whitespace().map(str::to_string).collect())
.unwrap_or_default(),
kernel_defconfig: req!("KERNEL_DEFCONFIG"),
kernel_config_fragments: kv
// Array syntax lives in `arrays`, not `kv` -- this always returned nothing.
kernel_config_fragments: arrays
.get("KERNEL_CONFIG_FRAGMENTS")
.map(|v| v.split_whitespace().map(str::to_string).collect())
.cloned()
.or_else(|| {
kv.get("KERNEL_CONFIG_FRAGMENTS")
.map(|v| v.split_whitespace().map(str::to_string).collect())
})
.unwrap_or_default(),
kernel_dtb_glob: kv.get("BOARD_DTB_GLOB").cloned(),

Expand Down
17 changes: 12 additions & 5 deletions crossdev-stages/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,7 +1386,7 @@ fn default_kernel(runner: &SandboxRunner, board: &BoardConfig) -> Result<()> {
cc = board.cross_compile,
defconfig = board.kernel_defconfig,
board_name = board.name,
fragments = kernel_config_fragments(board),
fragments = kernel_config_fragments(board, karch, &board.cross_compile),
))
}

Expand All @@ -1398,7 +1398,7 @@ fn default_kernel(runner: &SandboxRunner, board: &BoardConfig) -> Result<()> {
/// silently, and a board that says `# CONFIG_X is not set` has no way to find
/// out that X came back on. Checking the fragments themselves means the whole
/// request is covered rather than whichever symbols someone remembered to list.
fn kernel_config_fragments(board: &BoardConfig) -> String {
fn kernel_config_fragments(board: &BoardConfig, karch: &str, cc: &str) -> String {
if board.kernel_config_fragments.is_empty() {
return String::new();
}
Expand All @@ -1416,7 +1416,7 @@ fn kernel_config_fragments(board: &BoardConfig) -> String {
format!(
"frags=\n\
{out}\
make -C /build/linux ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE olddefconfig\n\
make -C /build/linux ARCH={karch} CROSS_COMPILE={cc} olddefconfig\n\
for f in $frags; do\n\
while read -r line; do\n\
case \"$line\" in\n\
Expand Down Expand Up @@ -2082,6 +2082,13 @@ pub fn build(

let result = match *step {
"deps" => run_step("deps", "deps", &bld, &runner, boards_root, board, |_r| {
// The overlay is a precondition of these providers alone
// (apk-tools, dnf5), so it is installed here and not in
// prepare(): every other command, a plain kernel build
// included, must build with the overlay repo unreachable.
if provider.needs_overlay() {
sandbox.install_overlay(defaults_root, provider)?;
}
// A wrong atom is otherwise only found by emerge, which gets
// there after the sandbox list has already been built -- ten
// minutes of compiling thrown away over a package that was
Expand Down Expand Up @@ -2363,12 +2370,12 @@ mod tests {

#[test]
fn no_fragments_generates_nothing() {
assert!(kernel_config_fragments(&board_with(&[])).is_empty());
assert!(kernel_config_fragments(&board_with(&[]), "riscv64", "riscv64-unknown-linux-gnu-").is_empty());
}

#[test]
fn a_fragment_is_looked_up_board_first_then_defaults() {
let script = kernel_config_fragments(&board_with(&["riscv64-no-vector"]));
let script = kernel_config_fragments(&board_with(&["riscv64-no-vector"]), "riscv64", "riscv64-unknown-linux-gnu-");
assert!(script.contains("/scripts/boards/demo/kernel-config/riscv64-no-vector"));
assert!(script.contains("/scripts/defaults/kernel-config/riscv64-no-vector"));
// Both directions of the check have to be generated: a symbol that was
Expand Down
19 changes: 18 additions & 1 deletion crossdev-stages/src/portage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ pub fn write_version_pins(portage_root: &Utf8Path, gcc_version: Option<&str>) ->
std::fs::write(mask_dir.join("pin-llvm"), mask)?;
std::fs::write(unmask_dir.join("pin-llvm"), unmask)?;

// Also pin these to LLVM_SLOT, same as llvm-core/* above.
std::fs::write(
mask_dir.join("pin-llvm-extra"),
"llvm-runtimes/libclc\ndev-util/spirv-llvm-translator\n",
)?;
std::fs::write(
unmask_dir.join("pin-llvm-extra"),
format!(
"=llvm-runtimes/libclc-{llvm_slot}*\n=dev-util/spirv-llvm-translator-{llvm_slot}*\n"
),
)?;

Ok(())
}

Expand Down Expand Up @@ -342,9 +354,14 @@ impl<'a> Portage<'a> {

/// Cross-emerge packages into the target stage (mounted at `/target`).
/// Uses `{chost}-emerge` which crossdev installs.
///
/// `--backtrack=100`: ROOT=/target's near-empty vdb makes this resolve
/// almost the whole graph from scratch; the default depth (20) isn't enough.
pub fn cross_emerge(&self, chost: &str, packages: &[&str]) -> Result<()> {
let pkgs = shell_quote_atoms(packages);
self.run_emerge(&format!("ROOT=/target {chost}-emerge -b -k {pkgs}"))
self.run_emerge(&format!(
"ROOT=/target {chost}-emerge -b -k --backtrack=100 {pkgs}"
))
}

/// Cross-emerge with `USE=build` for bootstrapping (baselayout, portage).
Expand Down
34 changes: 34 additions & 0 deletions crossdev-stages/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ impl RootfsProvider {
}
}

/// Whether the `deps` step emerges atoms the crossdev-stages overlay
/// carries (`app-arch/apk-tools`, `sys-apps/dnf5`). The only reason
/// any build needs the overlay repository to be reachable, so nothing
/// else may treat it as a precondition.
pub fn needs_overlay(&self) -> bool {
match self {
Self::Alpine | Self::Fedora => true,
Self::Gentoo
| Self::Debian
| Self::Ubuntu
| Self::Buildroot
| Self::None => false,
}
}

/// The debootstrap flavour behind this provider, if it is one.
pub fn debootstrap(&self) -> Option<Debootstrap> {
match self {
Expand Down Expand Up @@ -442,6 +457,25 @@ impl FedoraImage {
mod tests {
use super::{Debootstrap, RootfsProvider, SecondStage};

#[test]
fn only_alpine_and_fedora_need_the_overlay() {
assert!(RootfsProvider::Alpine.needs_overlay());
assert!(RootfsProvider::Fedora.needs_overlay());
for p in [
RootfsProvider::Gentoo,
RootfsProvider::Debian,
RootfsProvider::Ubuntu,
RootfsProvider::Buildroot,
RootfsProvider::None,
] {
assert!(
!p.needs_overlay(),
"{} must build without the overlay",
p.name()
);
}
}

#[test]
fn parse_known_values() {
assert_eq!(RootfsProvider::parse("gentoo"), Some(RootfsProvider::Gentoo));
Expand Down
Loading
Loading