From e1dfe34c004e0fac07f8e76d86ac0fbd39a21341 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 11 Dec 2025 10:17:43 -0800 Subject: [PATCH 1/5] drivers: hv: mshv_vtl: 0 for MSHV_CAP_LOWER_VTL_TIMER_VIRT if unsupported Returning -EOPNOTSUPP is a fatal error. It means that The driver doesn't know the feature. Not that the feature is not supported due to the runtime platform reason. Return 0 for MSHV_CAP_LOWER_VTL_TIMER_VIRT on non-TDX platform, which is safer. Fixes: 3528fd7a1743 ("drivers: hv: mshv_vtl: Advertise TDX timer service extension") Signed-off-by: Isaku Yamahata --- drivers/hv/mshv_vtl_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c index 2b79b77fa9ef..92c5d1c37fdd 100644 --- a/drivers/hv/mshv_vtl_main.c +++ b/drivers/hv/mshv_vtl_main.c @@ -332,7 +332,7 @@ static long __mshv_vtl_ioctl_check_extension(u32 arg) case MSHV_CAP_LOWER_VTL_TIMER_VIRT: if (hv_isolation_type_tdx()) return mshv_tdx_vtl_ioctl_check_extension(arg); - break; + return 0; } return -EOPNOTSUPP; From eaebbe162d4867dedab3fa10251b94f2caf27332 Mon Sep 17 00:00:00 2001 From: Naman Jain Date: Thu, 5 Feb 2026 06:44:42 +0000 Subject: [PATCH 2/5] Microsoft: Add Nix infrastructure for reproducible builds Add NixOS flake configuration and helper scripts for reproducible kernel builds. Files added: - flake.nix: Nix environment with pinned toolchain (GCC 13.2.0, binutils, etc.) - flake.lock: Locked package versions for reproducibility - Microsoft/nix-setup.sh: One-time Nix installation helper - Microsoft/nix-clean.sh: Build artifact cleanup - .gitignore: Add Nix-related entries This establishes the foundation for bit-reproducible kernel builds across different machines by providing a hermetic build environment with pinned dependencies. Signed-off-by: Naman Jain --- Microsoft/nix-clean.sh | 20 ++++ Microsoft/nix-setup.sh | 155 +++++++++++++++++++++++++++++++ flake.lock | 61 ++++++++++++ flake.nix | 204 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 440 insertions(+) create mode 100755 Microsoft/nix-clean.sh create mode 100755 Microsoft/nix-setup.sh create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/Microsoft/nix-clean.sh b/Microsoft/nix-clean.sh new file mode 100755 index 000000000000..f606eaeb256f --- /dev/null +++ b/Microsoft/nix-clean.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# +# Clean build artifacts + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +echo "Cleaning build artifacts..." + +# Remove build directory +rm -rf "${KERNEL_ROOT}/build" + +# Clean in-tree builds +cd "${KERNEL_ROOT}" +make mrproper 2>/dev/null || true + +echo "Clean completed!" diff --git a/Microsoft/nix-setup.sh b/Microsoft/nix-setup.sh new file mode 100755 index 000000000000..c36af87a4d22 --- /dev/null +++ b/Microsoft/nix-setup.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# +# Quick setup script for reproducible builds with NixOS + +set -euo pipefail + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +echo "===============================================" +echo "OHCL Kernel - Reproducible Build Setup" +echo "===============================================" +echo "" + +# Helper function to source nix and update PATH +source_nix_profile() { + if [ -f ~/.nix-profile/etc/profile.d/nix.sh ]; then + . ~/.nix-profile/etc/profile.d/nix.sh + export PATH="$HOME/.nix-profile/bin:$PATH" + return 0 + elif [ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then + . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh + export PATH="/nix/var/nix/profiles/default/bin:$PATH" + return 0 + fi + return 1 +} + +# Check if nix is installed +if ! command -v nix &> /dev/null; then + # Try to source nix profile first in case it's installed but not in PATH + if source_nix_profile; then + echo ">>> Nix profile sourced from existing installation" + fi +fi + +# Check again after sourcing +if ! command -v nix &> /dev/null; then + # Check if /nix directory exists (Nix is installed but profile not sourced) + if [ -d /nix ]; then + echo "⚠️ Nix is installed but not in PATH" + echo "" + echo "Please restart your shell or run:" + echo " . ~/.nix-profile/etc/profile.d/nix.sh" + echo "" + echo "Then run this script again: $0" + exit 0 + fi + + echo "⚠️ Nix is not installed!" + echo "" + echo "Installing Nix (single-user installation)..." + echo "This will download and install Nix package manager." + echo "" + + # Create nixbld group and users for sandboxed builds (required for Nix sandbox) + if ! getent group nixbld > /dev/null 2>&1; then + echo "Creating nixbld group and users for sandbox..." + groupadd -r nixbld || sudo groupadd -r nixbld + + # Create 10 build users (Nix uses these for parallel isolated builds) + for i in $(seq 1 10); do + useradd -r -g nixbld -G nixbld \ + -d /var/empty -s /sbin/nologin \ + -c "Nix build user $i" \ + "nixbld$i" 2>/dev/null || \ + sudo useradd -r -g nixbld -G nixbld \ + -d /var/empty -s /sbin/nologin \ + -c "Nix build user $i" \ + "nixbld$i" 2>/dev/null || true + done + echo "✓ Created nixbld group and 10 build users" + fi + + # Install Nix + echo "install nix" + if curl -L https://nixos.org/nix/install | sh -s -- --no-daemon; then + echo "" + echo "✓ Nix installed successfully!" + echo "" + # Source nix profile immediately for current session + if source_nix_profile; then + echo "✓ Nix environment loaded" + else + echo "⚠️ Could not source Nix profile" + fi + # Continue with setup instead of exiting + else + echo "" + echo "❌ Nix installation failed!" + echo "" + echo "You can try manually installing with:" + echo " curl -L https://nixos.org/nix/install | sh" + echo "" + echo "Or for multi-user installation:" + echo " curl -L https://nixos.org/nix/install | sh -s -- --daemon" + echo "" + exit 1 + fi +fi + +echo "✓ Nix is installed" + +# Check if flakes are enabled +echo "Enabling flakes..." +mkdir -p ~/.config/nix +if ! grep -q "experimental-features.*flakes" ~/.config/nix/nix.conf 2>/dev/null; then + echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf + echo "✓ Flakes enabled in ~/.config/nix/nix.conf" +else + echo "✓ Flakes already enabled in ~/.config/nix/nix.conf" +fi + +# Verify flakes work +if nix --extra-experimental-features "nix-command flakes" flake --version &> /dev/null 2>&1; then + echo "✓ Nix flakes are working" +else + echo "⚠ Could not verify flakes, but config is set" +fi + +# Initialize flake.lock if it doesn't exist (must be in kernel root where flake.nix is) +if [ -f "${KERNEL_ROOT}/flake.nix" ]; then + if [ ! -f "${KERNEL_ROOT}/flake.lock" ]; then + echo "" + echo "Initializing flake.lock..." + cd "${KERNEL_ROOT}" + nix --extra-experimental-features "nix-command flakes" flake lock + echo "✓ flake.lock created" + else + echo "✓ flake.lock already exists" + fi +else + echo "⚠ No flake.nix found in ${KERNEL_ROOT}, skipping flake.lock initialization" +fi + +# Source nix profile for current session (ensure it's available) +source_nix_profile && echo "✓ Nix environment ready" + +echo "" +echo "===============================================" +echo "Setup Complete!" +echo "===============================================" +echo "" +echo "You can now build the kernel with:" +echo "" +echo " ./Microsoft/nix-build.sh x64" +echo " ./Microsoft/nix-build.sh arm64" +echo "" +echo "The script will automatically enter the Nix environment." +echo "" +echo "For more information, run:" +echo " ./Microsoft/nix-build.sh --help" +echo "" diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000000..2468070f754b --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000000..171e42a68462 --- /dev/null +++ b/flake.nix @@ -0,0 +1,204 @@ +{ + description = "OHCL Linux Kernel - Reproducible Build Environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = false; + }; + + # Kernel build dependencies + kernelBuildInputs = with pkgs; [ + # Core build tools + gcc + gnumake + binutils + bison + flex + bc + perl + python3 + + # Shell utilities needed for build scripts + getopt + coreutils + findutils + gnugrep + gnused + gawk + bash + rsync + hostname + which + + # Cross-compilation toolchains + # ARM64 cross-compiler (for x86_64 → arm64) + pkgsCross.aarch64-multiplatform.stdenv.cc + pkgsCross.aarch64-multiplatform.buildPackages.binutils + # x86_64 cross-compiler (for arm64 → x86_64) + pkgsCross.gnu64.stdenv.cc + pkgsCross.gnu64.buildPackages.binutils + + # Compression tools + gzip + bzip2 + xz + zstd + + # Additional tools + elfutils + openssl + pkg-config + ncurses + + # For device tree compilation + dtc + + # For reproducibility checking + diffoscope + + # Version control + git + ]; + + # Reproducible build environment variables + reproducibleEnv = { + # Set consistent locale + LANG = "C.UTF-8"; + LC_ALL = "C.UTF-8"; + + # Kernel build flags for reproducibility + KBUILD_BUILD_USER = "builder"; + KBUILD_BUILD_HOST = "nixos"; + + # Disable hostname and username + KBUILD_BUILD_VERSION = "1"; + + # Set consistent timezone + TZ = "UTC"; + }; + + in + { + # Development shell with all dependencies + devShells.default = pkgs.mkShell { + buildInputs = kernelBuildInputs; + + shellHook = '' + echo "OHCL Linux Kernel - Reproducible Build Environment" + echo "==================================================" + echo "" + echo "Available commands:" + echo " ./Microsoft/nix-build.sh - Build kernel reproducibly" + echo " ./Microsoft/nix-check-repro.sh - Verify reproducibility" + echo " ./Microsoft/nix-clean.sh - Clean build artifacts" + echo "" + echo "Environment configured for reproducible builds:" + echo " KBUILD_BUILD_USER=${reproducibleEnv.KBUILD_BUILD_USER}" + echo " KBUILD_BUILD_HOST=${reproducibleEnv.KBUILD_BUILD_HOST}" + echo " (SOURCE_DATE_EPOCH will be set from git commit timestamp)" + echo "" + + # Export reproducible environment variables + # SOURCE_DATE_EPOCH is set by nix-build.sh before entering this shell + export LANG="${reproducibleEnv.LANG}" + export LC_ALL="${reproducibleEnv.LC_ALL}" + export KBUILD_BUILD_TIMESTAMP="@$SOURCE_DATE_EPOCH" + export KBUILD_BUILD_USER="${reproducibleEnv.KBUILD_BUILD_USER}" + export KBUILD_BUILD_HOST="${reproducibleEnv.KBUILD_BUILD_HOST}" + export KBUILD_BUILD_VERSION="${reproducibleEnv.KBUILD_BUILD_VERSION}" + export TZ="${reproducibleEnv.TZ}" + ''; + }; + + # Packages for building the kernel + packages = { + # Build the kernel + kernel = pkgs.stdenv.mkDerivation { + pname = "ohcl-linux-kernel"; + version = "6.x"; + + src = ./.; + + nativeBuildInputs = kernelBuildInputs; + + # Apply reproducible build environment + inherit (reproducibleEnv) + SOURCE_DATE_EPOCH + LANG + LC_ALL + KBUILD_BUILD_TIMESTAMP + KBUILD_BUILD_USER + KBUILD_BUILD_HOST + KBUILD_BUILD_VERSION + TZ; + + configurePhase = '' + runHook preConfigure + + # Use default config or provided config + if [ -f .config ]; then + echo "Using existing .config" + else + make defconfig + fi + + runHook postConfigure + ''; + + buildPhase = '' + runHook preBuild + + # Build with reproducible flags + make -j$NIX_BUILD_CORES \ + KBUILD_BUILD_TIMESTAMP="$KBUILD_BUILD_TIMESTAMP" \ + KBUILD_BUILD_USER="$KBUILD_BUILD_USER" \ + KBUILD_BUILD_HOST="$KBUILD_BUILD_HOST" \ + KBUILD_BUILD_VERSION="$KBUILD_BUILD_VERSION" + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/boot + cp arch/*/boot/Image $out/boot/ 2>/dev/null || true + cp arch/*/boot/bzImage $out/boot/ 2>/dev/null || true + cp arch/*/boot/zImage $out/boot/ 2>/dev/null || true + cp System.map $out/boot/ + cp .config $out/boot/config + + mkdir -p $out/lib/modules + make INSTALL_MOD_PATH=$out modules_install + + runHook postInstall + ''; + + enableParallelBuilding = true; + }; + + default = self.packages.${system}.kernel; + }; + + # Apps for easy execution + apps = { + build = { + type = "app"; + program = "${pkgs.writeShellScript "build-kernel" '' + set -e + cd "$(dirname "$0")/.." + exec ${pkgs.bash}/bin/bash ./Microsoft/nix-build.sh "$@" + ''}"; + }; + }; + } + ); +} From d8d2c8f10488d2648ae9c341a7a7776655a20560 Mon Sep 17 00:00:00 2001 From: Naman Jain Date: Thu, 5 Feb 2026 06:44:51 +0000 Subject: [PATCH 3/5] Microsoft: Add Nix build script with reproducible environment Add nix-build.sh that orchestrates reproducible kernel builds using the Nix environment established in the previous commit. Features: - Pure Nix environment with --ignore-environment flag - Fixed build paths for reproducible absolute path embeddings - Reproducible environment variables: - SOURCE_DATE_EPOCH= timestamp of top git commit embedded - KBUILD_BUILD_USER=builder - KBUILD_BUILD_HOST=nixos - KBUILD_BUILD_VERSION=1 - Copies source to fixed path to ensure identical embedded paths - Invokes build-hcl-kernel.sh within the controlled environment - Copies artifacts back to original location - Cleanup on exit Usage: ./Microsoft/nix-build.sh x64 # Build x64 kernel ./Microsoft/nix-build.sh arm64 # Build arm64 kernel ./Microsoft/nix-build.sh x64 cvm # Build x64 cvm kernel ./Microsoft/nix-build.sh arm64 cvm # Build arm64 cvm kernel Signed-off-by: Naman Jain --- Microsoft/nix-build.sh | 234 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100755 Microsoft/nix-build.sh diff --git a/Microsoft/nix-build.sh b/Microsoft/nix-build.sh new file mode 100755 index 000000000000..70f9ff150d1d --- /dev/null +++ b/Microsoft/nix-build.sh @@ -0,0 +1,234 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# +# Reproducible kernel build script for NixOS +# This script ensures consistent build environment for reproducible builds + +set -euo pipefail + +# Auto-detect and enter Nix environment if not already in one +if [ -z "${IN_NIX_SHELL:-}" ]; then + # Check if nix is available + if ! command -v nix &> /dev/null; then + # Try to source nix profile + if [ -f ~/.nix-profile/etc/profile.d/nix.sh ]; then + . ~/.nix-profile/etc/profile.d/nix.sh + else + echo "Error: Nix is not installed or not in PATH" + echo "Please run: ./Microsoft/nix-setup.sh" + exit 1 + fi + fi + + # Re-execute this script inside nix develop with experimental features enabled + # Use --ignore-environment (-i) to create a pure shell that excludes system packages + # Keep essential variables: HOME (for temp files), USER (for build metadata), TERM (for output) + # Keep SOURCE_DATE_EPOCH for reproducible builds + exec nix --extra-experimental-features "nix-command flakes" develop \ + --ignore-environment \ + --keep-env-var HOME \ + --keep-env-var USER \ + --keep-env-var TERM \ + --keep-env-var SOURCE_DATE_EPOCH \ + --command "$0" "$@" +fi + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KERNEL_ROOT_ORIGINAL="$(cd "${SCRIPT_DIR}/.." && pwd)" + +# Fixed build path for reproducibility - ensures identical paths across machines +FIXED_BUILD_PATH="${FIXED_BUILD_PATH:-/tmp/ohcl-kernel-build}" +KERNEL_ROOT="${FIXED_BUILD_PATH}/src" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${GREEN}[INFO]${NC} $*" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $*" +} + +# Parse architecture and build type from command line +ARCH_TYPE="${1:-x64}" # Default to x64 +BUILD_TYPE="${2:-}" # Optional: cvm + +# Validate architecture +case "${ARCH_TYPE}" in + x64|x86_64|amd64) + ARCH_TYPE="x64" + KERNEL_ARCH="x86_64" + ;; + arm64|aarch64) + ARCH_TYPE="arm64" + KERNEL_ARCH="arm64" + CROSS_COMPILE="aarch64-linux-gnu-" + ;; + build|clean|help|--help|-h) + # These are commands, not architectures - will be handled later + ;; + *) + log_error "Unknown architecture: ${ARCH_TYPE}" + log_error "Supported: x64, arm64" + exit 1 + ;; +esac + +# Build configuration +BUILD_OUTPUT="${BUILD_OUTPUT:-${KERNEL_ROOT}/build}" +MAKE_JOBS="${MAKE_JOBS:-$(nproc)}" + +# Reproducible build environment +# Always use timestamp of the top commit for SOURCE_DATE_EPOCH +# Override any value set by Nix itself +export SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)" +export LANG="C.UTF-8" +export LC_ALL="C.UTF-8" +export TZ="UTC" + +# Flag to indicate reproducible build mode (used by build-hcl-kernel.sh) +export REPRODUCIBLE_BUILD=1 + +# Kernel-specific reproducible flags +export KBUILD_BUILD_TIMESTAMP="@${SOURCE_DATE_EPOCH}" +export KBUILD_BUILD_USER="${KBUILD_BUILD_USER:-builder}" +export KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST:-nixos}" +export KBUILD_BUILD_VERSION="1" + +# Cleanup function to remove temporary build directory +cleanup_build_path() { + if [ -n "${FIXED_BUILD_PATH}" ] && [ -d "${FIXED_BUILD_PATH}" ]; then + log_info "Cleaning up temporary build directory: ${FIXED_BUILD_PATH}" + rm -rf "${FIXED_BUILD_PATH}" + fi +} + +# Set trap to cleanup on exit (success or failure) +trap cleanup_build_path EXIT + +main() { + log_info "Starting reproducible kernel build..." + log_info "Original source: ${KERNEL_ROOT_ORIGINAL}" + log_info "Fixed build path: ${KERNEL_ROOT}" + log_info "Reproducible environment:" + log_info " SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}" + log_info " KBUILD_BUILD_USER=${KBUILD_BUILD_USER}" + log_info " KBUILD_BUILD_HOST=${KBUILD_BUILD_HOST}" + + # Copy source to fixed path for reproducibility + # This ensures the same paths are embedded in binaries regardless of where source is located + log_info "Copying source to fixed build path..." + rm -rf "${FIXED_BUILD_PATH}" + mkdir -p "${FIXED_BUILD_PATH}" + # Use anchored excludes (/) to avoid matching subdirectories like tools/build + rsync -a --exclude='/.git' --exclude='/build' --exclude='/out' \ + "${KERNEL_ROOT_ORIGINAL}/" "${KERNEL_ROOT}/" + log_info "Source copied to ${KERNEL_ROOT}" + + # Set environment for reproducibility + export KBUILD_BUILD_TIMESTAMP="${KBUILD_BUILD_TIMESTAMP}" + export KBUILD_BUILD_USER="${KBUILD_BUILD_USER}" + export KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST}" + export KBUILD_BUILD_VERSION="${KBUILD_BUILD_VERSION}" + + # Unset Nix-specific compiler flags that might interfere with kernel build + unset NIX_CFLAGS_COMPILE + unset NIX_CFLAGS_COMPILE_FOR_TARGET + unset NIX_LDFLAGS + unset NIX_LDFLAGS_FOR_TARGET + + cd "${KERNEL_ROOT}" + + # Handle CVM build if requested + if [ "${BUILD_TYPE}" = "cvm" ]; then + log_info "Building with CVM config..." + "${KERNEL_ROOT}/Microsoft/merge-cvm-config.sh" + fi + + # Invoke the existing build-hcl-kernel.sh script + log_info "Invoking build-hcl-kernel.sh..." + "${KERNEL_ROOT}/Microsoft/build-hcl-kernel.sh" "${ARCH_TYPE}" + + # Copy build artifacts back to original location + log_info "Copying build artifacts back to original location..." + mkdir -p "${KERNEL_ROOT_ORIGINAL}/out" + rsync -a "${KERNEL_ROOT}/out/" "${KERNEL_ROOT_ORIGINAL}/out/" + + # Copy build directory back to original location + log_info "Copying build directory back to original location..." + mkdir -p "${KERNEL_ROOT_ORIGINAL}/../build" + rsync -a "${FIXED_BUILD_PATH}/build/" "${KERNEL_ROOT_ORIGINAL}/../build/" + + log_info "Build completed successfully!" + log_info "Build artifacts are in: ${KERNEL_ROOT_ORIGINAL}/out" + + # Print sha256sum of vmlinux for reproducibility verification + # Check the STRIPPED vmlinux (final post-processed output) + # build-hcl-kernel.sh creates stripped vmlinux at $BUILD_DIR/vmlinux + local VMLINUX_PATH="${KERNEL_ROOT_ORIGINAL}/../build/vmlinux" + if [ -f "${VMLINUX_PATH}" ]; then + echo "" + log_info "Reproducibility verification:" + echo " vmlinux sha256sum: $(sha256sum "${VMLINUX_PATH}" | cut -d' ' -f1)" + fi +} + +# Handle command line arguments +# Determine command (3rd arg for arch builds, or 1st arg if no arch specified) +COMMAND="${3:-build}" +if [ "${ARCH_TYPE}" = "build" ] || [ "${ARCH_TYPE}" = "clean" ] || [ "${ARCH_TYPE}" = "help" ] || [ "${ARCH_TYPE}" = "--help" ] || [ "${ARCH_TYPE}" = "-h" ]; then + COMMAND="${ARCH_TYPE}" + ARCH_TYPE="x64" # Reset to default +fi +if [ "${BUILD_TYPE}" = "build" ] || [ "${BUILD_TYPE}" = "clean" ] || [ "${BUILD_TYPE}" = "help" ]; then + COMMAND="${BUILD_TYPE}" + BUILD_TYPE="" +fi + +case "${COMMAND}" in + build) + main + ;; + clean) + log_info "Cleaning build directory: ${BUILD_OUTPUT}" + rm -rf "${BUILD_OUTPUT}" + log_info "Clean completed" + ;; + help|--help|-h) + echo "Usage: $0 [ARCH] [BUILD_TYPE] [COMMAND]" + echo "" + echo "Arguments:" + echo " ARCH - Architecture: x64, arm64 (default: x64)" + echo " BUILD_TYPE - Build type: cvm (optional)" + echo " COMMAND - Command: build, clean, help (default: build)" + echo "" + echo "Examples:" + echo " $0 x64 - Build for x64" + echo " $0 arm64 - Build for arm64" + echo " $0 x64 cvm - Build for x64 with CVM config" + echo " $0 arm64 cvm - Build for arm64 with CVM config" + echo "" + echo "Commands:" + echo " build - Build the kernel (default)" + echo " clean - Clean build artifacts" + echo " help - Show this help message" + echo "" + echo "Environment variables:" + echo " BUILD_OUTPUT - Build output directory (default: ./build)" + echo " MAKE_JOBS - Number of parallel jobs (default: nproc)" + echo " CONFIG_FILE_OVERRIDE - Override config file (default: auto-detect Microsoft config)" + echo " SOURCE_DATE_EPOCH - Timestamp for reproducible builds" + echo " KBUILD_BUILD_USER - Username for kernel build" + echo " KBUILD_BUILD_HOST - Hostname for kernel build" + ;; + *) + log_error "Unknown command: $1" + log_info "Run '$0 help' for usage information" + exit 1 + ;; +esac From 9fa824142fecf0898d324cbf861c6adae9bcaf93 Mon Sep 17 00:00:00 2001 From: Naman Jain Date: Thu, 5 Feb 2026 06:45:01 +0000 Subject: [PATCH 4/5] Microsoft: Update build-hcl-kernel.sh for reproducible builds Enhance build-hcl-kernel.sh to support reproducible builds when invoked from nix-build.sh or other reproducible environments. Changes: - Detect host architecture to avoid unnecessary cross-compilation - Set CC explicitly to gcc/cross-compiler for Nix toolchain - Add LOCALVERSION= to prevent '+' suffix in version string - Add KCFLAGS=-fdebug-prefix-map to normalize debug paths - Add SHA256 checksum output of vmlinux for verification - Remove KBUILD_BUILD_ID=none (not needed) When REPRODUCIBLE_BUILD=1: - Uses Nix's gcc instead of system gcc for native builds - Only uses cross-compiler when actually cross-compiling - Ensures consistent compiler identification in kernel binary Otherwise, let users continue using this script for dev work as before. Signed-off-by: Naman Jain --- Microsoft/build-hcl-kernel.sh | 87 ++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/Microsoft/build-hcl-kernel.sh b/Microsoft/build-hcl-kernel.sh index 0906371fb82c..5d81b55fe238 100755 --- a/Microsoft/build-hcl-kernel.sh +++ b/Microsoft/build-hcl-kernel.sh @@ -70,12 +70,67 @@ if test -z "$arch"; then arch=("x64") fi +# Detect host architecture +HOST_ARCH="$(uname -m)" + objcopy=("objcopy") -makeargs=("ARCH=x86_64") +if [ -n "$REPRODUCIBLE_BUILD" ]; then + # For reproducible builds, explicitly set CC to use Nix's gcc + makeargs=("ARCH=x86_64" "CC=gcc") +else + makeargs=("ARCH=x86_64") +fi targets=("vmlinux modules") + +# Handle x86_64 target architecture +if [ "$arch" = "x64" ]; then + # Check if we're cross-compiling from arm64 to x86_64 + if [ "$HOST_ARCH" = "aarch64" ]; then + # Cross-compiling from arm64 with Nix toolchain + if [ -n "$REPRODUCIBLE_BUILD" ]; then + cross_prefix="x86_64-unknown-linux-gnu-" + else + cross_prefix="x86_64-linux-gnu-" + fi + objcopy=("${cross_prefix}objcopy") + if [ -n "$REPRODUCIBLE_BUILD" ]; then + makeargs=("ARCH=x86_64" "CROSS_COMPILE=${cross_prefix}" "CC=${cross_prefix}gcc") + else + makeargs=("ARCH=x86_64" "CROSS_COMPILE=${cross_prefix}") + fi + fi +fi + +# Handle arm64 target architecture if [ "$arch" = "arm64" ]; then - objcopy=("aarch64-linux-gnu-objcopy") - makeargs=("ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-") + # Only use cross-compiler when cross-compiling (host != target) + if [ "$HOST_ARCH" = "aarch64" ]; then + # Native arm64 build - no cross-compile prefix needed + cross_prefix="" + elif [ -n "$REPRODUCIBLE_BUILD" ]; then + # Cross-compiling from x86_64 with Nix toolchain + cross_prefix="aarch64-unknown-linux-gnu-" + else + # Cross-compiling from x86_64 with system toolchain + cross_prefix="aarch64-linux-gnu-" + fi + + if [ -n "$cross_prefix" ]; then + objcopy=("${cross_prefix}objcopy") + # For reproducible builds, explicitly set CC to use the Nix cross-compiler + if [ -n "$REPRODUCIBLE_BUILD" ]; then + makeargs=("ARCH=arm64" "CROSS_COMPILE=${cross_prefix}" "CC=${cross_prefix}gcc") + else + makeargs=("ARCH=arm64" "CROSS_COMPILE=${cross_prefix}") + fi + else + # For native builds, explicitly set CC to ensure we use Nix's gcc in reproducible mode + if [ -n "$REPRODUCIBLE_BUILD" ]; then + makeargs=("ARCH=arm64" "CC=gcc") + else + makeargs=("ARCH=arm64") + fi + fi targets=("vmlinux Image modules") fi @@ -84,15 +139,31 @@ set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" SRC_DIR=`realpath ${SCRIPT_DIR}/..` +# For reproducible builds, add flags to normalize debug paths +if [ -n "$REPRODUCIBLE_BUILD" ]; then + makeargs+=("KCFLAGS=-fdebug-prefix-map=$SRC_DIR=.") + # Prevent + suffix from being added to version string + makeargs+=("LOCALVERSION=") +fi + build_kernel() { + echo ">>> Current directory: $(pwd)" if [ -n "$clean" ]; then make mrproper fi export KCONFIG_CONFIG=$LINUX_SRC/Microsoft/hcl-$arch.config - make $makeargs -j `nproc` olddefconfig $targets + + make "${makeargs[@]}" -j `nproc` olddefconfig $targets cp $LINUX_SRC/Microsoft/hcl-$arch.config $OUT_DIR $objcopy --only-keep-debug --compress-debug-sections $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux.dbg - $objcopy --strip-all --add-gnu-debuglink=$BUILD_DIR/vmlinux.dbg $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux + # For reproducible builds, skip --add-gnu-debuglink as it embeds a CRC of the debug file + # which can vary between builds. The debuglink is only used for debugging and is not + # essential for the kernel to function. + if [ -n "$REPRODUCIBLE_BUILD" ]; then + $objcopy --strip-all $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux + else + $objcopy --strip-all --add-gnu-debuglink=$BUILD_DIR/vmlinux.dbg $KBUILD_OUTPUT/vmlinux $BUILD_DIR/vmlinux + fi find $BUILD_DIR -name '*.ko' | while read -r mod; do relative_path="${mod#$BUILD_DIR/linux}" @@ -100,7 +171,11 @@ build_kernel() { mkdir -p "$dest_dir" outmod="$dest_dir/$(basename $mod)" $objcopy --only-keep-debug --compress-debug-sections "$mod" "$outmod.dbg" - $objcopy --strip-unneeded --add-gnu-debuglink "$outmod.dbg" "$mod" "$outmod" + if [ -n "$REPRODUCIBLE_BUILD" ]; then + $objcopy --strip-unneeded "$mod" "$outmod" + else + $objcopy --strip-unneeded --add-gnu-debuglink "$outmod.dbg" "$mod" "$outmod" + fi done cp $BUILD_DIR/vmlinux $OUT_DIR/build/native/bin/$arch From 6d4613e7108b44630be8b0c9e44e33ee614d9a1c Mon Sep 17 00:00:00 2001 From: Naman Jain Date: Thu, 5 Feb 2026 06:45:13 +0000 Subject: [PATCH 5/5] Microsoft: Add CI pipeline build script Add build-hcl-kernel-pipeline.sh for Azure DevOps CI integration with reproducible build support. Features: - Supports amd64 and arm64 architectures - CVM config merge support via merge_cvm_config() - Optional reproducible build mode (--reproducible flag) - Generates kernel, headers, modules, and debug symbols - Progress indicators for build stages [1/5] through [5/5] - SHA256 checksum output for reproducibility verification Key differences from build-hcl-kernel.sh: - Standalone script that doesn't depend on nix-build.sh wrapper - Implements complete build workflow in one script - Uses KBUILD_OUTPUT=$BUILD_DIR/linux subdirectory structure - Handles CVM config merging inline - Moves artifacts from /linux subdirectory to BUILD_DIR root for pipeline - When --reproducible: sets up Nix environment and reproducible variables Build directory structure: - $BUILD_DIR/linux/ # KBUILD_OUTPUT during build - $BUILD_DIR/vmlinux # Final artifacts at root - $BUILD_DIR/linux-headers/ - $BUILD_DIR/debug_symbols/ Usage: ./build-hcl-kernel-pipeline.sh -s -b -c -a ./build-hcl-kernel-pipeline.sh ... --reproducible ./build-hcl-kernel-pipeline.sh ... --cvm-config Signed-off-by: Naman Jain --- Microsoft/build-hcl-kernel-pipeline.sh | 631 +++++++++++++++++++++++++ 1 file changed, 631 insertions(+) create mode 100755 Microsoft/build-hcl-kernel-pipeline.sh diff --git a/Microsoft/build-hcl-kernel-pipeline.sh b/Microsoft/build-hcl-kernel-pipeline.sh new file mode 100755 index 000000000000..5eb75b4c50c5 --- /dev/null +++ b/Microsoft/build-hcl-kernel-pipeline.sh @@ -0,0 +1,631 @@ +#!/bin/bash +# +# Build script for HCL kernel in Azure DevOps pipeline +# This script mirrors the structure of Microsoft/build-hcl-kernel.sh +# but implements the same functionality as the pipeline's inline build steps. +# +# This script is called ONLY for OHCL product builds. +# + +set -eo pipefail + +usage() { + cat << EOF +Usage: $0 [OPTIONS] + +Build HCL kernel for pipeline with specified configuration. + +OPTIONS: + -s, --source-dir DIR Path to kernel source directory (required) + -b, --build-dir DIR Path to build output directory (required) + -c, --config FILE Path to kernel config file relative to source dir (required) + -a, --arch ARCH Target architecture: amd64 or arm64 (required) + -k, --kernel-type TYPE Kernel type: none or cvm (default: none) + --compiler CC Compiler to use (default: gcc) + --scripts-dir DIR Path to msft-lkt scripts directory (required for cvm) + --reproducible Enable reproducible build mode (uses Nix environment) + -h, --help Show this help message + +EXAMPLE: + $0 -s /path/to/kernel-source -b /path/to/build -c Microsoft/hcl-x64.config -a amd64 + $0 -s /path/to/kernel-source -b /path/to/build -c Microsoft/hcl-arm64.config -a arm64 -k cvm + $0 -s /path/to/kernel-source -b /path/to/build -c Microsoft/hcl-x64.config -a amd64 --reproducible + +EOF + exit 1 +} + +# Default values +KERNEL_TYPE="none" +COMPILER="gcc" +SCRIPTS_DIR="" +REPRODUCIBLE_BUILD="" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case "$1" in + -s|--source-dir) + SOURCE_DIR="$2" + shift 2 + ;; + -b|--build-dir) + BUILD_DIR="$2" + shift 2 + ;; + -c|--config) + CONFIG="$2" + shift 2 + ;; + -a|--arch) + ARCH="$2" + shift 2 + ;; + -k|--kernel-type) + KERNEL_TYPE="$2" + shift 2 + ;; + --compiler) + COMPILER="$2" + shift 2 + ;; + --scripts-dir) + SCRIPTS_DIR="$2" + shift 2 + ;; + --reproducible) + REPRODUCIBLE_BUILD="1" + shift + ;; + -h|--help) + usage + ;; + *) + echo "Unknown option: $1" >&2 + usage + ;; + esac +done + +# Validate required arguments +if [[ -z "$SOURCE_DIR" ]] || [[ -z "$BUILD_DIR" ]] || [[ -z "$CONFIG" ]] || [[ -z "$ARCH" ]]; then + echo "Error: Missing required arguments" >&2 + usage +fi + +# Validate scripts-dir is provided for CVM builds +if [[ "$KERNEL_TYPE" == "cvm" ]] && [[ -z "$SCRIPTS_DIR" ]]; then + echo "Error: --scripts-dir is required for CVM kernel builds" >&2 + usage +fi + +# Validate architecture +if [[ "$ARCH" != "amd64" ]] && [[ "$ARCH" != "arm64" ]]; then + echo "Error: Invalid architecture '$ARCH'. Must be 'amd64' or 'arm64'" >&2 + exit 1 +fi + +# +# Reproducible build setup - enter Nix environment if requested +# +setup_reproducible_build() { + if [[ -n "$REPRODUCIBLE_BUILD" ]] && [[ -z "${IN_NIX_SHELL:-}" ]]; then + echo ">>> Setting up reproducible build environment..." + + # Run nix-setup.sh to ensure Nix is installed and configured + NIX_SETUP_SCRIPT="$SOURCE_DIR/Microsoft/nix-setup.sh" + if [[ -f "$NIX_SETUP_SCRIPT" ]]; then + chmod +x "$NIX_SETUP_SCRIPT" + "$NIX_SETUP_SCRIPT" + fi + + # Source nix profile if not already available + if ! command -v nix &> /dev/null; then + if [[ -f ~/.nix-profile/etc/profile.d/nix.sh ]]; then + . ~/.nix-profile/etc/profile.d/nix.sh + export PATH="$HOME/.nix-profile/bin:$PATH" + + else + echo "Error: Nix is not installed or not in PATH" >&2 + echo "Please run: ./Microsoft/nix-setup.sh" >&2 + exit 1 + fi + fi + + # Re-execute this script inside nix develop shell + # Use --ignore-environment (-i) to create a pure shell that excludes system packages + # Keep essential variables: HOME (for temp files), USER (for build metadata), TERM (for output) + echo "Entering Nix development shell (pure mode)..." + cd "$SOURCE_DIR" + exec nix --extra-experimental-features "nix-command flakes" develop \ + --ignore-environment \ + --keep-env-var HOME \ + --keep-env-var USER \ + --keep-env-var TERM \ + --command \ + "$0" \ + --source-dir "$SOURCE_DIR" \ + --build-dir "$BUILD_DIR" \ + --config "$CONFIG" \ + --arch "$ARCH" \ + --kernel-type "$KERNEL_TYPE" \ + --compiler "$COMPILER" \ + ${SCRIPTS_DIR:+--scripts-dir "$SCRIPTS_DIR"} \ + --reproducible + fi +} + +# Resolve paths first (needed by setup_reproducible_build) +SOURCE_DIR=$(realpath "$SOURCE_DIR") +BUILD_DIR=$(realpath "$BUILD_DIR") + +# Call reproducible build setup before anything else +setup_reproducible_build + +# For reproducible builds, copy source to a fixed path +# This ensures identical paths in binaries regardless of where source is located +ORIGINAL_SOURCE_DIR="$SOURCE_DIR" +ORIGINAL_BUILD_DIR="$BUILD_DIR" + +setup_fixed_build_path() { + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + FIXED_BUILD_PATH="${FIXED_BUILD_PATH:-/tmp/ohcl-kernel-build}" + FIXED_SOURCE_DIR="${FIXED_BUILD_PATH}/src" + FIXED_BUILD_DIR="${FIXED_BUILD_PATH}/build" + + echo ">>> Setting up fixed build path for reproducibility..." + echo " Original source: $ORIGINAL_SOURCE_DIR" + echo " Fixed source: $FIXED_SOURCE_DIR" + + # Clean and create fixed build path + rm -rf "${FIXED_BUILD_PATH}" + mkdir -p "${FIXED_BUILD_PATH}" + + # Copy source to fixed path (use anchored excludes to avoid matching subdirs like tools/build) + rsync -a --exclude='/.git' --exclude='/build' --exclude='/out' --exclude='/compare' \ + "${ORIGINAL_SOURCE_DIR}/" "${FIXED_SOURCE_DIR}/" + + # Update paths to use fixed locations + SOURCE_DIR="${FIXED_SOURCE_DIR}" + BUILD_DIR="${FIXED_BUILD_DIR}" + + echo " Source copied to fixed path" + fi +} + +# Cleanup function to remove temporary build directory +cleanup_fixed_build_path() { + if [[ -n "$REPRODUCIBLE_BUILD" ]] && [[ -n "${FIXED_BUILD_PATH:-}" ]] && [[ -d "${FIXED_BUILD_PATH:-}" ]]; then + echo ">>> Cleaning up temporary build directory: ${FIXED_BUILD_PATH}" + rm -rf "${FIXED_BUILD_PATH}" + fi +} + +# Copy build artifacts back to original location +copy_artifacts_back() { + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + echo ">>> Copying build artifacts back to original location..." + mkdir -p "${ORIGINAL_BUILD_DIR}" + rsync -a "${FIXED_BUILD_DIR}/" "${ORIGINAL_BUILD_DIR}/" + echo " Artifacts copied to ${ORIGINAL_BUILD_DIR}" + fi +} + +# Set trap to cleanup on exit (success or failure) +if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + trap cleanup_fixed_build_path EXIT +fi + +# Setup fixed build path for reproducible builds +setup_fixed_build_path + +# Detect host architecture +HOST_ARCH="$(uname -m)" + +# Set architecture-specific variables +if [[ "$ARCH" == "amd64" ]]; then + MAKE_ARCH="x86" + KERNEL_ARCH="x86_64" + # Check if we're cross-compiling from arm64 to x86_64 + if [[ "$HOST_ARCH" == "aarch64" ]]; then + # Cross-compiling from arm64 with Nix toolchain + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + CROSS_COMPILE_PREFIX="x86_64-unknown-linux-gnu-" + COMPILER="${CROSS_COMPILE_PREFIX}gcc" + else + # Cross-compiling with system toolchain + CROSS_COMPILE_PREFIX="x86_64-linux-gnu-" + fi + else + # Native x86_64 build + CROSS_COMPILE_PREFIX="" + # For reproducible builds, ensure we use Nix's gcc + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + COMPILER="gcc" + fi + fi +else + MAKE_ARCH="arm64" + KERNEL_ARCH="arm64" + # Only use cross-compiler when cross-compiling (host != target) + # On native arm64 machines, use native compiler (no prefix) + if [[ "$HOST_ARCH" == "aarch64" ]]; then + # Native arm64 build - no cross-compile prefix needed + CROSS_COMPILE_PREFIX="" + # For reproducible builds, ensure we use Nix's gcc + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + COMPILER="gcc" + fi + elif [[ -n "$REPRODUCIBLE_BUILD" ]]; then + # Cross-compiling from x86_64 with Nix toolchain + CROSS_COMPILE_PREFIX="aarch64-unknown-linux-gnu-" + COMPILER="${CROSS_COMPILE_PREFIX}gcc" + else + # Cross-compiling from x86_64 with system toolchain + CROSS_COMPILE_PREFIX="aarch64-linux-gnu-" + fi +fi + +# Define output directories (matching pipeline structure) +LINUX_HEADERS_DIR="$BUILD_DIR/linux-headers" +DEBUG_SYMBOL_DIR="$BUILD_DIR/debug_symbols" +LINUX_DIR="$BUILD_DIR/linux_dir" +LINUX_BOOT_DIR="$LINUX_DIR/boot" + +# Setup reproducible build environment variables +if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + # Always use timestamp of the top commit for SOURCE_DATE_EPOCH + # Override any pre-set value to ensure consistency + export SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)" + export LANG="C.UTF-8" + export LC_ALL="C.UTF-8" + export TZ="UTC" + export KBUILD_BUILD_TIMESTAMP="@${SOURCE_DATE_EPOCH}" + export KBUILD_BUILD_USER="${KBUILD_BUILD_USER:-builder}" + export KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST:-nixos}" + export KBUILD_BUILD_VERSION="1" + + # Unset Nix-specific compiler flags that might interfere with kernel build + unset NIX_CFLAGS_COMPILE + unset NIX_CFLAGS_COMPILE_FOR_TARGET + unset NIX_LDFLAGS + unset NIX_LDFLAGS_FOR_TARGET +fi + +echo "==============================================" +echo "HCL Kernel Pipeline Build Script" +echo "==============================================" +echo "Source directory: $SOURCE_DIR" +echo "Build directory: $BUILD_DIR" +echo "Config file: $CONFIG" +echo "Architecture: $ARCH (make arch: $MAKE_ARCH)" +echo "Kernel type: $KERNEL_TYPE" +echo "Compiler: $COMPILER" +if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + echo "Reproducible: YES" + echo " SOURCE_DATE_EPOCH: $SOURCE_DATE_EPOCH" + echo " KBUILD_BUILD_USER: $KBUILD_BUILD_USER" + echo " KBUILD_BUILD_HOST: $KBUILD_BUILD_HOST" +fi +echo "==============================================" + +# Create output directories +mkdir -p "$BUILD_DIR" +mkdir -p "$LINUX_HEADERS_DIR" +mkdir -p "$DEBUG_SYMBOL_DIR" +mkdir -p "$LINUX_DIR" +mkdir -p "$LINUX_BOOT_DIR" + +cd "$SOURCE_DIR" + +# +# Step 0: CVM Config Merge (only for cvm kernel type) +# +merge_cvm_config() { + echo "" + echo ">>> Merging CVM config for HCL..." + + # Map architecture to config file naming + if [[ "$ARCH" == "amd64" ]]; then + CONFIG_ARCH="x64" + BASE_CONFIG="hcl-x64.config" + FRAGMENT_CONFIG="x64-cvm.config" + else + CONFIG_ARCH="arm64" + BASE_CONFIG="hcl-arm64.config" + FRAGMENT_CONFIG="arm64-cvm.config" + fi + + cd "$SOURCE_DIR/Microsoft" + + # Verify config files exist + if [[ ! -f "$BASE_CONFIG" ]]; then + echo "Error: Base config file $BASE_CONFIG not found!" >&2 + exit 1 + fi + if [[ ! -f "$FRAGMENT_CONFIG" ]]; then + echo "Error: Fragment config file $FRAGMENT_CONFIG not found!" >&2 + exit 1 + fi + + # Copy base config to .config in source directory + cp "$BASE_CONFIG" "$SOURCE_DIR/.config" + + # Merge the fragment configuration + cd "$SOURCE_DIR" + chmod +x "$SCRIPTS_DIR/merge_config_hcl.sh" + "$SCRIPTS_DIR/merge_config_hcl.sh" -m .config "Microsoft/$FRAGMENT_CONFIG" + + # Ensure merged config is valid + make olddefconfig + + # Move merged config back to Microsoft directory (overwrites original) + mv .config "Microsoft/hcl-$CONFIG_ARCH.config" + echo ">>> CVM config merged: Microsoft/hcl-$CONFIG_ARCH.config" + + cd "$SOURCE_DIR" +} + +# +# Step 1: Build kernel +# +build_kernel() { + echo "" + echo ">>> Building kernel..." + + # Print current directory for debugging + echo ">>> Current directory: $(pwd)" + + # For reproducible builds, always clean the build directory to ensure no stale state + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + echo "Cleaning build directory for reproducible build..." + rm -rf "$BUILD_DIR" + mkdir -p "$BUILD_DIR" + fi + + # Clean source tree for CVM builds (merge_cvm_config leaves artifacts) + if [[ "$KERNEL_TYPE" == "cvm" ]]; then + echo "Running make mrproper for CVM build..." + make mrproper + fi + + # Set KBUILD_OUTPUT to match build-hcl-kernel.sh behavior + # This ensures consistent build artifact locations + # Note: build-hcl-kernel.sh uses $BUILD_DIR/linux subdirectory + export KBUILD_OUTPUT="$BUILD_DIR/linux" + + # Export KCONFIG_CONFIG with absolute path (matches build-hcl-kernel.sh) + export KCONFIG_CONFIG="$SOURCE_DIR/$CONFIG" + + # Create output directories + mkdir -p "$KBUILD_OUTPUT" + mkdir -p "$LINUX_HEADERS_DIR" + mkdir -p "$DEBUG_SYMBOL_DIR" + mkdir -p "$LINUX_BOOT_DIR" + + # Copy config to build directory + cp "$SOURCE_DIR/$CONFIG" "$KBUILD_OUTPUT/.config" + + # Build make arguments + local make_args=() + make_args+=("ARCH=$KERNEL_ARCH") + make_args+=("LOCALVERSION=") + make_args+=("CC=$COMPILER") + make_args+=("O=$KBUILD_OUTPUT") + + # Add cross-compile prefix for arm64 + if [[ -n "$CROSS_COMPILE_PREFIX" ]]; then + make_args+=("CROSS_COMPILE=$CROSS_COMPILE_PREFIX") + fi + + # Add reproducible build flags + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + make_args+=("KCFLAGS=-fdebug-prefix-map=$SOURCE_DIR=.") + fi + + # Run olddefconfig + echo "Running olddefconfig..." + make "${make_args[@]}" olddefconfig + + # Build kernel with all targets + echo "Building kernel (make all)..." + make "${make_args[@]}" -j "$(nproc)" all + echo ">>> Kernel build complete" +} + +# +# Step 2: Install headers +# +build_headers() { + echo "" + echo ">>> Installing kernel headers..." + + local make_args=("CC=$COMPILER" "O=$KBUILD_OUTPUT" "ARCH=$KERNEL_ARCH") + if [[ -n "$CROSS_COMPILE_PREFIX" ]]; then + make_args+=("CROSS_COMPILE=$CROSS_COMPILE_PREFIX") + fi + + make "${make_args[@]}" headers_install INSTALL_HDR_PATH="$LINUX_HEADERS_DIR" + + echo ">>> Headers installed to $LINUX_HEADERS_DIR" +} + +# +# Step 3: Install modules +# +build_modules() { + echo "" + echo ">>> Installing kernel modules..." + + local make_args=("CC=$COMPILER" "O=$KBUILD_OUTPUT" "ARCH=$KERNEL_ARCH") + if [[ -n "$CROSS_COMPILE_PREFIX" ]]; then + make_args+=("CROSS_COMPILE=$CROSS_COMPILE_PREFIX") + fi + + make "${make_args[@]}" modules_install INSTALL_MOD_PATH="$LINUX_DIR" + + echo ">>> Modules installed to $LINUX_DIR" +} + +# +# Step 4: Generate debug symbols +# +build_debug_symbols() { + echo "" + echo ">>> Generating debug symbols..." + + cd "$BUILD_DIR" + + # Use cross-compile objcopy for arm64 + local OBJCOPY="${CROSS_COMPILE_PREFIX}objcopy" + + # Copy vmlinux to debug symbol directory and extract debug info + cp -a "$KBUILD_OUTPUT/vmlinux" "$DEBUG_SYMBOL_DIR/" + + # Generate kernel debug symbols with compression + echo "Extracting vmlinux debug symbols..." + $OBJCOPY --only-keep-debug --compress-debug-sections "$DEBUG_SYMBOL_DIR/vmlinux" \ + "$DEBUG_SYMBOL_DIR/vmlinux.debug" + + # Create stripped vmlinux at BUILD_DIR root (matches build-hcl-kernel.sh behavior) + echo "Creating stripped vmlinux at $BUILD_DIR/vmlinux..." + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + $OBJCOPY --strip-all "$KBUILD_OUTPUT/vmlinux" "$BUILD_DIR/vmlinux" + else + $OBJCOPY --strip-all --add-gnu-debuglink="$DEBUG_SYMBOL_DIR/vmlinux.debug" "$KBUILD_OUTPUT/vmlinux" "$BUILD_DIR/vmlinux" + fi + + # Also save debug info with .dbg extension (matches build-hcl-kernel.sh) + cp -a "$DEBUG_SYMBOL_DIR/vmlinux.debug" "$BUILD_DIR/vmlinux.dbg" + + # Generate module debug symbols and strip modules + echo "Processing module debug symbols..." + for module_path in $(find "$KBUILD_OUTPUT" -name '*.ko'); do + module=$(basename "$module_path") + + # Copy module to debug symbol directory + cp -a "$module_path" "$DEBUG_SYMBOL_DIR/" + + # Extract debug symbols with compression + $OBJCOPY --only-keep-debug --compress-debug-sections "$DEBUG_SYMBOL_DIR/$module" \ + "$DEBUG_SYMBOL_DIR/$module.debug" + + # Strip debug symbols from original module + # For reproducible builds, skip --add-gnu-debuglink as it embeds a CRC + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + $OBJCOPY --strip-unneeded "$module_path" + else + $OBJCOPY --strip-unneeded --add-gnu-debuglink="$DEBUG_SYMBOL_DIR/$module.debug" "$module_path" + fi + done + + echo ">>> Debug symbols generated in $DEBUG_SYMBOL_DIR" +} + +# +# Step 5: Package kernel files to boot directory +# +package_kernel() { + echo "" + echo ">>> Packaging kernel files..." + + cd "$SOURCE_DIR" + + # Use cross-compile objcopy for arm64 + local OBJCOPY="${CROSS_COMPILE_PREFIX}objcopy" + + # Get kernel version + KERNEL_VERSION=$(cat "$KBUILD_OUTPUT/include/config/kernel.release") + echo "Kernel version: $KERNEL_VERSION" + + # Copy architecture-specific kernel image + if [[ "$MAKE_ARCH" == "arm64" ]]; then + if [[ -f "$KBUILD_OUTPUT/arch/arm64/boot/Image" ]]; then + cp -a "$KBUILD_OUTPUT/arch/arm64/boot/Image" \ + "$LINUX_BOOT_DIR/Image-$KERNEL_VERSION" + echo "Copied Image to $LINUX_BOOT_DIR/Image-$KERNEL_VERSION" + else + echo "Warning: Image not found at $KBUILD_OUTPUT/arch/arm64/boot/Image" + fi + else + if [[ -f "$KBUILD_OUTPUT/arch/x86/boot/bzImage" ]]; then + cp -a "$KBUILD_OUTPUT/arch/x86/boot/bzImage" \ + "$LINUX_BOOT_DIR/vmlinuz-$KERNEL_VERSION" + echo "Copied bzImage to $LINUX_BOOT_DIR/vmlinuz-$KERNEL_VERSION" + else + echo "Warning: bzImage not found at $KBUILD_OUTPUT/arch/x86/boot/bzImage" + fi + fi + + # Strip and copy vmlinux + echo "Stripping vmlinux..." + $OBJCOPY --strip-all "$KBUILD_OUTPUT/vmlinux" + cp -a "$KBUILD_OUTPUT/vmlinux" "$LINUX_BOOT_DIR/vmlinux-$KERNEL_VERSION" + + # Copy config and System.map + cp -a "$KBUILD_OUTPUT/.config" "$LINUX_BOOT_DIR/config-$KERNEL_VERSION" + cp -a "$KBUILD_OUTPUT/System.map" "$LINUX_BOOT_DIR/System.map-$KERNEL_VERSION" + + echo ">>> Kernel files packaged in $LINUX_BOOT_DIR" +} + +# +# Main build sequence +# +main() { + # Merge CVM config if building CVM kernel + if [[ "$KERNEL_TYPE" == "cvm" ]]; then + merge_cvm_config + fi + + echo ">>> [1/5] Building kernel..." + build_kernel + echo ">>> [2/5] Installing headers..." + build_headers + echo ">>> [3/5] Installing modules..." + build_modules + echo ">>> [4/5] Generating debug symbols..." + build_debug_symbols + echo ">>> [5/5] Packaging kernel files..." + package_kernel + + # Move build artifacts from /linux subdirectory to BUILD_DIR root for pipeline compatibility + echo "" + echo ">>> Moving build artifacts from $KBUILD_OUTPUT to $BUILD_DIR for pipeline..." + rsync -a --remove-source-files "$KBUILD_OUTPUT/" "$BUILD_DIR/" + find "$KBUILD_OUTPUT" -type d -empty -delete + echo ">>> Artifacts moved to $BUILD_DIR" + + echo "" + echo "==============================================" + echo "Build completed successfully!" + echo "==============================================" + echo "Output locations:" + echo " Build output: $BUILD_DIR" + echo " Boot files: $LINUX_BOOT_DIR" + echo " Modules: $LINUX_DIR/lib/modules/" + echo " Headers: $LINUX_HEADERS_DIR" + echo " Debug symbols: $DEBUG_SYMBOL_DIR" + if [[ -n "$REPRODUCIBLE_BUILD" ]]; then + echo "" + echo "Reproducible build completed with:" + echo " SOURCE_DATE_EPOCH: $SOURCE_DATE_EPOCH" + echo " KBUILD_BUILD_USER: $KBUILD_BUILD_USER" + echo " KBUILD_BUILD_HOST: $KBUILD_BUILD_HOST" + fi + echo "==============================================" + + # Copy artifacts back to original location for reproducible builds + copy_artifacts_back + + # Print sha256sum of vmlinux for reproducibility verification + # Check the STRIPPED vmlinux after it's been copied back to original location + if [[ -n "$REPRODUCIBLE_BUILD" ]] && [[ -f "$ORIGINAL_BUILD_DIR/vmlinux" ]]; then + echo "" + echo "Reproducibility verification:" + echo " vmlinux sha256sum: $(sha256sum "$ORIGINAL_BUILD_DIR/vmlinux" | cut -d' ' -f1)" + echo " (stripped vmlinux from $ORIGINAL_BUILD_DIR/vmlinux)" + fi +} + +# Run main +main