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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
output/
84 changes: 84 additions & 0 deletions scripts/Dockerfile.kernel-build
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# SPDX-License-Identifier: BSD-3-Clause
#
# Dockerfile.kernel-build - Kernel build environment with dependencies
# resolved dynamically from a real kernel source
# tree's debian/control, instead of a
# hand-maintained control.<variant> snapshot.
#
# Based on docker.io/library/ubuntu:resolute, with public.ecr.aws/ubuntu/ubuntu:resolute
# as a fallback for when that tag isn't published under the primary registry.
# Both are genuine multi-arch manifest lists (amd64, arm64, ppc64le, armv7,
# riscv64, s390x), unlike ghcr.io/qualcomm-linux/pkg-builder:resolute, which
# is arm64-only and falls back to full-system QEMU emulation on an amd64
# host. A multi-arch manifest lets docker build/run pick the native manifest
# for the host, so only the cross-compiler invocations run under
# emulation-free cross toolchains. build-docker-image.sh probes which base
# image is available and passes it via the BASE_IMAGE build arg below.
#
# Not built directly — use build-docker-image.sh, which first runs
# `debian/rules clean` against a real kernel source tree to produce the
# `control` and `extra-tools.txt` files this Dockerfile's build context
# expects, then invokes `docker build` with this file.
#
# Build args:
# BASE_IMAGE Base image reference to build FROM (must be a genuine
# multi-arch manifest list); resolved by build-docker-image.sh
# TARGET_ARCH Target Debian architecture (e.g. arm64, amd64)
# CROSS "true" for cross-compilation (host arch != TARGET_ARCH),
# "false" for a native build (default)

ARG BASE_IMAGE=docker.io/library/ubuntu:resolute
FROM ${BASE_IMAGE}

ARG TARGET_ARCH
ARG CROSS=false
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

ENV DEBIAN_FRONTEND=noninteractive

# Base tools to run debian/rules (dh_testdir/dch/etc) and resolve build-dep
# (dpkg-dev). Mirrors docker-pkg-build's Dockerfiles/base-packages.txt,
# trimmed to what this kernel build needs.
#
# Proxy vars are scoped to this RUN only (not ENV), so they won't leak
# into containers started from the built image.
RUN http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" \
apt-get update -qq && \
apt-get install -y --no-install-recommends \
ca-certificates dpkg-dev build-essential debhelper fakeroot devscripts && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Enable deb-src for build-dep
RUN sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources

RUN if [ "${CROSS}" = "true" ]; then dpkg --add-architecture "${TARGET_ARCH}"; fi

COPY extra-tools.txt /tmp/extra-tools.txt
RUN http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" \
apt-get update -qq && \
apt-get install -y $(cat /tmp/extra-tools.txt | tr '\n' ' ') && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Dynamically generated debian/control (from `debian/rules clean` against
# the real kernel source tree, patched for :native host-tool deps when
# cross-compiling) — not a hand-maintained snapshot.
COPY control /tmp/control-dir/debian/control

RUN http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" \
apt-get update -qq && \
cd /tmp/control-dir && \
if [ "${CROSS}" = "true" ]; then \
apt-get build-dep -y --host-architecture "${TARGET_ARCH}" --build-profiles cross . && \
apt-get build-dep -y . ; \
else \
apt-get build-dep -y . ; \
fi && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/control-dir

# Set default environment for build-kernel-deb.sh
ENV SKIP_BUILD_DEP=1
302 changes: 302 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
# Kernel Build Scripts

This directory contains scripts for building Ubuntu kernel .deb packages for Qualcomm platforms.

## Setup & Build Steps

### 1. Docker Access

Ensure your user can run Docker without sudo. If not already configured:

```bash
sudo usermod -aG docker $USER
newgrp docker
```

Verify Docker access:

```bash
docker ps
```

### 2. Prepare Workspace

Create a workspace directory (you can rename `canonical-pkg` as needed):

```bash
mkdir canonical-pkg && cd canonical-pkg
```

### 3. Pull Required Repositories

#### a) Pull the CI orchestrator (main branch)

```bash
git clone --depth 1 https://github.com/qualcomm-linux/pkg-linux-qcom-canonical.git
```

#### b) Pull the kernel source (resolute-qcom-devel branch)

```bash
git clone -b resolute-qcom-devel --depth 1 https://github.com/qualcomm-linux/pkg-linux-qcom-canonical.git resolute-qcom-devel
```

#### c) Pull the Qualcomm DTB metadata

```bash
git clone https://github.com/qualcomm-linux/qcom-dtb-metadata.git
```

Make the build scripts executable:

```bash
chmod +x pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh
chmod +x pkg-linux-qcom-canonical/scripts/build-docker-image.sh
chmod +x qcom-dtb-metadata/build-dtb-image.sh
```

