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 7import("//build/toolchain/embedded.gni") 8import("//build/toolchain/platform.gni") 9 10# Build image, link to an ELF file then convert to plain binary. 11template("image_binary") { 12 assert(defined(invoker.image_name), 13 "image_binary() must specify an \"image_name\" value") 14 15 output_root = "" 16 if (defined(invoker.output_path)) { 17 output_root += "${invoker.output_path}/" 18 } 19 output_root += invoker.image_name 20 21 file_root = "${root_out_dir}/${output_root}" 22 elf_file = "${file_root}.elf" 23 bin_file = "${file_root}.bin" 24 25 elf_target = "${target_name}__elf" 26 checked_elf_target = "${target_name}__checked_elf" 27 28 # Link objects together 29 executable(elf_target) { 30 forward_variables_from(invoker, 31 [ 32 "cflags", 33 "cflags_c", 34 "defines", 35 "deps", 36 "include_dirs", 37 "public_configs", 38 "public_deps", 39 "sources", 40 "testonly", 41 ]) 42 output_name = "${output_root}.elf" 43 inputs = [ 44 rebase_path("//build/image/image.ld"), 45 ] 46 ldflags = [ 47 "-T", 48 rebase_path("//build/image/image.ld"), 49 ] 50 visibility = [ 51 ":${checked_elf_target}", 52 ":${invoker.target_name}", 53 ] 54 } 55 56 # Analyze the generated ELF file and check that assembly-level fixes, e.g. 57 # for CPU errata, have been properly applied. 58 action(checked_elf_target) { 59 forward_variables_from(invoker, [ "testonly" ]) 60 stamp_file = elf_file + "_check.stamp" 61 62 script = "//build/image/check_elf.py" 63 deps = [ 64 ":${elf_target}", 65 ] 66 args = [ 67 rebase_path(elf_file), 68 rebase_path(stamp_file), 69 "--max-image-size", 70 "$plat_max_image_size", 71 ] 72 outputs = [ 73 stamp_file, 74 ] 75 visibility = [ ":${invoker.target_name}" ] 76 } 77 78 action(target_name) { 79 forward_variables_from(invoker, [ "testonly" ]) 80 81 script = "//build/image/convert_to_binary.py" 82 83 if (defined(invoker.check_binary) && invoker.check_binary == true) { 84 deps = [ 85 ":${checked_elf_target}", 86 ] 87 } else { 88 deps = [ 89 ":${elf_target}", 90 ] 91 } 92 args = [ 93 "--input", 94 rebase_path(elf_file), 95 "--output", 96 rebase_path(bin_file), 97 ] 98 outputs = [ 99 bin_file, 100 ] 101 } 102} 103 104# Helper to build a hypervisor image 105template("hypervisor") { 106 image_binary(target_name) { 107 forward_variables_from(invoker, 108 [ 109 "cflags", 110 "cflags_c", 111 "defines", 112 "deps", 113 "public_deps", 114 "sources", 115 "testonly", 116 ]) 117 image_name = target_name 118 119 # Perform checks on the generated binary to prevent regressing on some 120 # classes of bugs, typically CPU erratas. 121 check_binary = true 122 } 123} 124 125# Helper to build a virtual machine kernel 126template("vm_kernel") { 127 image_binary(target_name) { 128 forward_variables_from(invoker, 129 [ 130 "cflags", 131 "cflags_c", 132 "defines", 133 "deps", 134 "include_dirs", 135 "public_configs", 136 "public_deps", 137 "sources", 138 "testonly", 139 ]) 140 output_path = rebase_path(".", root_out_dir, target_out_dir) 141 image_name = target_name 142 } 143} 144 145# Build the initial RAM disk for the Linux VM. 146template("linux_initrd") { 147 initrd_base = "${target_out_dir}/${target_name}/initrd" 148 initrd_file = "${initrd_base}.img" 149 initrd_staging = "${initrd_base}" 150 151 copy_sources = [] 152 copy_deps = [] 153 154 # Add the files that need to be packaged into the RAM disk. The information 155 # about these files is encoded in lists with the following elements: 156 # 157 # - Source file: the target will have the same name as the source file. 158 # - Build target for the file (dependency) 159 foreach(file, invoker.files) { 160 copy_sources += [ file[0] ] 161 copy_deps += [ file[1] ] 162 } 163 164 copy("${target_name}__staging") { 165 forward_variables_from(invoker, [ "testonly" ]) 166 sources = copy_sources 167 deps = copy_deps 168 outputs = [ 169 "${initrd_staging}/{{source_file_part}}", 170 ] 171 } 172 173 action(target_name) { 174 forward_variables_from(invoker, [ "testonly" ]) 175 script = "//build/image/generate_linux_initrd.py" 176 args = [ 177 "--staging", 178 rebase_path(initrd_staging), 179 "--output", 180 rebase_path(initrd_file), 181 ] 182 deps = [ 183 ":${target_name}__staging", 184 ] 185 outputs = [ 186 initrd_file, 187 ] 188 } 189} 190 191template("device_tree") { 192 action(target_name) { 193 forward_variables_from(invoker, 194 [ 195 "testonly", 196 "deps", 197 ]) 198 script = "//build/image/dtc.py" 199 200 sources = [ 201 invoker.source, 202 ] 203 outputs = [ 204 invoker.output, 205 ] 206 args = [ 207 "compile", 208 "-i", 209 rebase_path(sources[0]), 210 "-o", 211 rebase_path(outputs[0]), 212 ] 213 } 214} 215 216template("fdt_overlay") { 217 action(target_name) { 218 forward_variables_from(invoker, 219 [ 220 "testonly", 221 "deps", 222 ]) 223 script = "//build/image/dtc.py" 224 225 sources = [ 226 invoker.base, 227 invoker.overlay, 228 ] 229 outputs = [ 230 invoker.output, 231 ] 232 args = [ 233 "overlay", 234 rebase_path(outputs[0]), 235 rebase_path(sources[0]), 236 rebase_path(sources[1]), 237 ] 238 } 239} 240 241template("incbin") { 242 source_set(target_name) { 243 forward_variables_from(invoker, 244 [ 245 "testonly", 246 "deps", 247 ]) 248 249 sources = [ 250 "//build/image/incbin.S", 251 ] 252 inputs = invoker.sources 253 defines = [ 254 "SECTION_NAME=" + invoker.section, 255 "FILE_PATH=\"" + rebase_path(inputs[0]) + "\"", 256 ] 257 } 258} 259 260template("incbin_target") { 261 incbin(target_name) { 262 forward_variables_from(invoker, 263 [ 264 "testonly", 265 "deps", 266 "section", 267 ]) 268 target_outputs = get_target_outputs(invoker.target) 269 target_file = target_outputs[0] 270 sources = [ 271 target_file, 272 ] 273 deps = [ 274 invoker.target, 275 ] 276 } 277} 278 279# Generate the manifest for the hypervisor and apply overlay if specified. 280template("manifest") { 281 # Check if the invoker specified an overlay for the manifest. 282 if (defined(invoker.overlay) && invoker.overlay != "") { 283 base_out_dir = invoker.base_out_dir 284 285 base_target = "${target_name}__manifest_base" 286 base_file = "${base_out_dir}/manifest_base.dtb" 287 overlay_target = "${target_name}__manifest_overlay" 288 overlay_file = "${base_out_dir}/manifest_overlay.dtbo" 289 290 # Compile the base manifest. 291 device_tree(base_target) { 292 source = invoker.source 293 output = base_file 294 } 295 296 # Compile the manifest overlay. 297 device_tree(overlay_target) { 298 source = invoker.overlay 299 output = overlay_file 300 } 301 302 # Merge the base manifest and the overlay, producing the final manifest. 303 fdt_overlay(target_name) { 304 base = base_file 305 overlay = overlay_file 306 output = "${target_out_dir}" + "/" + invoker.output 307 deps = [ 308 ":$base_target", 309 ":$overlay_target", 310 ] 311 } 312 } else { 313 # No overlay specified. Compile the manifest to DTB. 314 device_tree(target_name) { 315 source = invoker.source 316 output = "${target_out_dir}" + "/" + invoker.output 317 } 318 } 319} 320 321# Build the initial RAM disk for the hypervisor. 322template("initrd") { 323 base_out_dir = "${target_out_dir}/${target_name}" 324 325 action(target_name) { 326 forward_variables_from(invoker, [ "testonly" ]) 327 script = "//build/image/generate_initrd.py" 328 329 initrd_file = "${base_out_dir}/initrd.img" 330 initrd_staging = "${base_out_dir}/initrd" 331 332 deps = [] 333 args = [ 334 "--staging", 335 rebase_path(initrd_staging), 336 "--output", 337 rebase_path(initrd_file), 338 ] 339 340 # Add the files that need to be packaged into the RAM disk. The information 341 # about these files is encoded in lists with the following elements: 342 # 343 # - Target file name in the RAM disk 344 # - Build target for the file 345 # - File name to use as source (generated as output of the build) 346 foreach(file, invoker.files) { 347 deps += [ file[1] ] 348 args += [ 349 "--file", 350 file[0], 351 rebase_path(get_label_info(file[1], "target_out_dir") + "/" + file[2]), 352 ] 353 } 354 355 outputs = [ 356 initrd_file, 357 ] 358 } 359} 360 361# Generate Secure Partition package 362template("partition_package") { 363 base_out_dir = "${target_out_dir}/${target_name}" 364 365 action(target_name) { 366 forward_variables_from(invoker, [ "testonly" ]) 367 script = "//build/image/sptool.py" 368 369 output_package = "${base_out_dir}/${invoker.output}" 370 371 deps = [] 372 args = [] 373 374 foreach(file, invoker.files) { 375 deps += [ 376 file[2], 377 file[3], 378 ] 379 partition_dtb = rebase_path(get_label_info(file[0], "target_out_dir")) 380 partition_img = rebase_path(get_label_info(file[1], "target_out_dir")) 381 args += [ 382 "-i", 383 "${partition_img}:${partition_dtb}", 384 "-o", 385 rebase_path(output_package), 386 ] 387 } 388 389 args += [ 390 "--pm-offset", 391 "${invoker.pm_offset}", 392 "--img-offset", 393 "${invoker.img_offset}", 394 ] 395 396 outputs = [ 397 output_package, 398 ] 399 } 400} 401 402# Generate a JSON file containing the path to the necessary artifacts to run 403# an FVP driver, and adequately populate its arguments. 404template("partitions_json") { 405 base_out_dir = "${target_out_dir}" 406 action(target_name) { 407 forward_variables_from(invoker, 408 [ 409 "testonly", 410 "sps", 411 "vms", 412 ]) 413 414 script = "//build/image/generate_partitions_json.py" 415 416 json_file = "${base_out_dir}/" + invoker.json_file 417 418 args = [] 419 deps = [] 420 421 foreach(sp, sps) { 422 deps += [ 423 sp[2], 424 sp[3], 425 ] 426 427 package_dir = get_label_info(sp[2], "name") 428 img = rebase_path( 429 get_label_info(package_dir + "/" + sp[0], "target_out_dir")) 430 431 dts = rebase_path(sp[1]) 432 433 args += [ 434 "--sp", 435 "${img},${dts}", 436 ] 437 } 438 439 foreach(vm, vms) { 440 deps += [ 441 vm[2], 442 vm[3], 443 ] 444 445 package_dir = get_label_info(vm[2], "name") 446 img = rebase_path( 447 get_label_info(package_dir + "/" + vm[0], "target_out_dir")) 448 449 dts = rebase_path(vm[1]) 450 args += [ 451 "--vm", 452 "${img},${dts}", 453 ] 454 } 455 456 args += [ 457 "--out", 458 rebase_path(json_file), 459 ] 460 461 outputs = [ 462 json_file, 463 ] 464 } 465} 466