blob: 67857014f8fb308f47147033e3629794158d9e15 [file] [log] [blame]
# 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.
declare_args() {
# Set by arch toolchain. Prefix for binutils tools.
tool_prefix = ""
# Enable link time optimizations
use_lto = true
}
# Template for embedded toolchains; there is no support for C++ or libraries.
# Instead, use source_set to group source together.
template("embedded_cc_toolchain") {
toolchain(target_name) {
assert(defined(invoker.cc), "\"cc\" must be defined for ${target_name}.")
assert(defined(invoker.ld), "\"ld\" must be defined for ${target_name}.")
# Collect extra flags from the toolchain.
extra_defines = ""
extra_cflags = "-ffunction-sections -fdata-sections"
if (use_lto) {
extra_cflags += " -flto"
}
extra_ldflags = "-pie --gc-sections"
if (defined(invoker.extra_defines)) {
extra_defines += " ${invoker.extra_defines}"
}
if (defined(invoker.extra_cflags)) {
extra_cflags += " ${invoker.extra_cflags}"
}
if (defined(invoker.extra_ldflags)) {
extra_ldflags += " ${invoker.extra_ldflags}"
}
# Define the tools.
tool("cc") {
depfile = "{{output}}.d"
command = "${invoker.cc} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} ${extra_cflags} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
depsformat = "gcc"
description = "CC {{output}}"
outputs = [
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
]
}
tool("asm") {
depfile = "{{output}}.d"
command = "${invoker.cc} -MMD -MF $depfile ${extra_defines} {{defines}} {{include_dirs}} ${extra_cflags} {{asmflags}} -c {{source}} -o {{output}}"
depsformat = "gcc"
description = "ASM {{output}}"
outputs = [
"{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
]
}
tool("link") {
outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
rspfile = "$outfile.rsp"
command = "${invoker.ld} ${extra_ldflags} {{ldflags}} -o $outfile --start-group @$rspfile --end-group"
description = "LINK $outfile"
default_output_dir = "{{root_out_dir}}"
rspfile_content = "{{inputs}}"
outputs = [
outfile,
]
}
tool("stamp") {
command = "touch {{output}}"
description = "STAMP {{output}}"
}
tool("copy") {
command = "cp -af {{source}} {{output}}"
description = "COPY {{source}} {{output}}"
}
toolchain_args = {
forward_variables_from(invoker.toolchain_args, "*")
}
}
}
# Specialize for clang.
template("embedded_clang_toolchain") {
assert(defined(invoker.target),
"\"target\" must be defined for ${target_name}.")
assert(defined(invoker.tool_prefix),
"\"tool_prefix\" must be defined for ${target_name}.")
assert(defined(invoker.extra_defines),
"\"extra_defines\" must be defined for ${target_name}")
assert(defined(invoker.extra_cflags),
"\"extra_cflags\" must be defined for ${target_name}")
assert(defined(invoker.extra_ldflags),
"\"extra_ldflags\" must be defined for ${target_name}")
embedded_cc_toolchain(target_name) {
cc = "clang"
ld = "ld.lld"
forward_variables_from(invoker,
[
"extra_defines",
"extra_cflags",
"extra_ldflags",
])
# TODO: Remove //inc/system if we can stop using the version of stdatomic.h
# from the Android prebuilt Clang.
extra_cflags +=
" -target ${invoker.target} -fcolor-diagnostics -nostdinc -isystem" +
rebase_path("//prebuilts/linux-x64/clang/lib64/clang/8.0.4/include") +
" -isystem" + rebase_path("//inc/system")
extra_ldflags +=
" -O2 -lto-O2 --icf=all --fatal-warnings --color-diagnostics"
toolchain_args = {
tool_prefix = invoker.tool_prefix
if (defined(invoker.toolchain_args)) {
forward_variables_from(invoker.toolchain_args, "*")
}
}
}
}
# Specialize for mixed toolchain with clang and bfd linker.
template("embedded_clang_bfd_toolchain") {
assert(defined(invoker.target),
"\"target\" must be defined for ${target_name}.")
assert(defined(invoker.tool_prefix),
"\"tool_prefix\" must be defined for ${target_name}.")
assert(defined(invoker.extra_defines),
"\"extra_defines\" must be defined for ${target_name}")
assert(defined(invoker.extra_cflags),
"\"extra_cflags\" must be defined for ${target_name}")
assert(defined(invoker.extra_ldflags),
"\"extra_ldflags\" must be defined for ${target_name}")
embedded_cc_toolchain(target_name) {
cc = "clang"
ld = "${invoker.tool_prefix}ld.bfd"
forward_variables_from(invoker,
[
"extra_defines",
"extra_cflags",
"extra_ldflags",
])
extra_cflags += " -target ${invoker.target} -fcolor-diagnostics"
extra_ldflags += " --fatal-warnings"
if (use_lto) {
extra_ldflags += " -O2 -lto-O2 --icf=all"
}
toolchain_args = {
tool_prefix = invoker.tool_prefix
if (defined(invoker.toolchain_args)) {
forward_variables_from(invoker.toolchain_args, "*")
}
}
}
}
# Specialize for gcc.
template("embedded_gcc_toolchain") {
assert(defined(invoker.tool_prefix),
"\"tool_prefix\" must be defined for ${target_name}.")
assert(defined(invoker.extra_defines),
"\"extra_defines\" must be defined for ${target_name}.")
assert(defined(invoker.extra_cflags),
"\"extra_cflags\" must be defined for ${target_name}.")
assert(defined(invoker.extra_ldflags),
"\"extra_ldflags\" must be defined for ${target_name}.")
embedded_cc_toolchain(target_name) {
cc = "${invoker.tool_prefix}gcc"
ld = "${invoker.tool_prefix}ld"
forward_variables_from(invoker,
[
"extra_defines",
"extra_cflags",
"extra_ldflags",
])
extra_cflags += " -fdiagnostics-color=always"
toolchain_args = {
tool_prefix = invoker.tool_prefix
if (defined(invoker.toolchain_args)) {
forward_variables_from(invoker.toolchain_args, "*")
}
}
}
}
# Expand to clang and gcc variants.
template("embedded_platform_toolchain") {
assert(defined(invoker.arch), "\"arch\" must be defined for ${target_name}.")
assert(defined(invoker.target),
"\"target\" must be defined for ${target_name}.")
assert(defined(invoker.tool_prefix),
"\"tool_prefix\" must be defined for ${target_name}.")
assert(defined(invoker.origin_address),
"\"origin_address\" must be defined for ${target_name}.")
assert(defined(invoker.heap_pages),
"\"heap_pages\" must be defined for ${target_name}.")
assert(defined(invoker.max_cpus),
"\"max_cpus\" must be defined for ${target_name}.")
assert(defined(invoker.max_vms),
"\"max_vms\" must be defined for ${target_name}.")
assert(defined(invoker.platform_name),
"\"platform_name\" must be defined for ${target_name}.")
extra_defines = ""
extra_cflags = "-fno-builtin -ffreestanding -fpic"
extra_ldflags = "--defsym=ORIGIN_ADDRESS=${invoker.origin_address}"
if (defined(invoker.extra_defines)) {
extra_defines += " ${invoker.extra_defines}"
}
if (defined(invoker.extra_cflags)) {
extra_cflags += " ${invoker.extra_cflags}"
}
if (defined(invoker.extra_ldflags)) {
extra_ldflags += " ${invoker.extra_ldflags}"
}
toolchain_args = {
use_platform = true
plat_name = invoker.platform_name
plat_arch = invoker.arch
plat_heap_pages = invoker.heap_pages
plat_max_cpus = invoker.max_cpus
plat_max_vms = invoker.max_vms
if (defined(invoker.toolchain_args)) {
forward_variables_from(invoker.toolchain_args, "*")
}
}
tool_prefix = invoker.tool_prefix
embedded_clang_toolchain("${target_name}_clang") {
target = invoker.target
}
embedded_clang_bfd_toolchain("${target_name}_clang_bfd") {
target = invoker.target
}
embedded_gcc_toolchain("${target_name}_gcc") {
}
}
# Specialize for different architectures.
template("aarch64_common_toolchain") {
assert(defined(invoker.cpu), "\"cpu\" must be defined for ${target_name}.")
assert(defined(invoker.target),
"\"target\" must be defined for ${target_name}")
assert(defined(invoker.tool_prefix),
"\"tool_prefix\" must be defined for ${target_name}")
assert(defined(invoker.origin_address),
"\"origin_address\" must be defined for ${target_name}.")
assert(defined(invoker.console),
"\"console\" must be defined for ${target_name}.")
assert(defined(invoker.heap_pages),
"\"heap_pages\" must be defined for ${target_name}.")
assert(defined(invoker.max_cpus),
"\"max_cpus\" must be defined for ${target_name}.")
assert(defined(invoker.max_vms),
"\"max_vms\" must be defined for ${target_name}.")
if (invoker.gic_version == 3 || invoker.gic_version == 4) {
assert(defined(invoker.gicd_base_address),
"\"gicd_base_address\" must be defined for ${target_name}.")
assert(defined(invoker.gicr_base_address),
"\"gicr_base_address\" must be defined for ${target_name}.")
}
assert(defined(invoker.platform_name),
"\"platform_name\" must be defined for ${target_name}.")
embedded_platform_toolchain(target_name) {
forward_variables_from(invoker,
[
"origin_address",
"heap_pages",
"max_cpus",
"max_vms",
"platform_name",
"extra_ldflags",
])
arch = "aarch64"
target = invoker.target
tool_prefix = invoker.tool_prefix
extra_cflags = "-mcpu=${invoker.cpu} -mstrict-align"
if (defined(invoker.extra_cflags)) {
extra_cflags += " ${invoker.extra_cflags}"
}
extra_defines = ""
if (defined(invoker.extra_defines)) {
extra_defines += " ${invoker.extra_defines}"
}
if (invoker.gic_version > 0) {
extra_defines += " -DGIC_VERSION=${invoker.gic_version}"
}
if (invoker.gic_version == 3 || invoker.gic_version == 4) {
extra_defines += " -DGICD_BASE=${invoker.gicd_base_address} -DGICR_BASE=${invoker.gicr_base_address}"
}
toolchain_args = {
plat_boot_flow = invoker.boot_flow
plat_console = invoker.console
forward_variables_from(invoker.toolchain_args, "*")
}
}
}
template("aarch64_toolchain") {
aarch64_common_toolchain("${target_name}") {
forward_variables_from(invoker, "*")
target = "aarch64-none-eabi"
tool_prefix = "aarch64-linux-gnu-" # TODO: this isn't right for bare metal but it works.
platform_name = target_name
}
}
template("aarch64_toolchains") {
aarch64_toolchain("${target_name}") {
forward_variables_from(invoker,
[
"origin_address",
"boot_flow",
"console",
"gic_version",
"gicd_base_address",
"gicr_base_address",
"heap_pages",
"max_cpus",
"max_vms",
"toolchain_args",
])
cpu = "${invoker.cpu}+nofp"
# Add a macro so files can tell whether they are not being built for a VM.
extra_defines = " -DVM_TOOLCHAIN=0"
}
# Toolchain for building test VMs which run under Hafnium.
aarch64_toolchain("${target_name}_vm") {
forward_variables_from(invoker,
[
"origin_address",
"gic_version",
"gicd_base_address",
"gicr_base_address",
"max_cpus",
"toolchain_args",
])
cpu = "${invoker.cpu}+fp"
boot_flow = "//src/arch/fake:boot_flow"
console = "//src/arch/aarch64/hftest:console"
# Nonsense values because they are required but shouldn't be used.
heap_pages = 0
max_vms = 0
# Add a macro so files can tell whether they are being built for a VM.
extra_defines = " -DVM_TOOLCHAIN=1"
}
}