Skip to content

Commit 9fd0048

Browse files
committed
Add UKI mode
Signed-off-by: Alexey Gladkov <[email protected]>
1 parent 132ec31 commit 9fd0048

File tree

9 files changed

+346
-7
lines changed

9 files changed

+346
-7
lines changed

features/uki/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Feature: uki
2+
3+
Unified kernel image (UKI) is a single executable which can be booted directly
4+
from UEFI firmware, or automatically sourced by boot-loaders with little or no
5+
configuration.

features/uki/bin/find-kernel

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/bin/bash -eu
2+
# SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
. shell-error
5+
6+
BOOTDIR="${BOOTDIR:-/boot}"
7+
arch="${ARCH:-$(uname -m)}"
8+
kversion="${KERNEL:-$(uname -r)}"
9+
10+
show_usage()
11+
{
12+
cat <<-EOF
13+
Usage: $PROG [options]
14+
15+
The utility shows the kernel image.
16+
17+
Options:
18+
--arch=ARCH Use ARCH as target architecture instead of `uname -m`;
19+
-k, --set-version=VERSION Use VERSION instead of `uname -r`;
20+
-h, --help Show this text and exit.
21+
22+
Report bugs to authors.
23+
24+
EOF
25+
exit
26+
}
27+
28+
TEMP=`getopt -n "$PROG" -o "k:,h" -l "arch:,set-version:,help" -- "$@"` ||
29+
show_usage
30+
eval set -- "$TEMP"
31+
32+
while :; do
33+
case "$1" in
34+
--arch) shift
35+
arch="$1"
36+
;;
37+
-k|--set-version) shift
38+
kversion="$1"
39+
;;
40+
-h|--help)
41+
show_usage
42+
;;
43+
--) shift; break
44+
;;
45+
*) fatal "unrecognized option: $1"
46+
;;
47+
esac
48+
shift
49+
done
50+
51+
efi_type=
52+
53+
if [ -n "$arch" ]; then
54+
case "$arch" in
55+
x86_64) efi_type=x64 ;;
56+
i?86) efi_type=ia32 ;;
57+
aarch64) efi_type=aa64 ;;
58+
*)
59+
fatal "Architecture '$arch' not supported to create a UEFI executable"
60+
;;
61+
esac
62+
fi
63+
64+
for ent in "$BOOTDIR"/loader/entries/*.conf; do
65+
[ -s "$ent" ] ||
66+
continue
67+
68+
version='' architecture='' linux=''
69+
70+
while read -r k v; do
71+
case "$k" in
72+
architecture) architecture="$v" ;;
73+
version) version="$v" ;;
74+
linux) linux="$v" ;;
75+
esac
76+
done < "$ent"
77+
78+
[ -z "$architecture" ] || [ "$architecture" = "$efi_type" ] ||
79+
continue
80+
81+
[ "$version" = "$kverion" ] ||
82+
continue
83+
84+
[ -n "$linux" ] ||
85+
continue
86+
87+
! readlink -ev -- "$linux" 2>/dev/null ||
88+
exit 0
89+
done
90+
91+
readlink -ev -- "$BOOTDIR/vmlinuz-$kversion" 2>/dev/null ||
92+
readlink -ev -- "/lib/modules/$kversion/vmlinuz" 2>/dev/null ||
93+
fatal "kernel not found"

features/uki/bin/pack-uefi

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#!/bin/bash -eu
2+
# SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
. sh-functions
5+
. shell-error
6+
7+
BOOTDIR="${BOOTDIR:-/boot}"
8+
PROCFS_PATH="${PROCFS_PATH:-/proc}"
9+
arch="${ARCH:-$(uname -m)}"
10+
11+
uefi_stub="${UKI_UEFI_STUB-}"
12+
kernel="${UKI_KERNEL-}"
13+
initrd="$workdir/initrd.img"
14+
outfile="${UKI_EFI_INTERNAL_IMAGE:-$workdir/linux.efi}"
15+
16+
17+
get_offset_value()
18+
{
19+
local idx name size vma lma file_off algn
20+
21+
printf -v "$1" '0'
22+
23+
while read -r idx name size vma lma file_off algn; do
24+
[ -z "$idx" ] || [ -z "${idx##*[!0-9]*}" ] ||
25+
printf -v "$1" '%s' "$(( 16#${size} + 16#${vma} ))"
26+
done < <(objdump -h "$2" 2>/dev/null)
27+
}
28+
29+
filter_objdump()
30+
{
31+
local k a b c d e;
32+
33+
eval "$1=('' '' '' '' '')"
34+
35+
while read -r k a b c d e; do
36+
[ "$k" != "$3" ] ||
37+
eval "$1=(\"\$a\" \"\$b\" \"\$c\" \"\$d\" \"\$e\")"
38+
done < <(objdump -p "$2" 2>/dev/null)
39+
}
40+
41+
pe_get_int_value()
42+
{
43+
local values
44+
filter_objdump values "$2" "$3"
45+
46+
[ -n "${values[0]}" ] &&
47+
printf -v "$1" '%s' "$(( 16#${values[0]} ))" ||
48+
return 1
49+
}
50+
51+
pe_file_format()
52+
{
53+
local magic=0
54+
pe_get_int_value magic "$1" "Magic"
55+
56+
case "$magic" in
57+
267|523) # 010b (PE32) | 020b (PE32+)
58+
return 0
59+
;;
60+
esac
61+
return 1
62+
}
63+
64+
section_align=0
65+
offset=0
66+
update_section_offset()
67+
{
68+
[ "$#" -eq 0 ] ||
69+
offset=$(( $offset + $(stat -Lc%s "$1") ))
70+
offset=$(( $offset + $section_align - $offset % $section_align ))
71+
}
72+
73+
args=()
74+
add_section()
75+
{
76+
local offs
77+
printf -v offs '0x%x' "$offset"
78+
args+=( --add-section "$1=$2" --change-section-vma "$1=$offs" )
79+
update_section_offset "$2"
80+
}
81+
82+
[ -n "$kernel" ] ||
83+
kernel="$("$FEATURESDIR"/uki/bin/find-kernel)"
84+
85+
[ -f "$kernel" ] ||
86+
fatal "Can't find a kernel image to create a UEFI executable"
87+
88+
if [ -z "$uefi_stub" ]; then
89+
case "$arch" in
90+
x86_64) efi_type=x64 ;;
91+
i?86) efi_type=ia32 ;;
92+
aarch64) efi_type=aa64 ;;
93+
*)
94+
fatal "Architecture '$arch' not supported to create a UEFI executable"
95+
;;
96+
esac
97+
98+
uefi_stub="/usr/lib/systemd/boot/efi/linux${efi_type}.efi.stub"
99+
fi
100+
101+
pe_file_format "$uefi_stub" ||
102+
fatal "wrong file format: $uefi_stub"
103+
104+
get_offset_value offset "$uefi_stub"
105+
106+
[ $offset -gt 0 ] ||
107+
fatal "failed to get the size of $uefi_stub to create UEFI image file"
108+
109+
pe_get_int_value section_align "$uefi_stub" SectionAlignment ||
110+
fatal "failed to get the SectionAlignment of the stub PE header to create the UEFI image file"
111+
112+
image_base=0
113+
pe_get_int_value image_base "$uefi_stub" ImageBase ||
114+
fatal "failed to get the ImageBase of the stub PE header to create the UEFI image file"
115+
116+
printf -v image_base '0x%x' "$image_base"
117+
118+
args=( --image-base="$image_base" )
119+
120+
update_section_offset
121+
122+
for f in /usr/lib/os-release /etc/os-release; do
123+
if [ -s "$f" ]; then
124+
add_section ".osrel" "$f"
125+
break
126+
fi
127+
done
128+
129+
# shellcheck disable=SC2206
130+
cmdline=( ${UKI_CMDLINE-} )
131+
132+
if [ "${#cmdline[@]}" -gt 0 ]; then
133+
:;
134+
elif [ -d /etc/cmdline.d ]; then
135+
for conf in /etc/cmdline.d/*.conf; do
136+
[ -e "$conf" ] ||
137+
continue
138+
while read -r l; do
139+
# shellcheck disable=SC2206
140+
cmdline+=( $l )
141+
done < "$conf"
142+
done
143+
elif [ -e "$PROCFS_PATH/cmdline" ]; then
144+
while read -r l; do
145+
# shellcheck disable=SC2206
146+
cmdline+=( $l )
147+
done < "$PROCFS_PATH/cmdline"
148+
fi
149+
150+
uefi_cmdline="$workdir/cmdline.txt"
151+
printf >"$uefi_cmdline" '%s\0' "${cmdline[*]}"
152+
153+
add_section ".cmdline" "$uefi_cmdline"
154+
155+
[ -z "${UKI_SPLASH_IMAGE-}" ] || [ ! -s "$UKI_SPLASH_IMAGE" ] ||
156+
add_section ".splash" "$UKI_SPLASH_IMAGE"
157+
158+
uefi_sbat="$workdir/uki.sbat"
159+
printf >"$uefi_sbat" '%s\n' \
160+
"sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md" \
161+
${UKI_SBAT:+"$UKI_SBAT"}
162+
163+
add_section ".sbat" "$uefi_sbat"
164+
add_section ".linux" "$kernel"
165+
add_section ".initrd" "$initrd"
166+
167+
uefi_stub_file="$workdir/stub.efi"
168+
169+
cp $verbose -f -- "$uefi_stub" "$uefi_stub_file"
170+
objcopy --remove-section ".sbat" "$uefi_stub_file" >/dev/null 2>&1
171+
objcopy $verbose "${args[@]}" "$uefi_stub_file" "$outfile"
172+
173+
rm -f -- "$uefi_cmdline" "$uefi_sbat" "$uefi_stub_file" "$initrd"

features/uki/config.mk

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
$(call feature-requires,\
4+
$(call if-active-feature,btrfs mdadm lvm luks devmapper) \
5+
add-modules add-udev-rules \
6+
modules-blockdev \
7+
modules-crypto-user-api \
8+
modules-filesystem \
9+
modules-multiple-devices \
10+
modules-network \
11+
modules-nfs)
12+
13+
$(call feature-disables,compress)
14+
15+
UKI_PROGS = objdump objcopy
16+
17+
UKI_UEFI_STUB =
18+
UKI_SBAT =
19+
UKI_KERNEL =
20+
UKI_CMDLINE =
21+
UKI_SPLASH_IMAGE =
22+
23+
UKI_EFIDIR ?= $(firstword $(wildcard /efi/EFI $(BOOTDIR)/efi/EFI $(BOOTDIR)))
24+
UKI_IMAGEFILE ?= $(UKI_EFIDIR)/linux-$(KERNEL).efi

features/uki/rules.mk

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# SPDX-License-Identifier: GPL-3.0-or-later
2+
3+
PUT_FEATURE_PROGS += $(UKI_PROGS)
4+
5+
UKI_EFI_INTERNAL_IMAGE := $(WORKDIR)/linux.efi
6+
7+
pack-uefi: pack $(call if-active-feature,ucode bootconfig)
8+
@$(VMSG) "Packing UEFI image ..."
9+
@$(FEATURESDIR)/uki/bin/pack-uefi
10+
11+
install: pack-uefi
12+
@$(MSG) 'Used features: $(USED_FEATURES)'
13+
@$(MSG_N) 'Packed modules: '
14+
@find $(ROOTDIR)/lib/modules/$(KERNEL) -type f \( -name '*.ko' -o -name '*.ko.*' \) -printf '%f\n' 2>/dev/null | \
15+
sed -e 's/\.ko\(\.[^\.]\+\)\?$$//' | sort -u | tr '\n' ' '
16+
@printf '\n'
17+
@if [ -f "$(TEMPDIR)/images" ] && grep -Fxqs "$(UKI_IMAGEFILE)" "$(TEMPDIR)/images"; then \
18+
echo ""; \
19+
echo "An attempt to create two images with the same name. There is possibility" >&2; \
20+
echo "that you forgot to define IMAGE_SUFFIX or IMAGEFILE in one of the config files." >&2; \
21+
echo "" >&2; \
22+
echo "ERROR: Unable to overwrite the image $(UKI_IMAGEFILE)" >&2; \
23+
echo "" >&2; \
24+
exit 1; \
25+
else \
26+
$(VMSG) "Installing UKI image ..."; \
27+
$(MSG) "Unpacked size: `du -sh "$(WORKDIR)/img" |cut -f1 ||:`"; \
28+
$(MSG) "Image size: `du -sh "$(UKI_EFI_INTERNAL_IMAGE)" |cut -f1 ||:`"; \
29+
chmod 600 -- "$(UKI_EFI_INTERNAL_IMAGE)"; \
30+
mv -f $(verbose) -- "$(UKI_EFI_INTERNAL_IMAGE)" "$(UKI_IMAGEFILE)"; \
31+
echo "$(UKI_IMAGEFILE)" >> "$(TEMPDIR)/images"; \
32+
fi
33+
34+
genimage: install
35+
@$(MSG) "Image is saved as $(UKI_IMAGEFILE)"
36+
@echo

mk/config.mk.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ PUT_PROGS ?=
125125
#
126126
# See https://github.com/systemd/systemd/blob/main/docs/ELF_DLOPEN_METADATA.md
127127
#
128-
IGNORE_PUT_DLOPEN_FEATURE ?=
128+
IGNORE_PUT_DLOPEN_FEATURE ?= /libsystemd-shared-.*\.so:archive
129129
IGNORE_PUT_DLOPEN_PRIORITY ?=
130130

131131
# Load user configuration

mk/functions.mk.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ endef
6969

7070
define get-all-features
7171
$(strip $(if $(filter get-all-features,$(0)),\
72-
$(sort $(filter-out ,$(call expand-features,FEATURE-REQUIRES,$(FEATURES))))))
72+
$(sort $(filter-out ,$(call expand-features,FEATURE-REQUIRES,$(FEATURES) $(if $(UKI),uki))))))
7373
endef
7474

7575
define get-all-disable-features

0 commit comments

Comments
 (0)