linux-surface fedora

linux-surface fedora

09:13

my initial goal was to get the fedora implementation of linux-surface kernel working and get the surface pro9 i'd bought plenty usable. but of course then i wanted more. the fedora instructions for the linux-surface kernel mods do work, relatively out of the box, and get you up to kernel 6.19 currently {{date}}, but i want to run a more bleeding edge version - which is still relatively stable on fedora rawhide and with a repo update to rawhide, i broke all the goodies that went with the fedora44 install.

i used a mixture of solutions here and with some internet advise, searching reddit, and other nearly similar work arounds, decided on the following:

installing latest kernel with patches

the easiest instructions wound up in the github documentation for the Linus Torvalds github main kernel repo (am i saying that right?) and linked to here https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/quickly-build-trimmed-linux.rst#id17

this is a handy kernel build sheet for a one-time kernel install, of course there's options here, but the tl;dr is there and copy/paste will get you the latest kernel (7.2-rc5). the instructions worked part way for me.

git clone --no-checkout --depth 1 -b master \
  https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git ~/linux/
cd ~/linux/
git checkout --detach origin/master

this will get you the latest kernel sources. i have mine altered as below:

git clone --no-checkout --depth 1 -b master \
  https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git ~/projects/kernel/linux-7.2-rc5/
cd ~/projects/kernel/linux-7.2-rc5/
git checkout --detach origin/master

for manual installation, this will keep the linux sources separate for each kernel. the patch command that follows wasn't quite what i needed. i had to rework a couple things with the help of chatgpt to get the patches to work with some of the new kernel requirements. i put all the patches in the ~/projects/kernel/patches/surface-pro9-final and ofc are .patch, here's the list of the ones i used:

the names cross (roughly) to those in the linux-surface patch repo, but some are adapted to kernel specifics for the fedora platform and surface-pro9 specifically.

to get these applied i instead used

