]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/meson.build
man/systemd-sysext.xml: document mutable extensions
[thirdparty/systemd.git] / src / boot / efi / meson.build
1 # SPDX-License-Identifier: LGPL-2.1-or-later
2
3 efi_config_h_dir = meson.current_build_dir()
4 efi_addon = ''
5
6 libefitest = static_library(
7 'efitest',
8 files(
9 'bcd.c',
10 'efi-string.c',
11 ),
12 build_by_default : false,
13 include_directories : [
14 basic_includes,
15 include_directories('.'),
16 ],
17 dependencies : userspace)
18
19 efitest_base = {
20 'link_with' : [
21 libefitest,
22 libshared,
23 ],
24 }
25 efi_test_template = test_template + efitest_base
26 efi_fuzz_template = fuzz_template + efitest_base
27
28 executables += [
29 efi_test_template + {
30 'sources' : files('test-bcd.c'),
31 'dependencies' : libzstd,
32 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_ZSTD'],
33 },
34 efi_test_template + {
35 'sources' : files('test-efi-string.c'),
36 'conditions' : ['ENABLE_BOOTLOADER'],
37 },
38 efi_fuzz_template + {
39 'sources' : files('fuzz-bcd.c'),
40 },
41 efi_fuzz_template + {
42 'sources' : files('fuzz-efi-string.c'),
43 },
44 efi_fuzz_template + {
45 'sources' : files('fuzz-efi-osrel.c'),
46 },
47 efi_fuzz_template + {
48 'sources' : files('fuzz-efi-printf.c'),
49 },
50 ]
51
52 if conf.get('ENABLE_BOOTLOADER') != 1
53 subdir_done()
54 endif
55
56 efi_conf = configuration_data()
57 efi_conf.set10('ENABLE_TPM', get_option('tpm'))
58
59 foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit']
60 c = get_option('efi-' + ctype).split(',')
61 efi_conf.set(ctype.underscorify().to_upper(), 'EFI_TEXT_ATTR(@0@, @1@)'.format(
62 'EFI_' + c[0].strip().underscorify().to_upper(),
63 'EFI_' + c[1].strip().underscorify().to_upper()))
64 endforeach
65
66 if meson.is_cross_build() and get_option('sbat-distro') == 'auto'
67 warning('Auto detection of SBAT information not supported when cross-building, disabling SBAT.')
68 elif get_option('sbat-distro') != ''
69 efi_conf.set_quoted('SBAT_PROJECT', meson.project_name())
70 efi_conf.set_quoted('PROJECT_VERSION', meson.project_version().split('~')[0])
71 efi_conf.set('PROJECT_URL', conf.get('PROJECT_URL'))
72 if get_option('sbat-distro-generation') < 1
73 error('SBAT Distro Generation must be a positive integer')
74 endif
75 efi_conf.set('SBAT_DISTRO_GENERATION', get_option('sbat-distro-generation'))
76 foreach sbatvar : [['sbat-distro', 'ID'],
77 ['sbat-distro-summary', 'NAME'],
78 ['sbat-distro-url', 'BUG_REPORT_URL']]
79 value = get_option(sbatvar[0])
80 if (value == '' or value == 'auto') and not meson.is_cross_build()
81 cmd = 'if [ -e /etc/os-release ]; then . /etc/os-release; else . /usr/lib/os-release; fi; echo $@0@'.format(sbatvar[1])
82 value = run_command(sh, '-c', cmd, check: true).stdout().strip()
83 endif
84 if value == ''
85 error('Required @0@ option not set and autodetection failed'.format(sbatvar[0]))
86 endif
87 efi_conf.set_quoted(sbatvar[0].underscorify().to_upper(), value)
88 endforeach
89
90 pkgname = get_option('sbat-distro-pkgname')
91 if pkgname == ''
92 pkgname = meson.project_name()
93 endif
94 efi_conf.set_quoted('SBAT_DISTRO_PKGNAME', pkgname)
95
96 pkgver = get_option('sbat-distro-version')
97 if pkgver == ''
98 # This is determined during build, not configuration, so we can't display it yet.
99 efi_conf.set('SBAT_DISTRO_VERSION', 'GIT_VERSION')
100 else
101 efi_conf.set_quoted('SBAT_DISTRO_VERSION', pkgver)
102 endif
103 endif
104
105 summary({'UEFI architectures' : efi_arch + (efi_arch_alt == '' ? '' : ', ' + efi_arch_alt)},
106 section : 'UEFI')
107
108 if efi_conf.get('SBAT_DISTRO', '') != ''
109 summary({
110 'SBAT distro': efi_conf.get('SBAT_DISTRO'),
111 'SBAT distro generation': efi_conf.get('SBAT_DISTRO_GENERATION'),
112 'SBAT distro version': efi_conf.get('SBAT_DISTRO_VERSION'),
113 'SBAT distro summary': efi_conf.get('SBAT_DISTRO_SUMMARY'),
114 'SBAT distro URL': efi_conf.get('SBAT_DISTRO_URL')},
115 section : 'UEFI')
116 endif
117
118 configure_file(
119 output : 'efi_config.h',
120 configuration : efi_conf)
121
122 ############################################################
123
124 efi_includes = [
125 build_dir_include,
126 fundamental_include,
127 include_directories('.'),
128 ]
129
130 efi_c_args = [
131 '-DSD_BOOT=1',
132 '-ffreestanding',
133 '-fno-strict-aliasing',
134 '-fshort-wchar',
135 '-include', 'efi_config.h',
136 ]
137
138 efi_c_args += cc.get_supported_arguments(
139 '-fwide-exec-charset=UCS2',
140 # gcc docs says this is required for ms_abi to work correctly.
141 '-maccumulate-outgoing-args',
142 '-mstack-protector-guard=global',
143 )
144
145 # Debug information has little value in release builds as no normal human being knows
146 # how to attach a debugger to EFI binaries running on real hardware. Anyone who does
147 # certainly has the means to do their own dev build.
148 if get_option('mode') == 'developer' and get_option('debug')
149 efi_c_args += '-DEFI_DEBUG'
150 endif
151
152 efi_c_ld_args = [
153 '-lgcc',
154 '-nostdlib',
155 '-static-pie',
156 '-Wl,--entry=efi_main',
157 '-Wl,--fatal-warnings',
158
159 # These flags should be passed by -static-pie, but for whatever reason the flag translation
160 # is not enabled on all architectures. Not passing `-static` would just allow the linker to
161 # use dynamic libraries, (which we can't/don't use anyway). But if `-pie` is missing and the
162 # gcc build does not default to `-pie` we get a regular (no-pie) binary that will be
163 # rightfully rejected by elf2efi. Note that meson also passes `-pie` to the linker driver,
164 # but it is overridden by our `-static-pie`. We also need to pass these directly to the
165 # linker as `-static`+`-pie` seem to get translated differently.
166 '-Wl,-static,-pie,--no-dynamic-linker,-z,text',
167
168 # EFI has 4KiB pages.
169 '-z', 'common-page-size=4096',
170 '-z', 'max-page-size=4096',
171
172 '-z', 'noexecstack',
173 '-z', 'relro',
174 '-z', 'separate-code',
175 ]
176
177 efi_c_ld_args += cc.get_supported_link_arguments(
178 # binutils >= 2.38
179 '-Wl,-z,nopack-relative-relocs',
180 )
181
182 # efi_c_args is explicitly passed to targets so that they can override distro-provided flags
183 # that should not be used for EFI binaries.
184 efi_disabled_c_args = cc.get_supported_arguments(
185 '-fcf-protection=none',
186 '-fno-asynchronous-unwind-tables',
187 '-fno-exceptions',
188 '-fno-unwind-tables',
189 )
190 efi_override_options = [
191 'b_coverage=false',
192 'b_pgo=off',
193 ]
194
195 if get_option('b_sanitize') == 'undefined'
196 efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize-link-runtime')
197 else
198 efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize=all')
199 efi_override_options += 'b_sanitize=none'
200 endif
201
202 efi_c_args += efi_disabled_c_args
203 efi_c_ld_args += efi_disabled_c_args
204
205 if cc.get_id() == 'clang'
206 # clang is too picky sometimes.
207 efi_c_args += '-Wno-unused-command-line-argument'
208 efi_c_ld_args += '-Wno-unused-command-line-argument'
209 endif
210
211 efi_arch_c_args = {
212 'aarch64' : ['-mgeneral-regs-only'],
213 'arm' : ['-mgeneral-regs-only'],
214 # Pass -m64/32 explicitly to make building on x32 work.
215 'x86_64' : ['-m64', '-march=x86-64', '-mno-red-zone', '-mgeneral-regs-only'],
216 'x86' : ['-m32', '-march=i686', '-mgeneral-regs-only', '-malign-double'],
217 }
218 efi_arch_c_ld_args = {
219 # libgcc is not compiled with -fshort-wchar, but it does not use it anyways,
220 # so it's fine to link against it.
221 'arm' : cc.get_supported_link_arguments('-Wl,--no-wchar-size-warning'),
222 'x86_64' : ['-m64'],
223 'x86' : ['-m32'],
224 }
225
226 linker_sanity_code = 'void a(void) {}; void _start(void) { a(); }'
227 linker_sanity_args = ['-nostdlib', '-Wl,--fatal-warnings']
228 if not cc.links(linker_sanity_code,
229 name : 'linker supports -static-pie',
230 args : [linker_sanity_args, '-static-pie'])
231 error('Linker does not support -static-pie.')
232 endif
233
234 # https://github.com/llvm/llvm-project/issues/67152
235 if not cc.links(linker_sanity_code,
236 name : 'linker supports LTO with -nostdlib',
237 args : [linker_sanity_args, '-flto'])
238 efi_c_args += '-fno-lto'
239 efi_c_ld_args += '-fno-lto'
240 endif
241
242 # https://github.com/llvm/llvm-project/issues/61101
243 if efi_cpu_family_alt == 'x86' and not cc.links(linker_sanity_code,
244 name : 'linker supports LTO with -nostdlib (x86)',
245 args : [linker_sanity_args, '-flto', '-m32'])
246 efi_arch_c_args += { 'x86' : efi_arch_c_args['x86'] + '-fno-lto' }
247 efi_arch_c_ld_args += { 'x86' : efi_arch_c_ld_args['x86'] + '-fno-lto' }
248 endif
249
250 ############################################################
251
252 libefi_sources = files(
253 'console.c',
254 'device-path-util.c',
255 'devicetree.c',
256 'drivers.c',
257 'efi-string.c',
258 'graphics.c',
259 'initrd.c',
260 'log.c',
261 'measure.c',
262 'part-discovery.c',
263 'pe.c',
264 'random-seed.c',
265 'secure-boot.c',
266 'shim.c',
267 'ticks.c',
268 'util.c',
269 'vmm.c',
270 )
271
272 systemd_boot_sources = files(
273 'boot.c',
274 )
275
276 stub_sources = files(
277 'cpio.c',
278 'linux.c',
279 'splash.c',
280 'stub.c',
281 )
282
283 addon_sources = files(
284 'addon.c',
285 )
286
287 if get_option('b_sanitize') == 'undefined'
288 libefi_sources += files('ubsan.c')
289 endif
290
291 if host_machine.cpu_family() in ['x86', 'x86_64']
292 stub_sources += files('linux_x86.c')
293 endif
294
295 # BCD parser only makes sense on arches that Windows supports.
296 if host_machine.cpu_family() in ['aarch64', 'arm', 'x86_64', 'x86']
297 systemd_boot_sources += files('bcd.c')
298 endif
299
300 boot_targets = []
301 efi_elf_binaries = []
302 efi_archspecs = [
303 {
304 'arch' : efi_arch,
305 'c_args' : [
306 efi_c_args,
307 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch + '"',
308 efi_arch_c_args.get(host_machine.cpu_family(), []),
309 ],
310 'link_args' : [
311 efi_c_ld_args,
312 efi_arch_c_ld_args.get(host_machine.cpu_family(), []),
313 ],
314 },
315 ]
316 if efi_arch_alt != ''
317 efi_archspecs += {
318 'arch' : efi_arch_alt,
319 'c_args' : [
320 efi_c_args,
321 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch_alt + '"',
322 efi_arch_c_args.get(efi_cpu_family_alt, []),
323 ],
324 'link_args' : [
325 efi_c_ld_args,
326 efi_arch_c_ld_args.get(efi_cpu_family_alt, []),
327 ],
328 }
329 endif
330
331 foreach archspec : efi_archspecs
332 libefi = static_library(
333 'efi' + archspec['arch'],
334 fundamental_sources,
335 libefi_sources,
336 version_h,
337 include_directories : efi_includes,
338 c_args : archspec['c_args'],
339 gnu_symbol_visibility : 'hidden',
340 override_options : efi_override_options,
341 pic : true)
342
343 kwargs = {
344 'include_directories' : efi_includes,
345 'c_args' : archspec['c_args'],
346 'link_args' : archspec['link_args'],
347 'gnu_symbol_visibility' : 'hidden',
348 'override_options' : efi_override_options,
349 'pie' : true,
350 }
351
352 efi_elf_binaries += executable(
353 'systemd-boot' + archspec['arch'],
354 sources : [systemd_boot_sources, version_h],
355 link_with : libefi,
356 name_suffix : 'elf',
357 kwargs : kwargs)
358
359 efi_elf_binaries += executable(
360 'linux' + archspec['arch'],
361 sources : [stub_sources, version_h],
362 link_with : libefi,
363 name_suffix : 'elf.stub',
364 kwargs : kwargs)
365
366 efi_elf_binaries += executable(
367 'addon' + archspec['arch'],
368 sources : [addon_sources, version_h],
369 name_suffix : 'elf.stub',
370 kwargs : kwargs)
371 endforeach
372
373 foreach efi_elf_binary : efi_elf_binaries
374 name = efi_elf_binary.name()
375 name += name.startswith('systemd-boot') ? '.efi' : '.efi.stub'
376 # For the addon, given it's empty, we need to explicitly reserve space in the header to account for
377 # the sections that ukify will add.
378 minimum_sections = name.endswith('.stub') ? '15' : '0'
379 exe = custom_target(
380 name,
381 output : name,
382 input : efi_elf_binary,
383 install : true,
384 install_dir : bootlibdir,
385 install_tag : 'systemd-boot',
386 command : [
387 elf2efi_py,
388 '--version-major=' + meson.project_version().split('~')[0],
389 '--version-minor=0',
390 '--efi-major=1',
391 '--efi-minor=1',
392 '--subsystem=10',
393 '--minimum-sections=' + minimum_sections,
394 '--copy-sections=.sbat,.sdmagic,.osrel',
395 '@INPUT@',
396 '@OUTPUT@',
397 ])
398 boot_targets += exe
399 if name.startswith('linux')
400 boot_stubs += exe
401 endif
402
403 # This is supposed to match exactly one time
404 if name == 'addon@0@.efi.stub'.format(efi_arch)
405 efi_addon = exe.full_path()
406 endif
407 endforeach
408
409 alias_target('systemd-boot', boot_targets)