### 4. Configure Proxy (First Time per Machine, if Needed)

The first `docker-build-kernel.sh` run on a machine builds a local Docker image, which needs `apt-get` access to Ubuntu package mirrors. If this machine's network can't reach those mirrors directly, pass a proxy for that one build — it's only used while building the Docker image, never by the container itself or by later kernel builds on the same machine (the image is cached locally once built):

```bash
# Replace your-proxy-server:8080 with your actual proxy address
HTTP_PROXY=http://your-proxy-server:8080 \
HTTPS_PROXY=http://your-proxy-server:8080 \
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh
```

This is a **one-time, per-machine** step.

After completing the above, your workspace structure should look like:

```
canonical-pkg/
├── pkg-linux-qcom-canonical/ # CI orchestrator (main branch)
│ ├── scripts/
│ │ ├── docker-build-kernel.sh # Docker wrapper for builds
│ │ ├── build-kernel-deb.sh # Core build script
│ │ ├── build-docker-image.sh # Builds the local Docker image on demand
│ │ ├── Dockerfile.kernel-build # Image definition used by build-docker-image.sh
│ │ ├── lib/ # Shared helpers sourced by the scripts above
│ │ ├── README.md
│ │ └── ...
│ └── ...
├── resolute-qcom-devel/ # Kernel source (resolute-qcom-devel branch)
│ ├── debian.qcom/ # Qualcomm-specific build config
│ ├── arch/
│ ├── drivers/
│ └── ...
├── qcom-dtb-metadata/ # DTB metadata
│ ├── build-dtb-image.sh
│ └── ...
└── output/ # Build artifacts (created after first build)
├── linux-image-*.deb
├── linux-modules-*.deb
├── linux-headers-*.deb
└── ...
```

---

## Quick Start

After completing the setup steps above, from the workspace directory:

```bash
# uses default source directory: resolute-qcom-devel
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh

# Specify a different source directory (relative to current directory)
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh ./resolute-qcom-devel
```

Output packages: `./output/`

---

## Common Arguments & Environment Variables

### Arguments

```bash
./scripts/docker-build-kernel.sh [SOURCE_DIR] [ARCH] [FLAVOR] [JOBS] [VERSION_SUFFIX]
```

| Argument | Default | Description |
|----------|---------|-------------|
| `SOURCE_DIR` | `resolute-qcom-devel` | Root of kernel source tree (resolved relative to current working directory) |
| `ARCH` | `arm64` | Target architecture: `arm64` |
| `FLAVOR` | `qcom` | Kernel flavor: `qcom`, `qcom-rt`, or `all` (builds both `qcom` and `qcom-rt`) |
| `JOBS` | `$(nproc)` | Parallel make jobs |
| `VERSION_SUFFIX` | (none) | Version suffix (e.g., `+g1a2b3c4` or `+myuser1`). Pass `auto` to generate from git HEAD |

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `IMAGE` | `kernel-build-docker:resolute-target-<ARCH>` | Docker image to use; built on demand via `build-docker-image.sh` if not already present locally |
| `OUTPUT_DIR` | `./output` (relative to current directory) | Where built `.deb` packages are placed. Set to a fixed path (relative or absolute) if you don't want the output location to depend on which directory you invoke the script from. Created on the host before the container starts, so it's never auto-created by Docker as root |
| `VERSION_SUFFIX` | (none) | Optional version suffix for the kernel package (e.g., `+v1.0`, `+myuser1`). Pass `auto` to generate from git HEAD |
| `DEBEMAIL` | `build-kernel-deb@localhost` | Email for changelog entries |
| `DEBFULLNAME` | `build-kernel-deb.sh` | Full name for changelog entries |
| `HTTP_PROXY` | (none) | HTTP proxy URL for Docker image build only (e.g., `http://your-proxy-server:8080`). Only needed on first run if your network cannot access Ubuntu package mirrors directly |
| `HTTPS_PROXY` | (none) | HTTPS proxy URL for Docker image build only (e.g., `http://your-proxy-server:8080`). Only needed on first run if your network cannot access Ubuntu package mirrors directly |

---

## Argument Priority

Arguments are resolved in the following order (first match wins):

1. **Positional arguments** — passed directly to the script
2. **Environment variables** — `SOURCE_DIR`, `ARCH`, `FLAVOR`, `JOBS`, `VERSION_SUFFIX`
3. **Default values** — built into the script

`SOURCE_DIR` is resolved relative to the current working directory.

### Example

```bash
# JOBS comes from the environment variable since no 4th positional arg is given
JOBS=8 ./scripts/docker-build-kernel.sh resolute-qcom-devel arm64 qcom
# Result: SOURCE_DIR=resolute-qcom-devel, ARCH=arm64, FLAVOR=qcom, JOBS=8, VERSION_SUFFIX=(none)
```