git am ~/projects/kernel/patches/surface-pro9-final/*.patch

this gave me some blank line indicators and dealt with them while applying the patches without any errors.

here's the build-surface-kernel-2.sh file created to implemented after the git am command for the manual testing: build-surface-kernel-2.sh

#!/usr/bin/env bash
set -euo pipefail

exec > >(tee -a "$HOME/projects/kernel/build.log") 2>&1

KERNEL_SRC="${1:?Give kernel source path}"

# Normalize (resolve symlinks) if possible
KERNEL_SRC="$(readlink -f "$KERNEL_SRC" 2>/dev/null || echo "$KERNEL_SRC")"

[[ -d "$KERNEL_SRC" ]] || {
  echo "Kernel source must be a directory: $KERNEL_SRC"
  exit 1
}

NAME="surface-pro9"

BASE="$HOME/projects/kernel"

CONFIG="$BASE/configs/surface-pro9.config"
BUILD="$BASE/builds/$NAME"
LOCALVERSION="-surface-pro9"

MOK_KEY="$HOME/secureboot/MOK.key"
MOK_CERT="$HOME/secureboot/MOK.pem"

RHELVER="$BASE/Makefile.rhelver"

echo "================================="
echo "Kernel source:"
echo "$KERNEL_SRC"

echo
echo "Build:"
echo "$BUILD"

echo
echo "Config:"
echo "$CONFIG"

echo
echo "================================="

for f in "$CONFIG" "$MOK_KEY" "$MOK_CERT"; do
  [[ -f "$f" ]] || {
    echo "Missing:"
    echo "$f"
    exit 1
  }
done

mkdir -p "$BUILD"

echo "[1/9] Copy config"
cp "$CONFIG" "$BUILD/.config"

echo "[2/9] Fedora metadata"

# If kernel doesn't have Makefile.rhelver, link it in for the build.
if [[ ! -e "$KERNEL_SRC/Makefile.rhelver" ]]; then
  ln -sf "$RHELVER" "$KERNEL_SRC/Makefile.rhelver"
  CLEAN_RHELVER=1
else
  CLEAN_RHELVER=0
fi

echo "[3/9] Local version"

"$KERNEL_SRC/scripts/config" \
  --file "$BUILD/.config" \
  --set-str CONFIG_LOCALVERSION "$LOCALVERSION"

"$KERNEL_SRC/scripts/config" \
  --file "$BUILD/.config" \
  --disable CONFIG_LOCALVERSION_AUTO

echo "[4/9] olddefconfig"
make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  olddefconfig

echo "[5/9] Build"
make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  -j"$(nproc)"

KREL="$(make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  -s kernelrelease)"

echo
echo "Built:"
echo "$KREL"

echo "[6/9] Install modules"
sudo make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  modules_install

echo "[7/9] Install kernel"
sudo install \
  -Dm644 \
  "$BUILD/arch/x86/boot/bzImage" \
  "/boot/vmlinuz-$KREL"

echo "[8/9] Sign"
sudo sbsign \
  --key "$MOK_KEY" \
  --cert "$MOK_CERT" \
  --output "/boot/vmlinuz-$KREL.signed" \
  "/boot/vmlinuz-$KREL"

sudo mv \
  "/boot/vmlinuz-$KREL.signed" \
  "/boot/vmlinuz-$KREL"

echo "[9/9] Fedora registration"
sudo dracut \
  --force \
  "/boot/initramfs-$KREL.img" \
  "$KREL"

sudo ln -sf \
  "/boot/vmlinuz-$KREL" \
  "/usr/lib/modules/$KREL/vmlinuz"

sudo kernel-install add \
  "$KREL" \
  "/boot/vmlinuz-$KREL"

if [[ "$CLEAN_RHELVER" == "1" ]]; then
  rm -f "$KERNEL_SRC/Makefile.rhelver"
fi

echo
echo "DONE"
echo "$KREL installed"

automations - setting it up for permanence

build-exp.sh

#!/usr/bin/env bash
set -euo pipefail

exec > >(tee -a "$HOME/projects/kernel/build.log") 2>&1

KERNEL_SRC="${1:?Give kernel source path}"

# Normalize (resolve symlinks) if possible
KERNEL_SRC="$(readlink -f "$KERNEL_SRC" 2>/dev/null || echo "$KERNEL_SRC")"

[[ -d "$KERNEL_SRC" ]] || {
  echo "Kernel source must be a directory: $KERNEL_SRC"
  exit 1
}

NAME="surface-pro9"

BASE="$HOME/projects/kernel"

CONFIG="$BASE/configs/surface-pro9.config"
BUILD="$BASE/builds/$NAME"
LOCALVERSION="-surface-pro9"

MOK_KEY="$HOME/secureboot/MOK.key"
MOK_CERT="$HOME/secureboot/MOK.pem"

RHELVER="$BASE/Makefile.rhelver"

echo "================================="
echo "Kernel source:"
echo "$KERNEL_SRC"

echo
echo "Build:"
echo "$BUILD"

echo
echo "Config:"
echo "$CONFIG"

echo
echo "================================="

for f in "$CONFIG" "$MOK_KEY" "$MOK_CERT"; do
  [[ -f "$f" ]] || {
    echo "Missing:"
    echo "$f"
    exit 1
  }
done

mkdir -p "$BUILD"

echo "[1/9] Copy config"
cp "$CONFIG" "$BUILD/.config"

echo "[2/9] Fedora metadata"

# If kernel doesn't have Makefile.rhelver, link it in for the build.
if [[ ! -e "$KERNEL_SRC/Makefile.rhelver" ]]; then
  ln -sf "$RHELVER" "$KERNEL_SRC/Makefile.rhelver"
  CLEAN_RHELVER=1
else
  CLEAN_RHELVER=0
fi

echo "[3/9] Local version"

"$KERNEL_SRC/scripts/config" \
  --file "$BUILD/.config" \
  --set-str CONFIG_LOCALVERSION "$LOCALVERSION"

"$KERNEL_SRC/scripts/config" \
  --file "$BUILD/.config" \
  --disable CONFIG_LOCALVERSION_AUTO

echo "[4/9] olddefconfig"
make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  olddefconfig

echo "[5/9] Build"
make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  -j"$(nproc)"

KREL="$(make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  -s kernelrelease)"

echo
echo "Built:"
echo "$KREL"

echo "[6/9] Install modules"
sudo make \
  -C "$KERNEL_SRC" \
  O="$BUILD" \
  modules_install

echo "[7/9] Install kernel"
sudo install \
  -Dm644 \
  "$BUILD/arch/x86/boot/bzImage" \
  "/boot/vmlinuz-$KREL"

echo "[8/9] Sign"
sudo sbsign \
  --key "$MOK_KEY" \
  --cert "$MOK_CERT" \
  --output "/boot/vmlinuz-$KREL.signed" \
  "/boot/vmlinuz-$KREL"

sudo mv \
  "/boot/vmlinuz-$KREL.signed" \
  "/boot/vmlinuz-$KREL"

echo "[9/9] Fedora registration"
sudo dracut \
  --force \
  "/boot/initramfs-$KREL.img" \
  "$KREL"

sudo ln -sf \
  "/boot/vmlinuz-$KREL" \
  "/usr/lib/modules/$KREL/vmlinuz"

sudo kernel-install add \
  "$KREL" \
  "/boot/vmlinuz-$KREL"

if [[ "$CLEAN_RHELVER" == "1" ]]; then
  rm -f "$KERNEL_SRC/Makefile.rhelver"
fi

echo
echo "DONE"
echo "$KREL installed"

kernel/automation  rawhide*​ 
❯ cat build-exp.sh 
#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<'EOF'
Usage:
  build-surface-kernel-all.sh <kernel_dir> <remote_ref> <localversion_suffix> <patch_glob>

Examples:
  build-surface-kernel-all.sh ~/projects/kernel/7.2-rc5 master \
    "-proposed_fix-surface-pro9" \
    ~/projects/kernel/patches/surface-pro9-final/*.patch

remote_ref is the branch name you want from the stable/linux repo
(e.g. "master", "linux-6.9.y", etc.). The script fetches origin/<remote_ref>.
EOF
}

#enable ccache
export PATH="/usr/lib64/ccache:$PATH"
export CCACHE_DIR="$HOME/.ccache"
export CCACHE_MAXSIZE="50G"
export CCACHE_COMPILERCHECK="content"
export CCACHE_SLOPPINESS="time_macros,include_file_mtime"

KERNEL_DIR="${1:-}"
REMOTE_REF="${2:-}"                   # e.g. master
LOCALVERSION_SUFFIX="${3:-}"         # e.g. -proposed_fix-surface-pro9
PATCH_GLOB="${4:-}"

if [[ -z "$KERNEL_DIR" || -z "$REMOTE_REF" || -z "$LOCALVERSION_SUFFIX" || -z "$PATCH_GLOB" ]]; then
  usage
  exit 1
fi

KERNEL_DIR="$(readlink -f "$KERNEL_DIR" 2>/dev/null || echo "$KERNEL_DIR")"
BASE="${HOME}/projects/kernel"
NAME="surface-pro9"

REMOTE_REPO_URL="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"

CONFIG="${BASE}/configs/surface-pro9.config"
MOK_KEY="${HOME}/secureboot/MOK.key"
MOK_CERT="${HOME}/secureboot/MOK.pem"
RHELVER="${BASE}/Makefile.rhelver"

echo "Kernel dir: $KERNEL_DIR"
echo "Remote ref: origin/$REMOTE_REF"
echo "Localversion: $LOCALVERSION_SUFFIX"
echo "Patch glob: $PATCH_GLOB"

# -------- clone if missing --------
if [[ ! -d "${KERNEL_DIR}/.git" ]]; then
  mkdir -p "$(dirname "$KERNEL_DIR")"
  echo "[1/10] Cloning (shallow) kernel into: $KERNEL_DIR"
  git clone --no-checkout --depth 1 -b "$REMOTE_REF" "$REMOTE_REPO_URL" "$KERNEL_DIR"
fi

cd "$KERNEL_DIR"

# -------- compute current and remote commit IDs (shallow) --------
# Remote "newness" check:
# - Ensure origin remote exists
git remote get-url origin >/dev/null 2>&1 || git remote add origin "$REMOTE_REPO_URL"

echo "[2/10] Fetching remote commit (shallow) to check if newer"
git fetch --depth 1 origin "${REMOTE_REF}" >/dev/null

REMOTE_COMMIT="$(git rev-parse --verify --short "origin/${REMOTE_REF}")"
if git show -s --verify --quiet HEAD >/dev/null 2>&1; then
  LOCAL_COMMIT="$(git rev-parse --verify --short HEAD || echo "")"
else
  LOCAL_COMMIT=""
fi

echo "Local HEAD:   ${LOCAL_COMMIT:-<none>}"
echo "Remote commit:${REMOTE_COMMIT}"

# Optional policy: only continue if remote is newer/different.
# If you prefer always rebuild, delete the if-block and always proceed.
if [[ -n "$LOCAL_COMMIT" && "$LOCAL_COMMIT" == "$REMOTE_COMMIT" ]]; then
  echo "[3/10] Remote ref matches local HEAD; nothing to do."
  exit 0
fi

echo "[3/10] Checking out remote commit (detached)"
git checkout --detach "origin/${REMOTE_REF}"

# -------- patch stamp keyed by commit + patch set hash --------
# Compute patch set hash (cheap-ish but solid enough): hash file contents.
# If you have many patches and want faster, we can instead hash mtimes or names.
echo "[4/10] Building patch identity hash"
shopt -s nullglob
PATCH_FILES=( $PATCH_GLOB )
shopt -u nullglob

if [[ ${#PATCH_FILES[@]} -eq 0 ]]; then
  echo "No patches matched: $PATCH_GLOB"
  exit 1
fi

PATCH_HASH="$(
  {
    printf 'count=%s\n' "${#PATCH_FILES[@]}"
    for p in "${PATCH_FILES[@]}"; do
      # include path + file content
      printf 'file=%s\n' "$p"
      sha256sum "$p"
    done
  } | sha256sum | awk '{print $1}'
)"

KERNEL_COMMIT_FULL="$(git rev-parse HEAD)"
STAMP_DIR="${KERNEL_DIR}/.surface-pro9-stamps"
mkdir -p "$STAMP_DIR"

STAMP_FILE="${STAMP_DIR}/patches-applied.commit-${KERNEL_COMMIT_FULL}.localversion-${LOCALVERSION_SUFFIX}.hash-${PATCH_HASH}"
if [[ -f "$STAMP_FILE" ]]; then
  echo "[5/10] Patches already applied for this kernel commit + patch set + localversion"
else
  echo "[5/10] Applying patches via git am"
  # If previous am is interrupted:
  if [[ -d ".git/rebase-apply" || -f ".git/AM_ERROR" ]]; then
    git am --abort >/dev/null 2>&1 || true
  fi

  # git am needs files in order
  # We already expanded glob; preserve shell order (usually lexicographic). If you need explicit order,
  # you can sort PATCH_FILES.
  git am "${PATCH_FILES[@]}"

  touch "$STAMP_FILE"
fi

# -------- build directory keyed by localversion + commit --------
# Avoid mixing configs/artifacts from different suffix/commits.
SHORT="$(git rev-parse --short HEAD)"
SAFE_TAG="${LOCALVERSION_SUFFIX//[^A-Za-z0-9._+-]/_}"
BUILD="${BASE}/builds/${NAME}-${SHORT}${SAFE_TAG:+-${SAFE_TAG}}"

# -------- validate inputs --------
for f in "$CONFIG" "$MOK_KEY" "$MOK_CERT"; do
  [[ -f "$f" ]] || { echo "Missing: $f"; exit 1; }
done

mkdir -p "$BUILD"

KERNEL_SRC="$(readlink -f "$KERNEL_DIR" 2>/dev/null || echo "$KERNEL_DIR")"
CLEAN_RHELVER=0

# Ensure Makefile.rhelver exists during build
if [[ ! -e "$KERNEL_SRC/Makefile.rhelver" ]]; then
  ln -sf "$RHELVER" "$KERNEL_SRC/Makefile.rhelver"
  CLEAN_RHELVER=1
fi

# -------- config + localversion --------
echo "[6/10] Copy config to build dir"
cp "$CONFIG" "$BUILD/.config"

echo "[7/10] Set CONFIG_LOCALVERSION + disable auto"
"$KERNEL_SRC/scripts/config" --file "$BUILD/.config" --set-str CONFIG_LOCALVERSION "$LOCALVERSION_SUFFIX"
"$KERNEL_SRC/scripts/config" --file "$BUILD/.config" --disable CONFIG_LOCALVERSION_AUTO

echo "[8/10] olddefconfig + build"
make -C "$KERNEL_SRC" O="$BUILD" olddefconfig
make -C "$KERNEL_SRC" O="$BUILD" -j"$(nproc)"

KREL="$(make -C "$KERNEL_SRC" O="$BUILD" -s kernelrelease)"
echo "Built: $KREL"

# -------- install + sign + dracut --------
echo "[9/10] Install modules/kernel + sign + initramfs"
sudo make -C "$KERNEL_SRC" O="$BUILD" modules_install

sudo install -Dm644 "$BUILD/arch/x86/boot/bzImage" "/boot/vmlinuz-$KREL"

sudo sbsign \
  --key "$MOK_KEY" \
  --cert "$MOK_CERT" \
  --output "/boot/vmlinuz-$KREL.signed" \
  "/boot/vmlinuz-$KREL"

sudo mv "/boot/vmlinuz-$KREL.signed" "/boot/vmlinuz-$KREL"

sudo dracut --force "/boot/initramfs-$KREL.img" "$KREL"

sudo ln -sf "/boot/vmlinuz-$KREL" "/usr/lib/modules/$KREL/vmlinuz"
sudo kernel-install add "$KREL" "/boot/vmlinuz-$KREL"

if [[ "$CLEAN_RHELVER" == "1" ]]; then
  rm -f "$KERNEL_SRC/Makefile.rhelver"
fi

echo "[10/10] DONE"
echo "$KREL installed"

known caveats:

ipts driver built into kernel, so not exactly sure how i would change any config sensitivity, i will experiment with settings in the config file that iptsd is said to use here: https://github.com/linux-surface/linux-surface/wiki/Surface-Pro-9

quoted below:

The touchscreen may behave erratically due to wrong or missing calibration values.

To fix this, remove any existing calibration files present and create a new calibration file with the below values in /etc/iptsd.d/ (for example /etc/iptsd.d/91-calibration.conf), reboot your SP9 and your touchscreen should be smooth as butter:

[Contacts]
ActivationThreshold = 24
DeactivationThreshold = 20
OrientationThresholdMax = 5

Source: https://github.com/linux-surface/iptsd/issues/171#issuecomment-2359625900