]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/meson.build
Merge pull request #31000 from flatcar-hub/krnowak/mutable-overlays
[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_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 # Pass -m64/32 explicitly to make building on x32 work.
216 'x86_64' : ['-m64', '-march=x86-64', '-mno-red-zone', '-mgeneral-regs-only'],
217 'x86' : ['-m32', '-march=i686', '-mgeneral-regs-only', '-malign-double'],
218 }
219 efi_arch_c_ld_args = {
220 # libgcc is not compiled with -fshort-wchar, but it does not use it anyways,
221 # so it's fine to link against it.
222 'arm' : cc.get_supported_link_arguments('-Wl,--no-wchar-size-warning'),
223 'x86_64' : ['-m64'],
224 'x86' : ['-m32'],
225 }
226
227 linker_sanity_code = 'void a(void) {}; void _start(void) { a(); }'
228 linker_sanity_args = ['-nostdlib', '-Wl,--fatal-warnings']
229 if not cc.links(linker_sanity_code,
230 name : 'linker supports -static-pie',
231 args : [linker_sanity_args, '-static-pie'])
232 error('Linker does not support -static-pie.')
233 endif
234
235 # https://github.com/llvm/llvm-project/issues/67152
236 if not cc.links(linker_sanity_code,
237 name : 'linker supports LTO with -nostdlib',
238 args : [linker_sanity_args, '-flto'])
239 efi_c_args += '-fno-lto'
240 efi_c_ld_args += '-fno-lto'
241 endif
242
243 # https://github.com/llvm/llvm-project/issues/61101
244 if efi_cpu_family_alt == 'x86' and not cc.links(linker_sanity_code,
245 name : 'linker supports LTO with -nostdlib (x86)',
246 args : [linker_sanity_args, '-flto', '-m32'])
247 efi_arch_c_args += { 'x86' : efi_arch_c_args['x86'] + '-fno-lto' }
248 efi_arch_c_ld_args += { 'x86' : efi_arch_c_ld_args['x86'] + '-fno-lto' }
249 endif
250
251 ############################################################
252
253 libefi_sources = files(
254 'console.c',
255 'device-path-util.c',
256 'devicetree.c',
257 'drivers.c',
258 'efi-string.c',
259 'graphics.c',
260 'initrd.c',
261 'log.c',
262 'measure.c',
263 'part-discovery.c',
264 'pe.c',
265 'random-seed.c',
266 'secure-boot.c',
267 'shim.c',
268 'ticks.c',
269 'util.c',
270 'vmm.c',
271 )
272
273 systemd_boot_sources = files(
274 'boot.c',
275 )
276
277 stub_sources = files(
278 'cpio.c',
279 'linux.c',
280 'splash.c',
281 'stub.c',
282 )
283
284 addon_sources = files(
285 'addon.c',
286 )
287
288 if get_option('b_sanitize') == 'undefined'
289 libefi_sources += files('ubsan.c')
290 endif
291
292 if host_machine.cpu_family() in ['x86', 'x86_64']
293 stub_sources += files('linux_x86.c')
294 endif
295
296 # BCD parser only makes sense on arches that Windows supports.
297 if host_machine.cpu_family() in ['aarch64', 'arm', 'x86_64', 'x86']
298 systemd_boot_sources += files('bcd.c')
299 endif
300
301 boot_targets = []
302 efi_elf_binaries = []
303 efi_archspecs = [
304 {
305 'arch' : efi_arch,
306 'c_args' : [
307 efi_c_args,
308 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch + '"',
309 efi_arch_c_args.get(host_machine.cpu_family(), []),
310 ],
311 'link_args' : [
312 efi_c_ld_args,
313 efi_arch_c_ld_args.get(host_machine.cpu_family(), []),
314 ],
315 },
316 ]
317 if efi_arch_alt != ''
318 efi_archspecs += {
319 'arch' : efi_arch_alt,
320 'c_args' : [
321 efi_c_args,
322 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch_alt + '"',
323 efi_arch_c_args.get(efi_cpu_family_alt, []),
324 ],
325 'link_args' : [
326 efi_c_ld_args,
327 efi_arch_c_ld_args.get(efi_cpu_family_alt, []),
328 ],
329 }
330 endif
331
332 foreach archspec : efi_archspecs
333 libefi = static_library(
334 'efi' + archspec['arch'],
335 fundamental_sources,
336 libefi_sources,
337 version_h,
338 include_directories : efi_includes,
339 c_args : archspec['c_args'],
340 gnu_symbol_visibility : 'hidden',
341 override_options : efi_override_options,
342 pic : true)
343
344 kwargs = {
345 'include_directories' : efi_includes,
346 'c_args' : archspec['c_args'],
347 'link_args' : archspec['link_args'],
348 'gnu_symbol_visibility' : 'hidden',
349 'override_options' : efi_override_options,
350 'pie' : true,
351 }
352
353 efi_elf_binaries += executable(
354 'systemd-boot' + archspec['arch'],
355 sources : [systemd_boot_sources, version_h],
356 link_with : libefi,
357 name_suffix : 'elf',
358 kwargs : kwargs)
359
360 efi_elf_binaries += executable(
361 'linux' + archspec['arch'],
362 sources : [stub_sources, version_h],
363 link_with : libefi,
364 name_suffix : 'elf.stub',
365 kwargs : kwargs)
366
367 efi_elf_binaries += executable(
368 'addon' + archspec['arch'],
369 sources : [addon_sources, version_h],
370 name_suffix : 'elf.stub',
371 kwargs : kwargs)
372 endforeach
373
374 foreach efi_elf_binary : efi_elf_binaries
375 name = efi_elf_binary.name()
376 name += name.startswith('systemd-boot') ? '.efi' : '.efi.stub'
377 # For the addon, given it's empty, we need to explicitly reserve space in the header to account for
378 # the sections that ukify will add.
379 minimum_sections = name.endswith('.stub') ? '15' : '0'
380 exe = custom_target(
381 name,
382 output : name,
383 input : efi_elf_binary,
384 install : true,
385 install_dir : bootlibdir,
386 install_tag : 'systemd-boot',
387 command : [
388 elf2efi_py,
389 '--version-major=' + meson.project_version().split('~')[0],
390 '--version-minor=0',
391 '--efi-major=1',
392 '--efi-minor=1',
393 '--subsystem=10',
394 '--minimum-sections=' + minimum_sections,
395 '--copy-sections=.sbat,.sdmagic,.osrel',
396 '@INPUT@',
397 '@OUTPUT@',
398 ])
399 boot_targets += exe
400 if name.startswith('linux')
401 boot_stubs += exe
402 endif
403
404 # This is supposed to match exactly one time
405 if name == 'addon@0@.efi.stub'.format(efi_arch)
406 efi_addon = exe.full_path()
407 endif
408 endforeach
409
410 alias_target('systemd-boot', boot_targets)