| # Copyright 2018 The Hafnium Authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import("//build/toolchain/embedded.gni") |
| import("//build/toolchain/platform.gni") |
| |
| # Build image, link to an ELF file then convert to plain binary. |
| template("image_binary") { |
| assert(defined(invoker.image_name), |
| "image_binary() must specify an \"image_name\" value") |
| |
| output_root = "" |
| if (defined(invoker.output_path)) { |
| output_root += "${invoker.output_path}/" |
| } |
| output_root += invoker.image_name |
| |
| file_root = "${root_out_dir}/${output_root}" |
| elf_file = "${file_root}.elf" |
| bin_file = "${file_root}.bin" |
| |
| elf_target = "${target_name}__elf" |
| checked_elf_target = "${target_name}__checked_elf" |
| |
| # Link objects together |
| executable(elf_target) { |
| forward_variables_from(invoker, |
| [ |
| "cflags", |
| "cflags_c", |
| "defines", |
| "deps", |
| "include_dirs", |
| "public_configs", |
| "public_deps", |
| "sources", |
| "testonly", |
| ]) |
| output_name = "${output_root}.elf" |
| inputs = [ |
| rebase_path("//build/image/image.ld"), |
| ] |
| ldflags = [ |
| "-T", |
| rebase_path("//build/image/image.ld"), |
| ] |
| visibility = [ |
| ":${checked_elf_target}", |
| ":${invoker.target_name}", |
| ] |
| } |
| |
| # Analyze the generated ELF file and check that assembly-level fixes, e.g. |
| # for CPU errata, have been properly applied. |
| action(checked_elf_target) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| stamp_file = elf_file + "_check.stamp" |
| |
| script = "//build/image/check_elf.py" |
| deps = [ |
| ":${elf_target}", |
| ] |
| args = [ |
| rebase_path(elf_file), |
| rebase_path(stamp_file), |
| "--max-image-size", |
| "$plat_max_image_size", |
| ] |
| outputs = [ |
| stamp_file, |
| ] |
| visibility = [ ":${invoker.target_name}" ] |
| } |
| |
| action(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| |
| script = "//build/image/convert_to_binary.py" |
| |
| if (defined(invoker.check_binary) && invoker.check_binary == true) { |
| deps = [ |
| ":${checked_elf_target}", |
| ] |
| } else { |
| deps = [ |
| ":${elf_target}", |
| ] |
| } |
| args = [ |
| "--input", |
| rebase_path(elf_file), |
| "--output", |
| rebase_path(bin_file), |
| ] |
| outputs = [ |
| bin_file, |
| ] |
| } |
| } |
| |
| # Helper to build a hypervisor image |
| template("hypervisor") { |
| image_binary(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "cflags", |
| "cflags_c", |
| "defines", |
| "deps", |
| "public_deps", |
| "sources", |
| "testonly", |
| ]) |
| image_name = target_name |
| |
| # Perform checks on the generated binary to prevent regressing on some |
| # classes of bugs, typically CPU erratas. |
| check_binary = true |
| } |
| } |
| |
| # Helper to build a virtual machine kernel |
| template("vm_kernel") { |
| image_binary(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "cflags", |
| "cflags_c", |
| "defines", |
| "deps", |
| "include_dirs", |
| "public_configs", |
| "public_deps", |
| "sources", |
| "testonly", |
| ]) |
| output_path = rebase_path(".", root_out_dir, target_out_dir) |
| image_name = target_name |
| } |
| } |
| |
| # Build the initial RAM disk for the Linux VM. |
| template("linux_initrd") { |
| initrd_base = "${target_out_dir}/${target_name}/initrd" |
| initrd_file = "${initrd_base}.img" |
| initrd_staging = "${initrd_base}" |
| |
| copy("${target_name}__staging") { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "sources", |
| "deps", |
| ]) |
| outputs = [ |
| "${initrd_staging}/{{source_file_part}}", |
| ] |
| } |
| |
| action(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| script = "//build/image/generate_linux_initrd.py" |
| args = [ |
| "--staging", |
| rebase_path(initrd_staging), |
| "--output", |
| rebase_path(initrd_file), |
| ] |
| deps = [ |
| ":${target_name}__staging", |
| ] |
| outputs = [ |
| initrd_file, |
| ] |
| } |
| } |
| |
| template("device_tree") { |
| action(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "deps", |
| ]) |
| script = "//build/image/dtc.py" |
| |
| sources = [ |
| invoker.source, |
| ] |
| outputs = [ |
| invoker.output, |
| ] |
| args = [ |
| "compile", |
| "-i", |
| rebase_path(sources[0]), |
| "-o", |
| rebase_path(outputs[0]), |
| ] |
| } |
| } |
| |
| template("fdt_overlay") { |
| action(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "deps", |
| ]) |
| script = "//build/image/dtc.py" |
| |
| sources = [ |
| invoker.base, |
| invoker.overlay, |
| ] |
| outputs = [ |
| invoker.output, |
| ] |
| args = [ |
| "overlay", |
| rebase_path(outputs[0]), |
| rebase_path(sources[0]), |
| rebase_path(sources[1]), |
| ] |
| } |
| } |
| |
| template("incbin") { |
| source_set(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "deps", |
| ]) |
| |
| sources = [ |
| "//build/image/incbin.S", |
| ] |
| inputs = invoker.sources |
| defines = [ |
| "SECTION_NAME=" + invoker.section, |
| "FILE_PATH=\"" + rebase_path(inputs[0]) + "\"", |
| ] |
| } |
| } |
| |
| template("incbin_target") { |
| incbin(target_name) { |
| forward_variables_from(invoker, |
| [ |
| "testonly", |
| "deps", |
| "section", |
| ]) |
| target_outputs = get_target_outputs(invoker.target) |
| target_file = target_outputs[0] |
| sources = [ |
| target_file, |
| ] |
| deps = [ |
| invoker.target, |
| ] |
| } |
| } |
| |
| # Build the initial RAM disk for the hypervisor. |
| template("initrd") { |
| base_out_dir = "${target_out_dir}/${target_name}" |
| manifest_target = "${target_name}__manifest" |
| manifest_file = "${base_out_dir}/manifest.dtb" |
| |
| # Check if the invoker specified an overlay for the manifest. |
| if (defined(invoker.manifest_overlay) && invoker.manifest_overlay != "") { |
| manifest_base_target = "${target_name}__manifest_base" |
| manifest_base_file = "${base_out_dir}/manifest_base.dtb" |
| manifest_overlay_target = "${target_name}__manifest_overlay" |
| manifest_overlay_file = "${base_out_dir}/manifest_overlay.dtbo" |
| |
| # Compile the base manifest. |
| device_tree(manifest_base_target) { |
| source = invoker.manifest |
| output = manifest_base_file |
| } |
| |
| # Compile the manifest overlay. |
| device_tree(manifest_overlay_target) { |
| source = invoker.manifest_overlay |
| output = manifest_overlay_file |
| } |
| |
| # Merge the base manifest and the overlay, producing the final manifest. |
| fdt_overlay(manifest_target) { |
| base = manifest_base_file |
| overlay = manifest_overlay_file |
| output = manifest_file |
| deps = [ |
| ":$manifest_base_target", |
| ":$manifest_overlay_target", |
| ] |
| } |
| } else { |
| # No overlay specified. Compile the manifest to DTB. |
| device_tree(manifest_target) { |
| source = invoker.manifest |
| output = manifest_file |
| } |
| } |
| |
| action(target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| script = "//build/image/generate_initrd.py" |
| |
| initrd_file = "${base_out_dir}/initrd.img" |
| initrd_staging = "${base_out_dir}/initrd" |
| |
| deps = [ |
| ":${manifest_target}", |
| ] |
| args = [ |
| "--staging", |
| rebase_path(initrd_staging), |
| "--output", |
| rebase_path(initrd_file), |
| "--file", |
| "manifest.dtb", |
| rebase_path(manifest_file), |
| ] |
| |
| if (defined(invoker.primary_vm)) { |
| # Cannot get target outputs here as they are defined in a different file. |
| primary_vm_image = |
| get_label_info(invoker.primary_vm, "target_out_dir") + "/" + |
| get_label_info(invoker.primary_vm, "name") + ".bin" |
| |
| deps += [ invoker.primary_vm ] |
| args += [ |
| "--file", |
| invoker.primary_name, |
| rebase_path(primary_vm_image), |
| ] |
| |
| if (defined(invoker.primary_initrd)) { |
| deps += [ invoker.primary_initrd ] |
| primary_initrd_outputs = get_target_outputs(invoker.primary_initrd) |
| args += [ |
| "--file", |
| "initrd.img", |
| rebase_path(primary_initrd_outputs[0]), |
| ] |
| } |
| } |
| |
| # Add the info about the secondary VMs. The information about the VMs is |
| # encoded in lists with the following elements: |
| # |
| # 1. File name for the VM image. |
| # 2. Build target for the VM. |
| if (defined(invoker.secondary_vms)) { |
| foreach(vm, invoker.secondary_vms) { |
| deps += [ vm[1] ] |
| args += [ |
| "--file", |
| vm[0], |
| rebase_path(get_label_info(vm[1], "target_out_dir") + "/" + |
| get_label_info(vm[1], "name") + ".bin"), |
| ] |
| } |
| } |
| |
| outputs = [ |
| initrd_file, |
| ] |
| } |
| } |