---

## docker-build-kernel.sh

Docker wrapper script for containerized kernel builds.

### Usage

```bash
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh [SOURCE_DIR] [ARCH] [FLAVOR] [JOBS] [VERSION_SUFFIX]
```

### Examples

```bash
# Basic build
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh

# Only change source directory (other params use defaults)
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh ./resolute-qcom-devel

# With custom version
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh ./resolute-qcom-devel arm64 qcom $(nproc) +v1.0

# Auto-generate version from git
./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh ./resolute-qcom-devel arm64 qcom $(nproc) auto

# Use environment variable for version suffix
VERSION_SUFFIX=+myuser1 ./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh

# Auto-generate version via environment variable
VERSION_SUFFIX=auto ./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh

```

---

## build-docker-image.sh (build your own local Docker image)

`docker-build-kernel.sh` builds this image automatically on first use if
`kernel-build-docker:resolute-target-<ARCH>` isn't already present locally —
you normally don't need to invoke it yourself. To build (or rebuild) the
image explicitly — with build-dependencies resolved dynamically from your
actual kernel source tree's `debian/control` (via `debian/rules clean`),
rather than a hand-maintained snapshot file — use:

```bash
./pkg-linux-qcom-canonical/scripts/build-docker-image.sh [SOURCE_DIR] [ARCH]
```

This produces a local image tagged `kernel-build-docker:resolute-target-<ARCH>`
(`<ARCH>` here is the compile *target* architecture, not necessarily the
image's own native architecture — see the note below). To use a different
image instead of the default, point `docker-build-kernel.sh` at it via the
`IMAGE` environment variable:

```bash
./pkg-linux-qcom-canonical/scripts/build-docker-image.sh ./resolute-qcom-devel arm64
IMAGE=my-custom-image:tag ./pkg-linux-qcom-canonical/scripts/docker-build-kernel.sh ./resolute-qcom-devel arm64
```

Cross-compilation (e.g. building an arm64 image on an amd64 host) is
supported the same way — just pass `arm64` as `ARCH` while running on an
amd64 host, for both `build-docker-image.sh` and `docker-build-kernel.sh`.

> **Note:** `<ARCH>` in the image tag is the *target* architecture you're
> compiling for, not the image's own native architecture. `FROM
> ubuntu:resolute` always resolves to the multi-arch manifest for the build
> host, so a `resolute-target-arm64` image built on an amd64 host is still a
> native amd64 image — just one with an arm64 cross-toolchain installed
> inside it. Building on an arm64 host would instead be a native arm64
> image with the cross-toolchain layer skipped.

> **Note:** `build-docker-image.sh` builds `FROM` the official
> `docker.io/library/ubuntu:resolute` image when available, falling back to
> `public.ecr.aws/ubuntu/ubuntu:resolute` for whichever registry hasn't
> published that tag. Both are genuine multi-arch manifest lists, so this
> fallback doesn't affect which architecture the resulting image runs as on
> your build host.

---

## Create FIT dtb.bin

After kernel build completes, create the FIT dtb.bin image:

```bash
cd qcom-dtb-metadata

# Build dtb.bin from kernel modules deb
sudo ./build-dtb-image.sh --soc hamoa purwa qcs6490 qcs8275 qcs9075 --kernel-deb {kernel-deb-path}/linux-modules-7.0.0-1006-qcom_7.0.0-1006.8_arm64.deb --out dtb.bin --prune
```

Output: `dtb.bin`

---

## Update Kernel and DTB

### 1. Install Kernel on Target Machine

Example for kernel 7.0.0-1006-qcom:

```bash
# Required
sudo dpkg -i linux-modules-7.0.0-1006-qcom_7.0.0-1006.8_arm64.deb
sudo dpkg -i linux-image-7.0.0-1006-qcom_7.0.0-1006.8_arm64.deb

# Optional: kernel headers (for out-of-tree module development)
# linux-headers-*-qcom depends on the arch-independent linux-qcom-headers-*
# package, so install that first.
sudo dpkg -i linux-qcom-headers-7.0.0-1006_7.0.0-1006.8_all.deb
sudo dpkg -i linux-headers-7.0.0-1006-qcom_7.0.0-1006.8_arm64.deb
```

### 2. Flash dtb.bin

First, ensure the `qdl` tool is installed:

```bash
# Install qdl (Qualcomm Download tool)
sudo apt-get install -y qdl
```

Then flash the dtb.bin:

```bash
qdl --storage spinor xbl_s_devprg_ns.melf write dtb_a dtb.bin
```

---

## License

SPDX-License-Identifier: BSD-3-Clause

See individual script headers for details.
Loading
Loading