1 # SPDX-License-Identifier: LGPL-2.1-or-later
3 efi_config_h_dir = meson.current_build_dir()
6 libefitest = static_library(
12 build_by_default : false,
13 include_directories : [
15 include_directories('.'),
17 dependencies : userspace)
25 efi_test_template = test_template + efitest_base
26 efi_fuzz_template = fuzz_template + efitest_base
30 'sources' : files('test-bcd.c'),
31 'dependencies' : libzstd,
32 'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_ZSTD'],
35 'sources' : files('test-efi-string.c'),
36 'conditions' : ['ENABLE_BOOTLOADER'],
39 'sources' : files('fuzz-bcd.c'),
42 'sources' : files('fuzz-efi-string.c'),
45 'sources' : files('fuzz-efi-osrel.c'),
48 'sources' : files('fuzz-efi-printf.c'),
52 if conf.get('ENABLE_BOOTLOADER') != 1
56 efi_conf = configuration_data()
57 efi_conf.set10('ENABLE_TPM', get_option('tpm'))
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()))
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')
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()
86 error('Required @0@ option not set and autodetection failed'.format(sbatvar[0]))
88 efi_conf.set_quoted(sbatvar[0].underscorify().to_upper(), value)
91 pkgname = get_option('sbat-distro-pkgname')
93 pkgname = meson.project_name()
95 efi_conf.set_quoted('SBAT_DISTRO_PKGNAME', pkgname)
97 pkgver = get_option('sbat-distro-version')
99 # This is determined during build, not configuration, so we can't display it yet.
100 efi_conf.set('SBAT_DISTRO_VERSION', 'GIT_VERSION')
102 efi_conf.set_quoted('SBAT_DISTRO_VERSION', pkgver)
106 summary({'UEFI architectures' : efi_arch + (efi_arch_alt == '' ? '' : ', ' + efi_arch_alt)},
109 if efi_conf.get('SBAT_DISTRO', '') != ''
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')},
120 output : 'efi_config.h',
121 configuration : efi_conf)
123 ############################################################
128 include_directories('.'),
134 '-fno-strict-aliasing',
136 '-include', 'efi_config.h',
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',
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'
157 '-Wl,--entry=efi_main',
158 '-Wl,--fatal-warnings',
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',
169 # EFI has 4KiB pages.
170 '-z', 'common-page-size=4096',
171 '-z', 'max-page-size=4096',
175 '-z', 'separate-code',
178 efi_c_ld_args += cc.get_supported_link_arguments(
180 '-Wl,-z,nopack-relative-relocs',
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',
189 '-fno-unwind-tables',
191 efi_override_options = [
196 if get_option('b_sanitize') == 'undefined'
197 efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize-link-runtime')
199 efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize=all')
200 efi_override_options += 'b_sanitize=none'
203 efi_c_args += efi_disabled_c_args
204 efi_c_ld_args += efi_disabled_c_args
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'
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'],
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'),
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.')
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'
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' }
251 ############################################################
253 libefi_sources = files(
255 'device-path-util.c',
273 systemd_boot_sources = files(
277 stub_sources = files(
284 addon_sources = files(
288 if get_option('b_sanitize') == 'undefined'
289 libefi_sources += files('ubsan.c')
292 if host_machine.cpu_family() in ['x86', 'x86_64']
293 stub_sources += files('linux_x86.c')
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')
302 efi_elf_binaries = []
308 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch + '"',
309 efi_arch_c_args.get(host_machine.cpu_family(), []),
313 efi_arch_c_ld_args.get(host_machine.cpu_family(), []),
317 if efi_arch_alt != ''
319 'arch' : efi_arch_alt,
322 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch_alt + '"',
323 efi_arch_c_args.get(efi_cpu_family_alt, []),
327 efi_arch_c_ld_args.get(efi_cpu_family_alt, []),
332 foreach archspec : efi_archspecs
333 libefi = static_library(
334 'efi' + archspec['arch'],
338 include_directories : efi_includes,
339 c_args : archspec['c_args'],
340 gnu_symbol_visibility : 'hidden',
341 override_options : efi_override_options,
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,
353 efi_elf_binaries += executable(
354 'systemd-boot' + archspec['arch'],
355 sources : [systemd_boot_sources, version_h],
360 efi_elf_binaries += executable(
361 'linux' + archspec['arch'],
362 sources : [stub_sources, version_h],
364 name_suffix : 'elf.stub',
367 efi_elf_binaries += executable(
368 'addon' + archspec['arch'],
369 sources : [addon_sources, version_h],
370 name_suffix : 'elf.stub',
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'
383 input : efi_elf_binary,
385 install_dir : bootlibdir,
386 install_tag : 'systemd-boot',
389 '--version-major=' + meson.project_version().split('~')[0],
394 '--minimum-sections=' + minimum_sections,
395 '--copy-sections=.sbat,.sdmagic,.osrel',
400 if name.startswith('linux')
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()
410 alias_target('systemd-boot', boot_targets)