1# Copyright 2018 The Hafnium Authors. 2# 3# Use of this source code is governed by a BSD-style 4# license that can be found in the LICENSE file or at 5# https://opensource.org/licenses/BSD-3-Clause. 6 7declare_args() { 8 # Set by arch toolchain. Prefix for binutils tools. 9 tool_prefix = "" 10 11 # Enable link time optimizations 12 use_lto = true 13} 14 15# Template for embedded toolchains; there is no support for C++ or libraries. 16# Instead, use source_set to group source together. 17template("embedded_cc_toolchain") { 18 toolchain(target_name) { 19 assert(defined(invoker.cc), "\"cc\" must be defined for ${target_name}.") 20 assert(defined(invoker.ld), "\"ld\" must be defined for ${target_name}.") 21 22 # Collect extra flags from the toolchain. 23 extra_defines = "" 24 extra_cflags = "-ffunction-sections -fdata-sections" 25 if (use_lto) { 26 extra_cflags += " -flto" 27 } 28 extra_ldflags = "-pie --gc-sections" 29 30 if (defined(invoker.extra_defines)) { 31 extra_defines += " ${invoker.extra_defines}" 32 } 33 if (defined(invoker.extra_cflags)) { 34 extra_cflags += " ${invoker.extra_cflags}" 35 } 36 if (defined(invoker.extra_ldflags)) { 37 extra_ldflags += " ${invoker.extra_ldflags}" 38 } 39 40 # Define the tools. 41 tool("cc") { 42 depfile = "{{output}}.d" 43 command = "${invoker.cc} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} ${extra_cflags} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" 44 depsformat = "gcc" 45 description = "CC {{output}}" 46 outputs = [ 47 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", 48 ] 49 } 50 51 tool("asm") { 52 depfile = "{{output}}.d" 53 command = "${invoker.cc} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} ${extra_cflags} {{asmflags}} -c {{source}} -o {{output}}" 54 depsformat = "gcc" 55 description = "ASM {{output}}" 56 outputs = [ 57 "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", 58 ] 59 } 60 61 tool("link") { 62 outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 63 rspfile = "$outfile.rsp" 64 command = "${invoker.ld} ${extra_ldflags} {{ldflags}} -o $outfile --start-group @$rspfile --end-group" 65 description = "LINK $outfile" 66 default_output_dir = "{{root_out_dir}}" 67 rspfile_content = "{{inputs}}" 68 outputs = [ 69 outfile, 70 ] 71 } 72 73 tool("alink") { 74 outfile = "{{target_out_dir}}/{{target_output_name}}.a" 75 command = "rm -f $outfile && ${invoker.ar} -rc $outfile {{inputs}}" 76 description = "ALINK $outfile" 77 outputs = [ 78 outfile, 79 ] 80 } 81 82 tool("stamp") { 83 command = "touch {{output}}" 84 description = "STAMP {{output}}" 85 } 86 87 tool("copy") { 88 command = "cp -af {{source}} {{output}}" 89 description = "COPY {{source}} {{output}}" 90 } 91 92 toolchain_args = { 93 forward_variables_from(invoker.toolchain_args, "*") 94 } 95 } 96} 97 98# Specialize for clang. 99template("embedded_clang_toolchain") { 100 assert(defined(invoker.target), 101 "\"target\" must be defined for ${target_name}.") 102 assert(defined(invoker.extra_defines), 103 "\"extra_defines\" must be defined for ${target_name}") 104 assert(defined(invoker.extra_cflags), 105 "\"extra_cflags\" must be defined for ${target_name}") 106 assert(defined(invoker.extra_ldflags), 107 "\"extra_ldflags\" must be defined for ${target_name}") 108 109 embedded_cc_toolchain(target_name) { 110 cc = "clang" 111 ld = "ld.lld" 112 ar = "llvm-ar" 113 114 forward_variables_from(invoker, 115 [ 116 "extra_defines", 117 "extra_cflags", 118 "extra_ldflags", 119 ]) 120 121 # TODO: Remove //inc/system if we can stop using the version of stdatomic.h 122 # from the Android prebuilt Clang. 123 extra_cflags += " -target ${invoker.target} -fcolor-diagnostics -nostdinc" + 124 " -isystem ${toolchain_lib}/include" + " -isystem " + 125 rebase_path("//inc/system") 126 extra_ldflags += " -O2 --icf=all --fatal-warnings --color-diagnostics" 127 128 toolchain_args = { 129 if (defined(invoker.toolchain_args)) { 130 forward_variables_from(invoker.toolchain_args, "*") 131 } 132 } 133 } 134} 135 136# Specialize for mixed toolchain with clang and bfd linker. 137template("embedded_clang_bfd_toolchain") { 138 assert(defined(invoker.target), 139 "\"target\" must be defined for ${target_name}.") 140 assert(defined(invoker.tool_prefix), 141 "\"tool_prefix\" must be defined for ${target_name}.") 142 assert(defined(invoker.extra_defines), 143 "\"extra_defines\" must be defined for ${target_name}") 144 assert(defined(invoker.extra_cflags), 145 "\"extra_cflags\" must be defined for ${target_name}") 146 assert(defined(invoker.extra_ldflags), 147 "\"extra_ldflags\" must be defined for ${target_name}") 148 149 embedded_cc_toolchain(target_name) { 150 cc = "clang" 151 ld = "${invoker.tool_prefix}ld.bfd" 152 ar = "llvm-ar" 153 154 forward_variables_from(invoker, 155 [ 156 "extra_defines", 157 "extra_cflags", 158 "extra_ldflags", 159 ]) 160 extra_cflags += " -target ${invoker.target} -fcolor-diagnostics" 161 extra_ldflags += " --fatal-warnings" 162 if (use_lto) { 163 extra_ldflags += " -O2 --icf=all" 164 } 165 166 toolchain_args = { 167 if (defined(invoker.toolchain_args)) { 168 forward_variables_from(invoker.toolchain_args, "*") 169 } 170 } 171 } 172} 173 174# Expand to clang variants. 175template("embedded_platform_toolchain") { 176 assert(defined(invoker.arch), "\"arch\" must be defined for ${target_name}.") 177 assert(defined(invoker.target), 178 "\"target\" must be defined for ${target_name}.") 179 assert(defined(invoker.tool_prefix), 180 "\"tool_prefix\" must be defined for ${target_name}.") 181 assert(defined(invoker.origin_address), 182 "\"origin_address\" must be defined for ${target_name}.") 183 assert(defined(invoker.heap_pages), 184 "\"heap_pages\" must be defined for ${target_name}.") 185 assert(defined(invoker.max_cpus), 186 "\"max_cpus\" must be defined for ${target_name}.") 187 assert(defined(invoker.max_vms), 188 "\"max_vms\" must be defined for ${target_name}.") 189 assert(defined(invoker.platform_name), 190 "\"platform_name\" must be defined for ${target_name}.") 191 192 extra_defines = "" 193 extra_cflags = "-fno-builtin -ffreestanding -fpic" 194 extra_ldflags = "--defsym=ORIGIN_ADDRESS=${invoker.origin_address}" 195 if (defined(invoker.extra_defines)) { 196 extra_defines += " ${invoker.extra_defines}" 197 } 198 if (defined(invoker.extra_cflags)) { 199 extra_cflags += " ${invoker.extra_cflags}" 200 } 201 if (defined(invoker.extra_ldflags)) { 202 extra_ldflags += " ${invoker.extra_ldflags}" 203 } 204 toolchain_args = { 205 use_platform = true 206 plat_name = invoker.platform_name 207 plat_arch = invoker.arch 208 plat_heap_pages = invoker.heap_pages 209 plat_max_cpus = invoker.max_cpus 210 plat_max_vms = invoker.max_vms 211 if (defined(invoker.toolchain_args)) { 212 forward_variables_from(invoker.toolchain_args, "*") 213 } 214 } 215 216 embedded_clang_toolchain("${target_name}_clang") { 217 target = invoker.target 218 } 219 220 embedded_clang_bfd_toolchain("${target_name}_clang_bfd") { 221 target = invoker.target 222 tool_prefix = invoker.tool_prefix 223 } 224} 225 226# Specialize for different architectures. 227 228template("aarch64_common_toolchain") { 229 assert(defined(invoker.cpu), "\"cpu\" must be defined for ${target_name}.") 230 assert(defined(invoker.target), 231 "\"target\" must be defined for ${target_name}") 232 assert(defined(invoker.tool_prefix), 233 "\"tool_prefix\" must be defined for ${target_name}") 234 assert(defined(invoker.origin_address), 235 "\"origin_address\" must be defined for ${target_name}.") 236 assert(defined(invoker.console), 237 "\"console\" must be defined for ${target_name}.") 238 assert(defined(invoker.heap_pages), 239 "\"heap_pages\" must be defined for ${target_name}.") 240 assert(defined(invoker.max_cpus), 241 "\"max_cpus\" must be defined for ${target_name}.") 242 assert(defined(invoker.max_vms), 243 "\"max_vms\" must be defined for ${target_name}.") 244 if (invoker.gic_version == 3 || invoker.gic_version == 4) { 245 assert(defined(invoker.gicd_base_address), 246 "\"gicd_base_address\" must be defined for ${target_name}.") 247 assert(defined(invoker.gicr_base_address), 248 "\"gicr_base_address\" must be defined for ${target_name}.") 249 assert(defined(invoker.gicr_frames), 250 "\"gicr_frames\" must be defined for ${target_name}.") 251 } 252 assert(defined(invoker.platform_name), 253 "\"platform_name\" must be defined for ${target_name}.") 254 255 embedded_platform_toolchain(target_name) { 256 forward_variables_from(invoker, 257 [ 258 "origin_address", 259 "heap_pages", 260 "max_cpus", 261 "max_vms", 262 "platform_name", 263 "extra_ldflags", 264 ]) 265 arch = "aarch64" 266 target = invoker.target 267 tool_prefix = invoker.tool_prefix 268 extra_cflags = "-mcpu=${invoker.cpu} -mstrict-align" 269 if (defined(invoker.extra_cflags)) { 270 extra_cflags += " ${invoker.extra_cflags}" 271 } 272 273 extra_defines = "" 274 if (defined(invoker.extra_defines)) { 275 extra_defines += " ${invoker.extra_defines}" 276 } 277 278 if (invoker.gic_version > 0) { 279 extra_defines += " -DGIC_VERSION=${invoker.gic_version}" 280 } 281 if (invoker.gic_version == 3 || invoker.gic_version == 4) { 282 extra_defines += " -DGICD_BASE=${invoker.gicd_base_address} -DGICR_BASE=${invoker.gicr_base_address} -DGICR_FRAMES=${invoker.gicr_frames}" 283 } 284 if (defined(invoker.gic_enable_espi)) { 285 extra_defines += " -DGIC_EXT_INTID=${invoker.gic_enable_espi}" 286 } 287 if (defined(invoker.branch_protection)) { 288 extra_cflags += " -mbranch-protection=${invoker.branch_protection}" 289 extra_defines += " -DBRANCH_PROTECTION=1" 290 } 291 292 toolchain_args = { 293 plat_boot_flow = invoker.boot_flow 294 plat_console = invoker.console 295 plat_iommu = invoker.iommu 296 if (defined(invoker.stdout)) { 297 stdout = invoker.stdout 298 } 299 if (defined(invoker.max_image_size)) { 300 plat_max_image_size = invoker.max_image_size 301 } 302 forward_variables_from(invoker.toolchain_args, "*") 303 } 304 305 if (defined(toolchain_args.enable_mte)) { 306 extra_cflags += " -march=armv8.5-a+memtag" 307 extra_cflags += " -fsanitize=memtag" 308 extra_defines += " -DENABLE_MTE" 309 } 310 } 311} 312 313template("aarch64_toolchain") { 314 aarch64_common_toolchain("${target_name}") { 315 forward_variables_from(invoker, "*") 316 target = "aarch64-none-eabi" 317 tool_prefix = "aarch64-linux-gnu-" # TODO: this isn't right for bare metal but it works. 318 platform_name = target_name 319 } 320} 321 322template("aarch64_toolchains") { 323 aarch64_toolchain("${target_name}") { 324 forward_variables_from(invoker, 325 [ 326 "origin_address", 327 "boot_flow", 328 "console", 329 "iommu", 330 "gic_version", 331 "gic_enable_espi", 332 "gicd_base_address", 333 "gicr_base_address", 334 "gicr_frames", 335 "heap_pages", 336 "max_cpus", 337 "max_image_size", 338 "max_vms", 339 "toolchain_args", 340 "branch_protection", 341 ]) 342 cpu = "${invoker.cpu}+nofp" 343 344 # Add a macro so files can tell whether they are not being built for a VM. 345 extra_defines = " -DVM_TOOLCHAIN=0" 346 extra_cflags = " -mgeneral-regs-only" 347 } 348 349 # Toolchain for building test VMs which run under Hafnium. 350 aarch64_toolchain("${target_name}_vm") { 351 forward_variables_from(invoker, 352 [ 353 "origin_address", 354 "gic_version", 355 "gic_enable_espi", 356 "gicd_base_address", 357 "gicr_base_address", 358 "gicr_frames", 359 "max_cpus", 360 "toolchain_args", 361 "console", 362 "branch_protection", 363 ]) 364 cpu = "${invoker.cpu}+fp" 365 boot_flow = "//src/arch/fake:boot_flow" 366 iommu = "//src/iommu:absent" 367 stdout = "//src/arch/aarch64/hftest:stdout" 368 369 # Nonsense values because they are required but shouldn't be used. 370 heap_pages = 0 371 max_vms = 0 372 373 # Add a macro so files can tell whether they are being built for a VM. 374 extra_defines = " -DVM_TOOLCHAIN=1" 375 } 376} 377