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