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_cflags,
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 # 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'],
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'),
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.')
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'
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' }
253 ############################################################
255 libefi_sources = files(
257 'device-path-util.c',
275 systemd_boot_sources = files(
279 stub_sources = files(
286 addon_sources = files(
290 if get_option('b_sanitize') == 'undefined'
291 libefi_sources += files('ubsan.c')
294 if host_machine.cpu_family() in ['x86', 'x86_64']
295 stub_sources += files('linux_x86.c')
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')
304 efi_elf_binaries = []
310 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch + '"',
311 efi_arch_c_args.get(host_machine.cpu_family(), []),
315 efi_arch_c_ld_args.get(host_machine.cpu_family(), []),
319 if efi_arch_alt != ''
321 'arch' : efi_arch_alt,
324 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch_alt + '"',
325 efi_arch_c_args.get(efi_cpu_family_alt, []),
329 efi_arch_c_ld_args.get(efi_cpu_family_alt, []),
334 foreach archspec : efi_archspecs
335 libefi = static_library(
336 'efi' + archspec['arch'],
340 include_directories : efi_includes,
341 c_args : archspec['c_args'],
342 gnu_symbol_visibility : 'hidden',
343 override_options : efi_override_options,
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,
355 efi_elf_binaries += executable(
356 'systemd-boot' + archspec['arch'],
357 sources : [systemd_boot_sources, version_h],
362 efi_elf_binaries += executable(
363 'linux' + archspec['arch'],
364 sources : [stub_sources, version_h],
366 name_suffix : 'elf.stub',
369 efi_elf_binaries += executable(
370 'addon' + archspec['arch'],
371 sources : [addon_sources, version_h],
372 name_suffix : 'elf.stub',
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'
385 input : efi_elf_binary,
387 install_dir : bootlibdir,
388 install_tag : 'systemd-boot',
391 '--version-major=' + meson.project_version().split('~')[0],
396 '--minimum-sections=' + minimum_sections,
397 '--copy-sections=.sbat,.sdmagic,.osrel',
402 if name.startswith('linux')
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()
412 alias_target('systemd-boot', boot_targets)