blob: 6bd2e2a5290c9def4dd6cc1fbc74f607d1f33986 [file] [log] [blame]
#
# Copyright 2018, Data61
# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
# ABN 41 687 119 230.
#
# This software may be distributed and modified according to the terms of
# the BSD 2-Clause license. Note that NO WARRANTY is provided.
# See "LICENSE_BSD2.txt" for details.
#
# @TAG(DATA61_BSD)
#
cmake_minimum_required(VERSION 3.8.2)
include(debug)
# /*? macros.generated_file_notice() ?*/
# Define names for tools we will use
set(OBJCOPY ${CROSS_COMPILER_PREFIX}objcopy)
# Declare our 'core' CAmkES libraries. These are the libraries that are considered minimal for the
# glue code that is linked to camkes applications to run
set(CAMKES_CORE_LIBS "sel4;sel4runtime;muslc;sel4camkes;sel4sync;utils;sel4vka;sel4utils;sel4platsupport;platsupport;sel4vspace;sel4muslcsys;sel4camkes_Config;sel4runtime_Config;sel4_autoconf")
# The main function generated by CAmkES does not conform to the standard main
# signatures, so disable warnings for this.
set(CAMKES_C_FLAGS "-Wno-main")
/*- set instances = composition.instances -*/
/*- set connections = composition.connections -*/
/*# The terms 'group' and 'address space' are currently synonymous. We can
*# derive the groups by collecting all the instances' address spaces.
#*/
/*- set groups = set(map(lambda('x: x.address_space'), filter(lambda('x: not x.type.hardware'), instances))) -*/
# We build up a list of all the generated items that we want to construct a single
# camkes invocation
set(item_list "")
set(outfile_list "")
set(template_list "")
set(reflow_commands "")
set(deps_list "")
set(camkes_ver_opts "")
macro(ParentListAppend list)
set(local_list_value "${${list}}")
list(APPEND local_list_value ${ARGN})
set(${list} "${local_list_value}" PARENT_SCOPE)
endmacro(ParentListAppend list)
# Helper function for declaring a generated file
function(CAmkESGen output item template)
cmake_parse_arguments(PARSE_ARGV 3 CAMKES_GEN "SOURCE;C_STYLE;THY_STYLE" "SOURCES_VAR;VER_BASE_NAME" "DEPENDS")
if (NOT "${CAMKES_GEN_UNPARSED_ARGUMENTS}" STREQUAL "")
message(FATAL_ERROR "Unknown arguments to CAmkESGen: ${CAMKES_GEN_UNPARSED_ARGUMENTS}")
endif()
# generate command
get_filename_component(out_dir "${output}" DIRECTORY)
# Reflow generated files if requested
if (CAMKES_GEN_C_STYLE AND (NOT ("${CAMKES_C_FMT_INVOCATION}" STREQUAL "")))
ParentListAppend(reflow_commands COMMAND sh -c
"${CAMKES_C_FMT_INVOCATION} ${output} | ${CAMKES_SPONGE_INVOCATION} ${output}")
elseif(CAMKES_GEN_THY_STYLE)
ParentListAppend(reflow_commands COMMAND sh -c
"${TPP_TOOL} ${output} | ${CAMKES_SPONGE_INVOCATION} ${output}")
endif()
# Append the item and outfile
ParentListAppend(item_list "${item}")
ParentListAppend(outfile_list "${output}")
ParentListAppend(template_list "${template}")
ParentListAppend(deps_list "${CAMKES_GEN_DEPENDS}")
# Pass along base name for verification templates
if (NOT "${CAMKES_GEN_VER_BASE_NAME}" STREQUAL "")
ParentListAppend(camkes_ver_opts "--verification-base-name=${CAMKES_GEN_VER_BASE_NAME}")
endif()
# Add to the sources list if it's a source file
if (CAMKES_GEN_SOURCE)
if (CAMKES_GEN_SOURCES_VAR)
ParentListAppend("${CAMKES_GEN_SOURCES_VAR}" "${output}")
else ()
ParentListAppend(gen_sources "${output}")
endif()
endif()
# Always add to the list of generated files
ParentListAppend(gen_files "${output}")
endfunction(CAmkESGen)
# Generate all the files declared previously. object_state_op is either
# load- or save-object-state, depending on whether the object state has
# already been built.
function(CAmkESOutputGenCommand object_state_op object_state_file)
if ("${item_list}" STREQUAL "")
return()
endif()
list(LENGTH outfile_list outfile_list_count)
# Calculate the string length of ${CMAKE_BINARY_DIR} + 1 to do a hacky relative
# path calculation when editing our generated depfile. This is because, we need
# to calculate the depfile path depending on the top level build directory, but
# the tool generating the depfile only knows the current subdirectory and doesn't
# get told the top level one.
string(LENGTH ${CMAKE_BINARY_DIR} strlen)
math(EXPR strlen "${strlen} + 1")
set(depfile ${CMAKE_CURRENT_BINARY_DIR}/${object_state_op}moredeps)
string(COMPARE EQUAL ${object_state_op} "load-object-state" load_object_state)
set(object_file_depends)
set(object_file_output)
if(load_object_state)
set(object_file_depends ${object_state_file})
else()
set(object_file_output ${object_state_file})
endif()
add_custom_command(
OUTPUT ${outfile_list} ${object_file_output}
COMMAND
${CAMKES_TOOL}
"--item;$<JOIN:${item_list},;--item;>"
"--outfile;$<JOIN:${outfile_list},;--outfile;>"
"--template;$<JOIN:${template_list},;--template;>"
"--load-ast=${CMAKE_CURRENT_BINARY_DIR}/ast.pickle"
"--${object_state_op}=${object_state_file}"
"--object-sizes=$<TARGET_PROPERTY:object_sizes,FILE_PATH>"
--makefile-dependencies "${depfile}"
${camkes_ver_opts}
${CAMKES_FLAGS} ${CAMKES_RENDER_FLAGS}
# For some reason, ninja only accepts relative targets.
# We truncate the first `strlen` chars which takes off the CMAKE_BINARY_DIR from the depfile.
COMMAND sh -c "dd if=${depfile} of=${depfile}.truncated bs=${strlen} skip=1 2> /dev/null && mv ${depfile}.truncated ${depfile}"
${reflow_commands}
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/ast.pickle
# This pulls in miscellaneous dependencies
# which is used by the camkes tool
${CAMKES_TOOL_DEPENDENCIES}
# Any additional dependencies from the files
${deps_list}
${object_file_depends}
object_sizes
VERBATIM
DEPFILE "${depfile}"
${USES_TERMINAL_DEBUG}
COMMAND_EXPAND_LISTS
COMMENT "Performing CAmkES generation for ${outfile_list_count} files"
)
set(reflow_commands "" PARENT_SCOPE)
set(item_list "" PARENT_SCOPE)
set(deps_list "" PARENT_SCOPE)
set(outfile_list "" PARENT_SCOPE)
set(template_list "" PARENT_SCOPE)
set(camkes_ver_opts "" PARENT_SCOPE)
endfunction(CAmkESOutputGenCommand)
# helper for appending lists of generator expressions
function(AppendGenerator output new_list_value)
# determine if there is anything in the original list OR the new list, and use that to deteremine
# whether or not to put a semicolon between the two
set(prop "${${output}}")
set(new_list "${prop}$<$<OR:$<BOOL:${prop}>,$<BOOL:${new_list_value}>>:$<SEMICOLON>>${new_list_value}")
set(${output} "${new_list}" PARENT_SCOPE)
endfunction(AppendGenerator)
# Helper for constructing a generator expression that evalutes to the provided value if it exists,
# or to a default value.
# if maybe_value is the empty string
# evaluate to the contents of default
# else
# evaluate to the contents of maybe_value
# Both 'default' and 'maybe_value' can themselves be generator expressions, allow for chaining usages of
# this together to build nested ORs.
function(GeneratorValueOrDefault output default maybe_value)
set(new_output "$<IF:$<STREQUAL:${maybe_value},>,${default},${maybe_value}>")
set(${output} "${new_output}" PARENT_SCOPE)
endfunction(GeneratorValueOrDefault)
# A target for each binary that we need to build
/*- for i in instances if not i.type.hardware -*/
# Variable for collecting generated files
set(gen_files "")
set(gen_sources "")
set(cakeml_sources "")
# If no instance target exists declare it to simplify the logic of the generator expressions
set (instance_target "CAmkESComponent_/*? i.type.name ?*/_instance_/*? i.name ?*/")
if (NOT (TARGET ${instance_target}))
add_custom_target(${instance_target})
endif()
# Retrieve the static sources for the component
set(static_sources "$<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_SOURCES>")
AppendGenerator(static_sources "$<TARGET_PROPERTY:${instance_target},COMPONENT_SOURCES>")
set(extra_c_flags "$<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_C_FLAGS>")
AppendGenerator(extra_c_flags "$<TARGET_PROPERTY:${instance_target},COMPONENT_C_FLAGS>")
set(extra_ld_flags "$<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_LD_FLAGS>")
AppendGenerator(extra_ld_flags "$<TARGET_PROPERTY:${instance_target},COMPONENT_LD_FLAGS>")
set(extra_libs "$<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_LIBS>")
AppendGenerator(extra_libs "$<TARGET_PROPERTY:${instance_target},COMPONENT_LIBS>")
# Retrieve the static headers for the component. Ensure instance headers are placed first
set(includes "$<TARGET_PROPERTY:${instance_target},COMPONENT_INCLUDES>")
AppendGenerator(includes "$<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_INCLUDES>")
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}//*? i.name ?*/")
# Generated different entry points for the instance
CAmkESGen("${generated_dir}/camkes.c" /*? i.name ?*//source component.common.c SOURCE C_STYLE)
# Generate camkes header
CAmkESGen("${generated_dir}/include/camkes.h" "/*? i.name ?*//header" component.template.h C_STYLE)
/*- if configuration[i.name].get('environment', 'c').lower() == 'c' -*/
CAmkESGen("${generated_dir}/camkes.environment.c" /*? i.name ?*//c_environment_source component.environment.c SOURCE C_STYLE)
/*- elif configuration[i.name].get('environment').lower() == 'cakeml' -*/
set(cakeml_sources "$<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_CAKEML_SOURCES>")
CAmkESGen("${generated_dir}/camkesStartScript.sml" /*? i.name ?*//cakeml_start_source component.environment.start.cakeml SOURCE SOURCES_VAR cakeml_sources)
CAmkESGen("${generated_dir}/camkesConstants.sml" /*? i.name ?*//camkesConstants camkesConstants.sml SOURCE SOURCES_VAR cakeml_sources)
CAmkESGen("${generated_dir}/camkesEndScript.sml" /*? i.name ?*//cakeml_end_source component.environment.end.cakeml SOURCE SOURCES_VAR cakeml_sources)
/*- else -*/
/*? raise(TemplateError('Unknown environment')) ?*/
/*- endif -*/
# Generate our linker script
set(linker_file "${generated_dir}/linker.lds")
CAmkESGen("${linker_file}" /*? i.name ?*//linker linker.lds)
# Generate connectors for this instance
/*- for c in connections -*/
/*- for id, e in enumerate(c.from_ends) -*/
set(unique_name /*? e.interface.name ?*/_/*? c.type.name ?*/_/*? id ?*/)
/*- if e.instance.name == i.name -*/
set(connector_target CAmkESConnector_/*? c.type.name ?*/)
get_property(c_from_template TARGET ${connector_target} PROPERTY CONNECTOR_FROM)
CAmkESGen("${generated_dir}/${unique_name}.c" /*? c.name ?*//from/source//*? id ?*/ ${c_from_template} SOURCE C_STYLE)
/*- endif -*/
/*- endfor -*/
/*- for id, e in enumerate(c.to_ends) -*/
set(unique_name /*? e.interface.name ?*/_/*? c.type.name ?*/_/*? id ?*/)
/*- if e.instance.name == i.name -*/
set(connector_target CAmkESConnector_/*? c.type.name ?*/)
/*- if configuration[i.name].get('environment', 'c').lower() == 'cakeml' -*/
get_property(cake_to_template TARGET ${connector_target} PROPERTY CONNECTOR_CAKEML_TO)
if (NOT "${cake_to_template}" STREQUAL "")
CAmkESGen("${generated_dir}/connectorScript.sml" /*? c.name ?*//to/cakeml//*? id ?*/ ${cake_to_template} SOURCE SOURCES_VAR cakeml_sources)
else()
get_property(c_to_template TARGET ${connector_target} PROPERTY CONNECTOR_TO)
CAmkESGen("${generated_dir}/${unique_name}.c" /*? c.name ?*//to/source//*? id ?*/ ${c_to_template} SOURCE C_STYLE)
endif()
/*- else -*/
get_property(c_to_template TARGET ${connector_target} PROPERTY CONNECTOR_TO)
CAmkESGen("${generated_dir}/${unique_name}.c" /*? c.name ?*//to/source//*? id ?*/ ${c_to_template} SOURCE C_STYLE)
/*- endif -*/
/*- endif -*/
/*- endfor -*/
/*- endfor -*/
/*- if configuration[i.name].get('debug') -*/
CAmkESGen("${generated_dir}/camkes.debug.c" /*? i.name ?*//debug component.debug.c SOURCE C_STYLE)
/*- endif -*/
/*- if configuration[i.name].get('simple') -*/
CAmkESGen("${generated_dir}/camkes.simple.c" /*? i.name ?*//simple component.simple.c SOURCE C_STYLE)
/*- endif -*/
/*- if configuration[i.name].get('rump_config') -*/
CAmkESGen("${generated_dir}/camkes.rumprun.c" /*? i.name ?*//rumprun component.rumprun.c SOURCE C_STYLE)
/*- endif -*/
# Create a target for all our generated files
set(gen_target /*? i.name ?*/_generated)
add_custom_target(${gen_target} DEPENDS ${gen_files})
# Build the actual binary
set(target /*? i.name ?*/.instance.bin)
add_executable(${target} EXCLUDE_FROM_ALL
${static_sources}
${gen_sources}
)
# If COMPONENT_LINKER_LANGUAGE is set on the component target, set the LINKER_LANGUAGE of the executable
get_property(link_language TARGET CAmkESComponent_/*? i.type.name ?*/ PROPERTY COMPONENT_LINKER_LANGUAGE)
if (NOT "${link_language}" STREQUAL "")
set_property(TARGET ${target} PROPERTY LINKER_LANGUAGE ${link_language})
endif()
# Build any CakeML library
if (NOT ("${cakeml_sources}" STREQUAL ""))
# Pull heap/stack size from component expression OR instances expression OR default to an arbitrary 50
# The order here is important as we want the instance property to be able to override the component property
GeneratorValueOrDefault(heap 50 $<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_CAKEML_HEAP_SIZE>)
GeneratorValueOrDefault(heap "${heap}" $<TARGET_PROPERTY:${instance_target},COMPONENT_CAKEML_HEAP_SIZE>)
GeneratorValueOrDefault(stack 50 $<TARGET_PROPERTY:CAmkESComponent_/*? i.type.name ?*/,COMPONENT_CAKEML_STACK_SIZE>)
GeneratorValueOrDefault(stack "${stack}" $<TARGET_PROPERTY:${instance_target},COMPONENT_CAKEML_STACK_SIZE>)
# Additional directories for the HOL build to depend on
get_property(cakeml_includes TARGET CAmkESComponent_/*? i.type.name ?*/ PROPERTY COMPONENT_CAKEML_INCLUDES)
get_property(cakeml_depends TARGET CAmkESComponent_/*? i.type.name ?*/ PROPERTY COMPONENT_CAKEML_DEPENDS)
DeclareCakeMLLib(/*? i.name ?*/_camkescakeml_contents
SOURCES "${cakeml_sources}"
TRANSLATION_THEORY "camkesEnd"
HEAP_SIZE "${heap}"
STACK_SIZE "${stack}"
RUNTIME_ENTRY "component_control_main"
CAKEML_ENTRY "camkes_entry"
INCLUDES ${cakeml_includes}
DEPENDS "${gen_target}" "${cakeml_depends}"
)
target_link_libraries(${target} camkescakeml /*? i.name ?*/_camkescakeml_contents)
endif()
target_include_directories(${target} PRIVATE ${includes} "${generated_dir}/include")
# Depend upon core camkes libraries
target_link_libraries(${target} ${CAMKES_CORE_LIBS})
# Depend upon additional libraries
target_link_libraries(${target} ${extra_libs})
# Depend upon target that creates the generated source files
add_dependencies(${target} ${gen_target} CAmkESComponent_/*? i.type.name ?*/)
# Set our CAmkES specific additional link flags
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS
" -static -nostdlib -u _camkes_start -e _camkes_start ")
# Add extra flags specified by the user
target_compile_options(${target} PRIVATE ${extra_c_flags} ${CAMKES_C_FLAGS})
set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS ${extra_ld_flags})
# Only incrementally link if this instance is going on to become part of a
# group.
# TODO: we care about being grouped elsewhere as well. generalize this
/*- set grouped = [False] -*/
/*- for inst in instances if not i.type.hardware -*/
/*- if id(i) != id(inst) and inst.address_space == i.address_space -*/
/*- do grouped.__setitem__(0, True) -*/
/*- endif -*/
/*- endfor -*/
/*- if grouped[0] -*/
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--relocatable ")
/*- endif -*/
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,--script=${linker_file} ")
/*- endfor -*/
# We need to apply objcopy to each component instance's ELF before we link them
# into a flattened binary in order to avoid symbol collision. Note that when we
# mangle symbols, we use the prefix 'camkes ' to avoid colliding with any
# user-provided symbols.
/*- set instancelist = set() -*/
/*- for i in instances if not i.type.hardware -*/
set(input_target /*? i.name ?*/.instance.bin)
set(output ${CMAKE_CURRENT_BINARY_DIR}//*? i.name ?*/.instance-copy.bin)
set(output_target /*? i.name ?*/_instance_copy_target)
set(input $<TARGET_FILE:${input_target}>)
add_custom_command(
OUTPUT "${output}"
COMMAND
# Brace yourself. This is going to be a bumpy ride.
${OBJCOPY}
/*# Use a dummy impossible symbol of the empty string here, because
*# marking one symbol as 'keep global' causes all others to be demoted
*# to local. This allows us to avoid symbol collisions from
*# user-provided symbols.
#*/
--keep-global-symbol ""
/*# Rename the entry point to avoid symbol conflicts when we are
*# colocated with other components. Note that we will still use this as
*# the entry point.
#*/
--redefine-sym "_camkes_start=/*? "camkes %s _camkes_start" % i.name ?*/"
/*- for c in connections -*/
/*- if c.type.name == 'seL4DirectCall' -*/
/*# For all 'from' connection ends (calls to unresolved symbols),
*# rename the symbols so they will correctly link to the
*# implementations provided by the 'to' side.
#*/
/*- for e in c.from_ends -*/
/*- if id(e.instance) == id(i) -*/
/*- for m in e.interface.type.methods -*/
--redefine-sym "/*? e.interface.name ?*/_/*? m.name ?*/=camkes connection /*? e.parent.name ?*/_/*? m.name ?*/"
/*- endfor -*/
/*- endif -*/
/*- endfor -*/
/*# For all 'to' connection ends (implementations of procedures),
*# rename the symbols so they will be found during the next
*# linking stage. Note we need to mark them as 'keep global' or
*# they will not be visible during the next link.
#*/
/*- for e in c.to_ends -*/
/*- if id(e.instance) == id(i) -*/
/*- if '%s_%s' % (i.name, e.interface.name) in instancelist -*/
/*- continue -*/
/*- endif -*/
/*- do instancelist.add('%s_%s' % (i.name, e.interface.name)) -*/
/*- for m in e.interface.type.methods -*/
--redefine-sym "/*? e.interface.name ?*/_/*? m.name ?*/=camkes connection /*? e.parent.name ?*/_/*? m.name ?*/"
--keep-global-symbol "camkes connection /*? e.parent.name ?*/_/*? m.name ?*/"
/*- endfor -*/
/*- endif -*/
/*- endfor -*/
/*- endif -*/
/*- endfor -*/
"${input}" "${output}"
COMMAND
# Some toolchains insert exception handling infrastructure whether we ask
# for it or not. The preceding `objcopy` step breaks references in
# implicit `.eh_frame`s and friends, which then goes on to cause a linker
# warning. Rather than attempt some complicated gymnastics to repair these
# references, we just strip the exception handling pieces. To further
# complicate the process, some architectures require an `.eh_frame` and
# attempting to remove it causes errors. To handle this we just blindly
# try to remove it and mask errors. We can't do this unconditionally in
# the preceding `objcopy` because it fails when our toolchain has *not*
# inserted exception handling pieces or when we're targeting an
# architecture that requires `.eh_frame`.
bash -c "${OBJCOPY} --remove-section .eh_frame --remove-section .eh_frame_hdr \
--remove-section .rel.eh_frame --remove-section .rela.eh_frame ${output} \
>/dev/null 2>/dev/null"
VERBATIM
DEPENDS ${input_target}
)
add_custom_target(/*? i.name ?*/_instance_copy_target DEPENDS "${output}")
# TODO target for dependencies
/*- endfor -*/
# Define the linker we used for instances groups. This is just C linking but without crt objects
# or any other libraries, we just want the flags to generate the correct binary type
set(CMAKE_INSTANCE_GROUP_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET>" CACHE INTERNAL "" FORCE)
# Finally link together the instances in the different groups */
/*- for g in groups -*/
/*- set elf_name = "%s_group_bin" % g -*/
list(APPEND key_names /*? g ?*/)
# Find all the instances that are part of this group */
set(instances "")
set(instance_targets "")
/*- for i in instances if not i.type.hardware -*/
/*- set other_elf_name = "%s_group_bin" % i.address_space -*/
/*- if elf_name == other_elf_name -*/
list(APPEND instances "/*? i.name ?*/.instance-copy.bin")
list(APPEND instance_targets "/*? i.name ?*/_instance_copy_target")
# Define the copies as objects in case we need to link them into a group and
# we would like cmake to not attempt to compile them
set_property(SOURCE "/*? i.name ?*/.instance-copy.bin" PROPERTY EXTERNAL_OBJECT TRUE)
/*- endif -*/
/*- endfor -*/
set(target ${CMAKE_CURRENT_BINARY_DIR}//*? elf_name ?*/)
list(LENGTH instances instances_len)
if (${instances_len} GREATER 1)
add_executable(/*? elf_name ?*/ EXCLUDE_FROM_ALL ${instances})
add_dependencies(/*? elf_name ?*/ ${instance_targets})
# Use a custom linker definition that will not include crt objects
set_property(TARGET /*? elf_name ?*/ PROPERTY LINKER_LANGUAGE INSTANCE_GROUP)
# Note that we deliberately give groups a
# broken entry point so that, if they are incorrectly loaded without correct
# initial instruction pointers, threads will immediately fault
set_property(TARGET /*? elf_name ?*/ APPEND PROPERTY LINK_FLAGS " -static -nostdlib --entry=0x0 -Wl,--build-id=none -T${TLS_LINKER_LDS}")
else()
add_custom_command(
OUTPUT ${target}
COMMAND
cp "${instances}" "${target}"
DEPENDS
${instances}
${instance_targets}
)
endif()
add_custom_target(/*? elf_name ?*/_group_target DEPENDS "${target}")
/*- endfor -*/
# Generate our targets up to this point
CAmkESOutputGenCommand(save-object-state ${CMAKE_CURRENT_BINARY_DIR}/object.pickle)
# CapDL generation. Aside from depending upon the CAmkES specifications themselves, it
# depends upon the copied instance binaries and (optionally) the bootinfo untyped list.
# First, find all instance binaries
set(capdl_elf_depends "")
set(capdl_elf_targets "")
/*- for g in groups -*/
/*- set elf_name = "%s_group_bin" % g -*/
list(APPEND capdl_elfs "${CMAKE_CURRENT_BINARY_DIR}//*? elf_name ?*/")
list(APPEND capdl_elf_targets "/*? elf_name ?*/_group_target")
/*- endfor -*/
# Generate boot untyped info for capDL allocator (if applicable)
if(CAmkESCapDLStaticAlloc)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/untyped.yaml
COMMAND
${CAPDL_UNTYPED_GEN}
"--input=${platform_yaml}"
"--output=${CMAKE_CURRENT_BINARY_DIR}/untyped.yaml"
"--linker=${CMAKE_CURRENT_BINARY_DIR}/linker.lds"
--architecture ${KernelSel4Arch}
"--object-sizes=$<TARGET_PROPERTY:object_sizes,FILE_PATH>"
--dtb-size ${KernelDTBSize}
--kernel-elf "$<TARGET_FILE:kernel.elf>"
"$<$<BOOL:${capdl_elfs}>:--elffile$<SEMICOLON>>$<JOIN:${capdl_elfs},$<SEMICOLON>--elffile$<SEMICOLON>>"
DEPENDS
# This pulls in miscellaneous dependencies
# which is used by the camkes tool
${CAPDL_UNTYPED_GEN_DEPENDENCIES}
object_sizes
${platform_yaml}
${capdl_elfs}
VERBATIM
${USES_TERMINAL_DEBUG}
COMMAND_EXPAND_LISTS
COMMENT "Generating untyped list"
)
add_custom_target(untyped_capdl_target DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/untyped.yaml")
set(CAPDL_UNTYPED_YAML_FILE "${CMAKE_CURRENT_BINARY_DIR}/untyped.yaml")
else()
add_custom_target(untyped_capdl_target)
set(CAPDL_UNTYPED_YAML_FILE "")
endif()
# Now, define the capDL spec generation from CAmkES
if(CAmkESCapDLStaticAlloc)
set(CAPDL_LINKER_ALLOC_OPT "--static-alloc")
set(CAPDL_LINKER_UNTYPED_OPT "--untyped=${CAPDL_UNTYPED_YAML_FILE}")
else()
set(CAPDL_LINKER_ALLOC_OPT "--dynamic-alloc")
set(CAPDL_LINKER_UNTYPED_OPT "")
endif()
add_custom_command(
OUTPUT ${CAMKES_CDL_TARGET} ${CMAKE_CURRENT_BINARY_DIR}/object-final.pickle
COMMAND
${CAPDL_LINKER}
"--object-sizes=$<TARGET_PROPERTY:object_sizes,FILE_PATH>"
--architecture ${KernelSel4Arch}
gen_cdl
"--manifest-in=${CMAKE_CURRENT_BINARY_DIR}/object.pickle"
"--save-object-state=${CMAKE_CURRENT_BINARY_DIR}/object-final.pickle"
${CAPDL_LINKER_ALLOC_OPT}
${CAPDL_LINKER_UNTYPED_OPT}
"$<$<BOOL:${capdl_elfs}>:--elffile$<SEMICOLON>>$<JOIN:${capdl_elfs},$<SEMICOLON>--elffile$<SEMICOLON>>"
"$<$<BOOL:${key_names}>:--key$<SEMICOLON>>$<JOIN:${key_names},$<SEMICOLON>--key$<SEMICOLON>>"
--outfile ${CAMKES_CDL_TARGET}
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/ast.pickle
# This pulls in miscellaneous dependencies
# which is used by the camkes tool
${CAPDL_LINKER_DEPENDENCIES}
# Any additional dependencies from the files
${CMAKE_CURRENT_BINARY_DIR}/object.pickle
object_sizes
untyped_capdl_target
${CAPDL_UNTYPED_YAML_FILE}
${capdl_elfs}
${capdl_elf_targets}
VERBATIM
${USES_TERMINAL_DEBUG}
COMMAND_EXPAND_LISTS
COMMENT "Generating final \"${CAMKES_CDL_TARGET}\" file"
)
add_custom_target(camkes_capdl_target DEPENDS "${CAMKES_CDL_TARGET}" "${CMAKE_CURRENT_BINARY_DIR}/object-final.pickle")
add_dependencies(camkes_capdl_target object_sizes ${capdl_elf_targets})
# Invoke the parse-capDL tool to turn the CDL spec into a C spec
CapDLToolCFileGen(capdl_c_spec_target capdl_spec.c ${CAmkESCapDLStaticAlloc} "$<TARGET_PROPERTY:object_sizes,FILE_PATH>" "${CAMKES_CDL_TARGET}" "${CAPDL_TOOL_BINARY}"
DEPENDS camkes_capdl_target install_capdl_tool "${CAPDL_TOOL_BINARY}")
# Ask the CapDL tool to generate an image with our given copied/mangled instances
BuildCapDLApplication(
C_SPEC "capdl_spec.c"
/*- for g in groups -*/
ELF "${CMAKE_CURRENT_BINARY_DIR}//*? "%s_group_bin" % g ?*/"
/*- endfor -*/
DEPENDS
# Dependency on the C_SPEC and ELFs are added automatically, we just have to add the target
# dependencies
capdl_c_spec_target
${capdl_elf_targets}
OUTPUT "capdl-loader"
)
include(rootserver)
DeclareRootserver("capdl-loader")
# Generate Isabelle theory scripts if needed
if (CAmkESCapDLVerification)
# Base name for Isabelle theories. We derive this from the top-level ADL name,
# but mangled to ensure that it is a valid identifier.
get_filename_component(VER_BASE_NAME "${adl}" NAME_WE)
string(MAKE_C_IDENTIFIER "${VER_BASE_NAME}" VER_BASE_NAME)
# Generated theory names. These must be consistent with the templates.
set(CAMKES_CDL_THY "${CMAKE_CURRENT_BINARY_DIR}/cdl-refine/${VER_BASE_NAME}_CDL.thy")
set(CAMKES_ADL_THY "${CMAKE_CURRENT_BINARY_DIR}/cdl-refine/${VER_BASE_NAME}_Arch_Spec.thy")
set(CAMKES_CDL_REFINE_THY "${CMAKE_CURRENT_BINARY_DIR}/cdl-refine/${VER_BASE_NAME}_CDL_Refine.thy")
set(CAMKES_VER_ROOT "${CMAKE_CURRENT_BINARY_DIR}/cdl-refine/ROOT")
# ROOT file
CAmkESGen("${CAMKES_VER_ROOT}" "isabelle-root" "root.thy" THY_STYLE VER_BASE_NAME ${VER_BASE_NAME})
add_custom_target(isabelle_root DEPENDS "${CAMKES_VER_ROOT}")
# Generate these theory files as part of overall build
# FIXME: hack?
add_dependencies("capdl-loader" isabelle_root)
# Isabelle capDL spec
add_custom_command(
OUTPUT "${CAMKES_CDL_THY}"
COMMAND
${CAPDL_TOOL_BINARY}
--isabelle "${CAMKES_CDL_THY}"
--object-sizes "$<TARGET_PROPERTY:object_sizes,FILE_PATH>"
"${CAMKES_CDL_TARGET}"
DEPENDS
"${CAMKES_CDL_TARGET}"
camkes_capdl_target
"${CAPDL_TOOL_BINARY}"
install_capdl_tool
"$<TARGET_PROPERTY:object_sizes,FILE_PATH>"
)
add_custom_target(camkes_cdl_thy DEPENDS "${CAMKES_CDL_THY}")
add_dependencies(isabelle_root camkes_cdl_thy)
# ADL spec
CAmkESGen("${CAMKES_ADL_THY}" "arch-spec" "arch-definitions.thy" THY_STYLE VER_BASE_NAME ${VER_BASE_NAME})
add_custom_target(camkes_adl_thy DEPENDS "${CAMKES_ADL_THY}")
add_dependencies(isabelle_root camkes_adl_thy)
# CDL refinement proof
CAmkESGen("${CAMKES_CDL_REFINE_THY}" "cdl-refine" "cdl-refine.thy" THY_STYLE VER_BASE_NAME ${VER_BASE_NAME}
DEPENDS camkes_capdl_target)
add_custom_target(camkes_cdl_refine_thy DEPENDS "${CAMKES_CDL_REFINE_THY}")
add_dependencies(isabelle_root camkes_cdl_refine_thy)
CAmkESOutputGenCommand(load-object-state ${CMAKE_CURRENT_BINARY_DIR}/object-final.pickle)
endif()
# Ensure we generated all the files we intended to, this is just sanity checking
if (NOT ("${item_list}" STREQUAL ""))
message(FATAL_ERROR "Items added through CAmkESGen not generated")
endif()