]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/meson.build
Merge pull request #28567 from yuwata/meson-versiondep
[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 if efi_arch != ''
7 libefitest = static_library(
8 'efitest',
9 files(
10 'bcd.c',
11 'efi-string.c',
12 ),
13 build_by_default : false,
14 include_directories : [
15 basic_includes,
16 include_directories('.'),
17 ],
18 dependencies : userspace)
19
20 efitest_base = {
21 'link_with' : [
22 libefitest,
23 libshared,
24 ],
25 }
26
27 tests += [
28 {
29 'sources' : files('test-bcd.c'),
30 'dependencies' : libzstd,
31 'condition' : 'HAVE_ZSTD',
32 'base' : efitest_base,
33 },
34 {
35 'sources' : files('test-efi-string.c'),
36 'base' : efitest_base,
37 },
38 ]
39 fuzzers += [
40 {
41 'sources' : files('fuzz-bcd.c'),
42 'base' : efitest_base,
43 },
44 {
45 'sources' : files('fuzz-efi-string.c'),
46 'base' : efitest_base,
47 },
48 {
49 'sources' : files('fuzz-efi-printf.c'),
50 'base' : efitest_base,
51 },
52 ]
53 endif
54
55 if conf.get('ENABLE_BOOTLOADER') != 1
56 subdir_done()
57 endif
58
59 efi_conf = configuration_data()
60 efi_conf.set10('ENABLE_TPM', get_option('tpm'))
61
62 foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit']
63 c = get_option('efi-' + ctype).split(',')
64 efi_conf.set(ctype.underscorify().to_upper(), 'EFI_TEXT_ATTR(@0@, @1@)'.format(
65 'EFI_' + c[0].strip().underscorify().to_upper(),
66 'EFI_' + c[1].strip().underscorify().to_upper()))
67 endforeach
68
69 if meson.is_cross_build() and get_option('sbat-distro') == 'auto'
70 warning('Auto detection of SBAT information not supported when cross-building, disabling SBAT.')
71 elif get_option('sbat-distro') != ''
72 efi_conf.set_quoted('SBAT_PROJECT', meson.project_name())
73 efi_conf.set_quoted('PROJECT_VERSION', meson.project_version())
74 efi_conf.set('PROJECT_URL', conf.get('PROJECT_URL'))
75 if get_option('sbat-distro-generation') < 1
76 error('SBAT Distro Generation must be a positive integer')
77 endif
78 efi_conf.set('SBAT_DISTRO_GENERATION', get_option('sbat-distro-generation'))
79 foreach sbatvar : [['sbat-distro', 'ID'],
80 ['sbat-distro-summary', 'NAME'],
81 ['sbat-distro-url', 'BUG_REPORT_URL']]
82 value = get_option(sbatvar[0])
83 if (value == '' or value == 'auto') and not meson.is_cross_build()
84 cmd = 'if [ -e /etc/os-release ]; then . /etc/os-release; else . /usr/lib/os-release; fi; echo $@0@'.format(sbatvar[1])
85 value = run_command(sh, '-c', cmd, check: true).stdout().strip()
86 endif
87 if value == ''
88 error('Required @0@ option not set and autodetection failed'.format(sbatvar[0]))
89 endif
90 efi_conf.set_quoted(sbatvar[0].underscorify().to_upper(), value)
91 endforeach
92
93 pkgname = get_option('sbat-distro-pkgname')
94 if pkgname == ''
95 pkgname = meson.project_name()
96 endif
97 efi_conf.set_quoted('SBAT_DISTRO_PKGNAME', pkgname)
98
99 pkgver = get_option('sbat-distro-version')
100 if pkgver == ''
101 pkgver = version_tag
102 endif
103 efi_conf.set_quoted('SBAT_DISTRO_VERSION', pkgver)
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 = [fundamental_include, include_directories('.')]
126
127 efi_c_args = [
128 '-DSD_BOOT=1',
129 '-ffreestanding',
130 '-fno-strict-aliasing',
131 '-fshort-wchar',
132 '-include', 'efi_config.h',
133 ]
134
135 efi_c_args += cc.get_supported_arguments(
136 '-fwide-exec-charset=UCS2',
137 # gcc docs says this is required for ms_abi to work correctly.
138 '-maccumulate-outgoing-args',
139 '-mstack-protector-guard=global',
140 )
141
142 # Debug information has little value in release builds as no normal human being knows
143 # how to attach a debugger to EFI binaries running on real hardware. Anyone who does
144 # certainly has the means to do their own dev build.
145 if get_option('mode') == 'developer' and get_option('debug')
146 efi_c_args += '-DEFI_DEBUG'
147 endif
148
149 efi_c_ld_args = [
150 # We only support bfd. gold is going away, lld has issues with LTO on x86
151 # and mold does not support linker scripts.
152 '-fuse-ld=bfd',
153
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 seem to be missing sometimes.
161 '-Wl,--no-dynamic-linker',
162 '-z', 'text',
163
164 # EFI has 4KiB pages.
165 '-z', 'common-page-size=4096',
166 '-z', 'max-page-size=4096',
167
168 '-z', 'noexecstack',
169 '-z', 'norelro',
170 '-T' + elf2efi_lds,
171 ]
172
173 # On CentOS 8 the nopack-relative-relocs linker flag is not supported, and we get:
174 # /usr/bin/ld.bfd: warning: -z nopack-relative-relocs ignored
175 efi_c_ld_args += cc.get_supported_link_arguments('-Wl,-z,nopack-relative-relocs')
176
177 # efi_c_args is explicitly passed to targets so that they can override distro-provided flags
178 # that should not be used for EFI binaries.
179 efi_disabled_c_args = cc.get_supported_arguments(
180 '-fcf-protection=none',
181 '-fno-asynchronous-unwind-tables',
182 '-fno-exceptions',
183 '-fno-unwind-tables',
184 )
185 efi_override_options = [
186 'b_coverage=false',
187 'b_pgo=off',
188 ]
189
190 if get_option('b_sanitize') == 'undefined'
191 efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize-link-runtime')
192 else
193 efi_disabled_c_args += cc.get_supported_arguments('-fno-sanitize=all')
194 efi_override_options += 'b_sanitize=none'
195 endif
196
197 efi_c_args += efi_disabled_c_args
198 efi_c_ld_args += efi_disabled_c_args
199
200 if cc.get_id() == 'clang'
201 # clang is too picky sometimes.
202 efi_c_args += '-Wno-unused-command-line-argument'
203 efi_c_ld_args += '-Wno-unused-command-line-argument'
204 endif
205
206 efi_arch_c_args = {
207 'aarch64' : ['-mgeneral-regs-only'],
208 'arm' : ['-mgeneral-regs-only'],
209 # Pass -m64/32 explicitly to make building on x32 work.
210 'x86_64' : ['-m64', '-march=x86-64', '-mno-red-zone', '-mgeneral-regs-only'],
211 'x86' : ['-m32', '-march=i686', '-mgeneral-regs-only', '-malign-double'],
212 }
213 efi_arch_c_ld_args = {
214 # libgcc is not compiled with -fshort-wchar, but it does not use it anyways,
215 # so it's fine to link against it.
216 'arm' : ['-Wl,--no-wchar-size-warning'],
217 'x86_64' : ['-m64'],
218 'x86' : ['-m32'],
219 }
220
221 ############################################################
222
223 libefi_sources = files(
224 'console.c',
225 'device-path-util.c',
226 'devicetree.c',
227 'drivers.c',
228 'efi-string.c',
229 'graphics.c',
230 'initrd.c',
231 'log.c',
232 'measure.c',
233 'part-discovery.c',
234 'pe.c',
235 'random-seed.c',
236 'secure-boot.c',
237 'shim.c',
238 'ticks.c',
239 'util.c',
240 'vmm.c',
241 )
242
243 systemd_boot_sources = files(
244 'boot.c',
245 )
246
247 stub_sources = files(
248 'cpio.c',
249 'linux.c',
250 'splash.c',
251 'stub.c',
252 )
253
254 addon_sources = files(
255 'addon.c',
256 )
257
258 if get_option('b_sanitize') == 'undefined'
259 libefi_sources += files('ubsan.c')
260 endif
261
262 if host_machine.cpu_family() in ['x86', 'x86_64']
263 stub_sources += files('linux_x86.c')
264 endif
265
266 # BCD parser only makes sense on arches that Windows supports.
267 if host_machine.cpu_family() in ['aarch64', 'arm', 'x86_64', 'x86']
268 systemd_boot_sources += files('bcd.c')
269 endif
270
271 boot_targets = []
272 efi_elf_binaries = []
273 efi_archspecs = [
274 {
275 'arch' : efi_arch,
276 'c_args' : [
277 efi_c_args,
278 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch + '"',
279 efi_arch_c_args.get(host_machine.cpu_family(), []),
280 ],
281 'link_args' : [
282 efi_c_ld_args,
283 efi_arch_c_ld_args.get(host_machine.cpu_family(), []),
284 ],
285 },
286 ]
287 if efi_arch_alt != ''
288 efi_archspecs += {
289 'arch' : efi_arch_alt,
290 'c_args' : [
291 efi_c_args,
292 '-DEFI_MACHINE_TYPE_NAME="' + efi_arch_alt + '"',
293 efi_arch_c_args.get(efi_cpu_family_alt, []),
294 ],
295 'link_args' : [
296 efi_c_ld_args,
297 efi_arch_c_ld_args.get(efi_cpu_family_alt, []),
298 ],
299 }
300 endif
301
302 foreach archspec : efi_archspecs
303 libefi = static_library(
304 'efi' + archspec['arch'],
305 fundamental_sources,
306 libefi_sources,
307 include_directories : efi_includes,
308 c_args : archspec['c_args'],
309 dependencies : versiondep,
310 gnu_symbol_visibility : 'hidden',
311 override_options : efi_override_options,
312 pic : true)
313
314 kwargs = {
315 'include_directories' : efi_includes,
316 'c_args' : archspec['c_args'],
317 'link_args' : archspec['link_args'],
318 'link_with' : libefi,
319 'link_depends' : elf2efi_lds,
320 'dependencies' : versiondep,
321 'gnu_symbol_visibility' : 'hidden',
322 'override_options' : efi_override_options,
323 'pie' : true,
324 }
325
326 efi_elf_binaries += executable(
327 'systemd-boot' + archspec['arch'],
328 sources : systemd_boot_sources,
329 name_suffix : 'elf',
330 kwargs : kwargs)
331
332 efi_elf_binaries += executable(
333 'linux' + archspec['arch'],
334 sources : stub_sources,
335 name_suffix : 'elf.stub',
336 kwargs : kwargs)
337
338 efi_elf_binaries += executable(
339 'addon' + archspec['arch'],
340 sources : addon_sources,
341 name_suffix : 'elf.stub',
342 kwargs : kwargs)
343 endforeach
344
345 foreach efi_elf_binary : efi_elf_binaries
346 name = efi_elf_binary.name()
347 name += name.startswith('systemd-boot') ? '.efi' : '.efi.stub'
348 # For the addon, given it's empty, we need to explicitly reserve space in the header to account for
349 # the sections that ukify will add.
350 minimum_sections = name.startswith('addon') ? '7' : '0'
351 exe = custom_target(
352 name,
353 output : name,
354 input : efi_elf_binary,
355 install : true,
356 install_dir : bootlibdir,
357 install_tag : 'systemd-boot',
358 command : [
359 elf2efi_py,
360 '--version-major=' + meson.project_version(),
361 '--version-minor=0',
362 '--efi-major=1',
363 '--efi-minor=1',
364 '--subsystem=10',
365 '--minimum-sections=' + minimum_sections,
366 '@INPUT@',
367 '@OUTPUT@',
368 ])
369 boot_targets += exe
370 if name.startswith('linux')
371 boot_stubs += exe
372 endif
373
374 # This is supposed to match exactly one time
375 if name == 'addon@0@.efi.stub'.format(efi_arch)
376 efi_addon = exe.full_path()
377 endif
378 endforeach
379
380 alias_target('systemd-boot', boot_targets)