From f7401d9cedbafac1332fc5de57b6e03c2d1bfa25 Mon Sep 17 00:00:00 2001 From: JaredWright Date: Wed, 13 Dec 2017 15:12:39 -0800 Subject: [PATCH] New VMM extension integration mechanism 1) New vmm_extension() macro for registering bareflank extensions to the build system from build configuration file 2) New VMM extension-specific config variables and extension-specific macros 3) Added vmm_ex.cmake to be included by all Bareflank extensions 4) Updated build system documentation [RFC] #545 Signed-off-by: JaredWright --- .travis.yml | 1 + CMakeLists.txt | 4 +- README.md | 25 +- scripts/cmake/build_rules.cmake | 5 + scripts/cmake/config/bfconfig_template.cmake | 41 +++ scripts/cmake/config/default.cmake | 52 +++- scripts/cmake/config/default_ex.cmake | 129 +++++++++ scripts/cmake/global_vars.cmake | 45 ++- scripts/cmake/macros.cmake | 276 +++++++++++++++---- scripts/cmake/macros_ex.cmake | 87 ++++++ scripts/cmake/vmm_ex.cmake | 99 +++++++ scripts/docs/build_instructions.md | 140 ++++++++++ scripts/docs/extension_instructions.md | 190 +++++++++++++ 13 files changed, 1000 insertions(+), 94 deletions(-) create mode 100644 scripts/cmake/config/bfconfig_template.cmake create mode 100644 scripts/cmake/config/default_ex.cmake create mode 100644 scripts/cmake/macros_ex.cmake create mode 100644 scripts/cmake/vmm_ex.cmake create mode 100644 scripts/docs/build_instructions.md create mode 100644 scripts/docs/extension_instructions.md diff --git a/.travis.yml b/.travis.yml index e58879c8f..d276c384f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ # language: cpp dist: trusty +group: deprecated-2017Q4 # # Build Dependencies diff --git a/CMakeLists.txt b/CMakeLists.txt index c9b5f5e1e..e41d246b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,13 +23,13 @@ project(hypervisor) # Cmake global properties # ------------------------------------------------------------------------------ +include(ExternalProject) include(${CMAKE_SOURCE_DIR}/scripts/cmake/global_vars.cmake) include(${CMAKE_SOURCE_DIR}/scripts/cmake/macros.cmake) include(${BF_CONFIG_DIR}/default.cmake) include(${BF_FLAGS_DIR}/flags.cmake) include(${BF_SCRIPTS_DIR}/cmake/build_rules.cmake) include(${BF_SCRIPTS_DIR}/cmake/targets.cmake) -include(ExternalProject) validate_build() @@ -224,5 +224,7 @@ if(ENABLE_UNITTESTING) endif() endif() + +add_vmm_extensions() print_banner() print_usage() diff --git a/README.md b/README.md index 5249f8dbd..c693971c4 100644 --- a/README.md +++ b/README.md @@ -177,30 +177,19 @@ bcdedit.exe /set testsigning ON ``` ## Compilation Instructions -To compile, run the following commands: +To compile with default settings for your host environment, run the following commands: ``` git clone -b dev https://github.com/bareflank/hypervisor.git -mkdir hypervisor/build; cd hypervisor/build -cmake .. +mkdir build; cd build +cmake ../hypervisor make -j<# cores + 1> ``` -Also, if your modifying the hypervisor, we highly recommend enabling -unit testing and developer mode. This will enable the various different tools -that are needed to pass all of our CI tests. This also compiles the hypervisor -in debug mode. -- `-DENABLE_UNITTESTING=ON` -- `-DENABLE_DEVELOPER_MODE=ON` - -Once this is enabled, you can run the following commands before submitting a -PR: -- `make test` -- `make format` -- `make tidy` - -If you wish to enable the extended APIs, you can do so using the following. -- `-DENABLE_EXTENDED_APIS=ON` and/or `-DEXTENDED_APIS_PATH=` +For more detailed build instuctions and configurations, see the +[detailed build instructions](scripts/docs/build_instructions.md). +For instructions on building and creating Bareflank extensions, see the +[extension build instructions](scripts/docs/extension_instructions.md) ## Usage Instructions diff --git a/scripts/cmake/build_rules.cmake b/scripts/cmake/build_rules.cmake index dc21c15e1..eee9af83f 100644 --- a/scripts/cmake/build_rules.cmake +++ b/scripts/cmake/build_rules.cmake @@ -82,6 +82,11 @@ add_build_rule( FAIL_MSG "Extended APIs unit tests require VMM unit tests, please enable UNITTEST_VMM" ) +add_build_rule( + FAIL_ON ${UNITTEST_VMM_EXTENSIONS} AND NOT ${UNITTEST_VMM} + FAIL_MSG "VMM extension unit tests require VMM unit tests, please enable UNITTEST_VMM" +) + # ------------------------------------------------------------------------------ # Developer-mode build rules # ------------------------------------------------------------------------------ diff --git a/scripts/cmake/config/bfconfig_template.cmake b/scripts/cmake/config/bfconfig_template.cmake new file mode 100644 index 000000000..7997cd174 --- /dev/null +++ b/scripts/cmake/config/bfconfig_template.cmake @@ -0,0 +1,41 @@ +# +# Bareflank Hypervisor +# Copyright (C) 2015 Assured Information Security, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# ------------------------------------------------------------------------------ +# Bareflank Build Configurations +# ------------------------------------------------------------------------------ + +# set(BUILD_TYPE Debug) +# set(BUILD_VMM_STATIC ON) +# set(ENABLE_DEVELOPER_MODE ON) + +# ------------------------------------------------------------------------------ +# Bareflank Extensions +# ------------------------------------------------------------------------------ + +# vmm_extension( +# extended_apis +# GIT_REPOSITORY https://github.com/bareflank/extended_apis.git +# GIT_TAG dev +# ) + +# vmm_extension( +# extended_apis +# SOURCE_DIR ~/bareflank/my_extension +# DEPENDS extended_apis +# ) diff --git a/scripts/cmake/config/default.cmake b/scripts/cmake/config/default.cmake index bd3f2000d..6ed2af70c 100644 --- a/scripts/cmake/config/default.cmake +++ b/scripts/cmake/config/default.cmake @@ -26,20 +26,36 @@ # using: cmake /path/to/src -DBFCONFIG=/path/to/config.cmake # ------------------------------------------------------------------------------ -# Import user configuration file (if specified) +# Import Bareflank build configuration file # ------------------------------------------------------------------------------ +# -DBFCONFIG=/path/to/bfconfig.cmake takes first precedence +# Search relative to the build directory first, then the source tree defaults if(BFCONFIG) - find_file(_BFCONFIG_PATH ${BFCONFIG} ${BF_CONFIG_DIR}) - set(_BFCONFIG_PATH ${_BFCONFIG_PATH} CACHE INTERNAL "") - if(EXISTS ${_BFCONFIG_PATH}) - message(STATUS "Configuring Bareflank using: ${_BFCONFIG_PATH}") - include(${_BFCONFIG_PATH}) + # Prevent infinite loop this file is specified + if(${BFCONFIG} STREQUAL default.cmake) + message(STATUS "Building Bareflank with default settings") else() - message(FATAL_ERROR "Configuration file ${BFCONFIG} not found") + find_file(_BFCONFIG_PATH ${BFCONFIG} PATHS ${BF_BUILD_DIR} ${BF_CONFIG_DIR}) + if(EXISTS ${_BFCONFIG_PATH}) + message(STATUS "Configuring Bareflank using: ${_BFCONFIG_PATH}") + include(${_BFCONFIG_PATH}) + else() + message(FATAL_ERROR "Configuration file ${BFCONFIG} not found") + endif() endif() +# Next, search the current build directory for "bfconfig.cmake" +elseif(EXISTS ${BF_BUILD_DIR}/bfconfig.cmake) + message(STATUS "Configuring Bareflank using: ${BF_BUILD_DIR}/bfconfig.cmake") + include(${BF_BUILD_DIR}/bfconfig.cmake) +# Otherwise, fall back to the empty bfconfig template file else() - message(STATUS "No configuration specified, using default settings") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${BF_CONFIG_DIR}/bfconfig_template.cmake + ${BF_BUILD_DIR}/bfconfig.cmake + ) + message(STATUS "No build configuration specified, using default settings") endif() # ------------------------------------------------------------------------------ @@ -140,6 +156,13 @@ add_config( DESCRIPTION "Path to the Bareflank Extended APIs" ) +add_config( + CONFIG_NAME BUILD_VMM_EXTENSIONS + CONFIG_TYPE BOOL + DEFAULT_VAL ON + DESCRIPTION "Build all configured Bareflank VMM extensions" +) + if(${CMAKE_VERBOSE_MAKEFILE}) set(_BUILD_VERBOSE ON CACHE INTERNAL "") else() @@ -254,7 +277,18 @@ add_config( CONFIG_NAME UNITTEST_VMM CONFIG_TYPE BOOL DEFAULT_VAL ${ENABLE_UNITTESTING} - DESCRIPTION "Build unit tests for the VMM" + DESCRIPTION "Build VMM unit tests" +) + +set(_DEFAULT_UNITTEST_VMM_EXTENSIONS OFF CACHE INTERNAL "") +if(${ENABLE_UNITTESTING} AND ${BUILD_VMM_EXTENSIONS} AND ${UNITTEST_VMM}) + set(_DEFAULT_UNITTEST_VMM_EXTENSIONS ON) +endif() +add_config( + CONFIG_NAME UNITTEST_VMM_EXTENSIONS + CONFIG_TYPE BOOL + DEFAULT_VAL ${_DEFAULT_UNITTEST_VMM_EXTENSIONS} + DESCRIPTION "Build VMM extension unit tests" ) set(_DEFAULT_UNITTEST_BFDRIVER OFF CACHE INTERNAL "") diff --git a/scripts/cmake/config/default_ex.cmake b/scripts/cmake/config/default_ex.cmake new file mode 100644 index 000000000..0d50b69be --- /dev/null +++ b/scripts/cmake/config/default_ex.cmake @@ -0,0 +1,129 @@ +# +# Bareflank Hypervisor +# Copyright (C) 2015 Assured Information Security, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# ------------------------------------------------------------------------------ +# README +# ------------------------------------------------------------------------------ + +# This file defines all configurable cmake variables available to Barefank +# VMM extensions, set to their default value. These configuration are NOT +# available to base Bareflank hypervisor projects. VMM extension projects +# can use both these configurations PLUS the base hypervisor configurations. + +# Each configuration here indicates the Bareflank suggested convention as +# a default value. The goal is to encourage a "convention over configuration" +# mindset for extension developers. If extension developers choose not follow +# a suggested convention, they can override a configuration using two methods: +# +# 1) Specify each configuration as CMAKE_ARGS to the vmm_extension() macro. Ex: +# +# vmm_extension( +# extension_name +# CMAKE_ARGS -DVMM_EX_BUILD_RULES=/path/to/build_rules.cmake +# ) +# +# 2) Override a configuration in the extension's CMakeLists.txt file BEFORE +# calling include(${VMM_EXTENSION}). Ex: +# +# set(VMM_EX_BUILD_RULES "/path/to/build_rules.cmake") +# set(VMM_EX_UNITTEST_PATH "/path/to/the/unit/tests") +# include(${VMM_EXTENSION}) +# + +# ------------------------------------------------------------------------------ +# Source tree structure +# ------------------------------------------------------------------------------ + +add_config( + CONFIG_NAME VMM_EX_TOP_DIR + CONFIG_TYPE PATH + DEFAULT_VAL ${CMAKE_CURRENT_SOURCE_DIR} + DESCRIPTION "Path to the top directory for this VMM extension" +) + +add_config( + CONFIG_NAME VMM_EX_SOURCE_DIR + CONFIG_TYPE PATH + DEFAULT_VAL ${VMM_EX_TOP_DIR}/src + DESCRIPTION "Path to the source code directory for this VMM extension" + SKIP_VALIDATION +) + +add_config( + CONFIG_NAME VMM_EX_INCLUDE_DIR + CONFIG_TYPE PATH + DEFAULT_VAL ${VMM_EX_TOP_DIR}/include + DESCRIPTION "Path to the header include directory for this VMM extension" + SKIP_VALIDATION +) + +add_config( + CONFIG_NAME VMM_EX_UNITTEST_DIR + CONFIG_TYPE PATH + DEFAULT_VAL ${VMM_EX_TOP_DIR}/test + DESCRIPTION "Path to the unit test directory for this VMM extension" + SKIP_VALIDATION +) + +# ------------------------------------------------------------------------------ +# Build system features +# ------------------------------------------------------------------------------ + +add_config( + CONFIG_NAME VMM_EX_CONFIGS + CONFIG_TYPE FILE + DEFAULT_VAL ${VMM_EX_TOP_DIR}/configs.cmake + DESCRIPTION "Path to extention-specific build configurations to be added " + "for this VMM extension" + SKIP_VALIDATION +) + +add_config( + CONFIG_NAME VMM_EX_BUILD_RULES + CONFIG_TYPE FILE + DEFAULT_VAL ${VMM_EX_TOP_DIR}/build_rules.cmake + DESCRIPTION "Path to a build rules file to be validated before building " + "this VMM extension" + SKIP_VALIDATION +) + +# ------------------------------------------------------------------------------ +# Read-only variables +# ------------------------------------------------------------------------------ + +add_config( + CONFIG_NAME VMM_EX_IS_UNITTEST_BUILD + CONFIG_TYPE INTERNAL + DEFAULT_VAL OFF + DESCRIPTION "The build system sets this variable to ON if this extension's " + "unit tests are currently being built, rather than it's source" + SKIP_VALIDATION +) + +if(VMM_EX_IS_UNTTEST_BUILD) + set(_VMM_EX_SYSROOT_DEFAULT ${BUILD_SYSROOT_TEST}) +else() + set(_VMM_EX_SYSROOT_DEFAULT ${BUILD_SYSROOT_VMM}) +endif() +add_config( + CONFIG_NAME VMM_EX_SYSROOT + CONFIG_TYPE INTERNAL + DEFAULT_VAL ${_VMM_EX_SYSROOT_DEFAULT} + DESCRIPTION "Path to this VMM extension's sysroot" + SKIP_VALIDATION +) diff --git a/scripts/cmake/global_vars.cmake b/scripts/cmake/global_vars.cmake index fef878ff2..8e83c5770 100644 --- a/scripts/cmake/global_vars.cmake +++ b/scripts/cmake/global_vars.cmake @@ -70,87 +70,97 @@ set(BF_BUILD_DIR ${CMAKE_BINARY_DIR} "Top-level build directory" ) +set(BF_BUILD_PROJECTS_DIR ${BF_BUILD_DIR}/hypervisor + CACHE INTERNAL + "Build directory for Bareflank hypervisor projects" +) + set(BF_BUILD_DEPENDS_DIR ${BF_BUILD_DIR}/depends CACHE INTERNAL "Build directory for external dependencies" ) +set(BF_BUILD_EXTENSIONS_DIR ${BF_BUILD_DIR}/extensions + CACHE INTERNAL + "Build directory for Bareflank VMM extensions" +) + set(BF_BUILD_INSTALL_DIR "${BF_BUILD_DIR}/install" CACHE INTERNAL "Intermediate build installation directory" ) -set(BF_BUILD_DIR_BFDRIVER "${BF_BUILD_DIR}/bfdriver/build" +set(BF_BUILD_DIR_BFDRIVER "${BF_BUILD_PROJECTS_DIR}/bfdriver/build" CACHE INTERNAL "Build directory for bfdriver" ) -set(BF_BUILD_DIR_BFDRIVER_TEST "${BF_BUILD_DIR}/bfdriver_test/build" +set(BF_BUILD_DIR_BFDRIVER_TEST "${BF_BUILD_PROJECTS_DIR}/bfdriver_test/build" CACHE INTERNAL "Build directory for bfdriver unit tests" ) -set(BF_BUILD_DIR_BFELF_LOADER "${BF_BUILD_DIR}/bfelf_loader/build" +set(BF_BUILD_DIR_BFELF_LOADER "${BF_BUILD_PROJECTS_DIR}/bfelf_loader/build" CACHE INTERNAL "Build directory for bfelf_loader" ) -set(BF_BUILD_DIR_BFELF_LOADER_TEST "${BF_BUILD_DIR}/bfelf_loader_test/build" +set(BF_BUILD_DIR_BFELF_LOADER_TEST "${BF_BUILD_PROJECTS_DIR}/bfelf_loader_test/build" CACHE INTERNAL "Build directory for bfelf_loader unit tests" ) -set(BF_BUILD_DIR_BFM "${BF_BUILD_DIR}/bfm/build" +set(BF_BUILD_DIR_BFM "${BF_BUILD_PROJECTS_DIR}/bfm/build" CACHE INTERNAL "Build directory for bfm" ) -set(BF_BUILD_DIR_BFM_TEST "${BF_BUILD_DIR}/bfm_test/build" +set(BF_BUILD_DIR_BFM_TEST "${BF_BUILD_PROJECTS_DIR}/bfm_test/build" CACHE INTERNAL "Build directory for bfm unit tests" ) -set(BF_BUILD_DIR_BFSDK "${BF_BUILD_DIR}/bfsdk/build" +set(BF_BUILD_DIR_BFSDK "${BF_BUILD_PROJECTS_DIR}/bfsdk/build" CACHE INTERNAL "Build directory for bfsdk" ) -set(BF_BUILD_DIR_BFSDK_TEST "${BF_BUILD_DIR}/bfsdk_test/build" +set(BF_BUILD_DIR_BFSDK_TEST "${BF_BUILD_PROJECTS_DIR}/bfsdk_test/build" CACHE INTERNAL "Build directory for bfsdk unit tests" ) -set(BF_BUILD_DIR_BFSUPPORT "${BF_BUILD_DIR}/bfsupport/build" +set(BF_BUILD_DIR_BFSUPPORT "${BF_BUILD_PROJECTS_DIR}/bfsupport/build" CACHE INTERNAL "Build directory for bfsupport unit tests" ) -set(BF_BUILD_DIR_BFSUPPORT_TEST "${BF_BUILD_DIR}/bfsupport_test/build" +set(BF_BUILD_DIR_BFSUPPORT_TEST "${BF_BUILD_PROJECTS_DIR}/bfsupport_test/build" CACHE INTERNAL "Build directory for bfsupport unit tests" ) -set(BF_BUILD_DIR_BFUNWIND "${BF_BUILD_DIR}/bfunwind/build" +set(BF_BUILD_DIR_BFUNWIND "${BF_BUILD_PROJECTS_DIR}/bfunwind/build" CACHE INTERNAL "Build directory for bfunwind" ) -set(BF_BUILD_DIR_BFVMM "${BF_BUILD_DIR}/bfvmm/build" +set(BF_BUILD_DIR_BFVMM "${BF_BUILD_PROJECTS_DIR}/bfvmm/build" CACHE INTERNAL "Build directory for bfvmm" ) -set(BF_BUILD_DIR_BFVMM_TEST "${BF_BUILD_DIR}/bfvmm_test/build" +set(BF_BUILD_DIR_BFVMM_TEST "${BF_BUILD_PROJECTS_DIR}/bfvmm_test/build" CACHE INTERNAL "Build directory for bfvmm tests" ) -set(BF_BUILD_DIR_EXTENDED_APIS "${BF_BUILD_DIR}/extended_apis/build" +set(BF_BUILD_DIR_EXTENDED_APIS "${BF_BUILD_PROJECTS_DIR}/extended_apis/build" CACHE INTERNAL "Build directory for bareflank Extended APIs" ) -set(BF_BUILD_DIR_EXTENDED_APIS_TEST "${BF_BUILD_DIR}/extended_apis_test/build" +set(BF_BUILD_DIR_EXTENDED_APIS_TEST "${BF_BUILD_PROJECTS_DIR}/extended_apis_test/build" CACHE INTERNAL "Build directory for bareflank Extended APIs unit tests" ) @@ -200,6 +210,11 @@ endif() # Miscellaneous # ------------------------------------------------------------------------------ +set(BF_VMM_EXTENSION ${BF_SCRIPTS_DIR}/cmake/vmm_ex.cmake + CACHE INTERNAL + "Path to VMM extension cmake include file" +) + STRING(FIND ${CMAKE_GENERATOR} "Makefile" is_make) STRING(FIND ${CMAKE_GENERATOR} "Ninja" is_ninja) STRING(FIND ${CMAKE_GENERATOR} "Visual Studio" is_vs) diff --git a/scripts/cmake/macros.cmake b/scripts/cmake/macros.cmake index 5fc0be5ce..b26b3745e 100644 --- a/scripts/cmake/macros.cmake +++ b/scripts/cmake/macros.cmake @@ -16,29 +16,38 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# Platform independent symbolic link creation -macro(install_symlink filepath sympath) - if(WIN32) - install(CODE "execute_process(COMMAND mklink ${sympath} ${filepath})") - install(CODE "message(STATUS \"Created symlink: ${sympath} -> ${filepath}\")") - else() - install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${filepath} ${sympath})") - install(CODE "message(STATUS \"Created symlink: ${sympath} -> ${filepath}\")") - endif() -endmacro(install_symlink) +# ------------------------------------------------------------------------------ +# Sub-project and VMM extension management +# ------------------------------------------------------------------------------ -# Convenience wrapper around cmake's built-in find_program() -# @arg path: Will hold the path to the program given by "name" on success -# @arg name: The program to be searched for. -# If the program given by "name" is not found, cmake exits with an error -macro(check_program_installed path name) - find_program(${path} ${name}) - if(${path} MATCHES "-NOTFOUND$") - message(FATAL_ERROR "Unable to find ${name}, or ${name} is not installed") +# Generate common cmake arguements shared across all projects added to the build +# system using ExternalProject_Add() +macro(generate_external_project_args args_out) + # Silence noisy cmake warnings + list(APPEND ${args_out} + -DCMAKE_TARGET_MESSAGES=OFF + -DCMAKE_INSTALL_MESSAGE=NEVER + --no-warn-unused-cli + ) + + # Copy all non-built-in cmake cache variables to the external project scope + # (i.e. build configuration variables, build global variables, etc.) + get_cmake_property(_vars CACHE_VARIABLES) + foreach (_var ${_vars}) + STRING(REGEX MATCH "^CMAKE" is_cmake_var ${_var}) + if(NOT is_cmake_var) + list(APPEND ${args_out} -D${_var}=${${_var}}) + endif() + endforeach() + + # Support for clang-tidy (if enabled) + if(ENABLE_TIDY) + list(APPEND ${args_out} -DCMAKE_EXPORT_COMPILE_COMMANDS=ON) endif() -endmacro(check_program_installed) -# Add a project directory to be built with a new toolchain +endmacro(generate_external_project_args) + +# Add a sub-project directory to be built with the specified toolchain # @arg SOURCE_DIR: Path to a source code directory to be built with cmake # @arg TARGET: The name of the cmake target to be created for this project # @arg TOOLCHAIN: Path to a cmake toolchain file to use for compiling "project" @@ -58,13 +67,6 @@ function(add_subproject) message(FATAL_ERROR "Unable to find toolchain file ${ADD_SUBPROJECT_TOOLCHAIN}") endif() - list(APPEND _PROJECT_CMAKE_ARGS - -DCMAKE_TOOLCHAIN_FILE=${ADD_SUBPROJECT_TOOLCHAIN} - -DCMAKE_TARGET_MESSAGES=OFF - -DCMAKE_INSTALL_MESSAGE=NEVER - --no-warn-unused-cli - ) - if(${ADD_SUBPROJECT_VERBOSE}) message(STATUS "Adding subproject: ${ADD_SUBPROJECT_TARGET}") message(STATUS "\t${ADD_SUBPROJECT_TARGET} source path: ${ADD_SUBPROJECT_SOURCE_DIR}") @@ -72,37 +74,183 @@ function(add_subproject) message(STATUS "\t${ADD_SUBPROJECT_TARGET} dependencies: ${ADD_SUBPROJECT_DEPENDS}") endif() - # Copy all non-built-in cmake cache variables to the new project scope - get_cmake_property(_vars CACHE_VARIABLES) - foreach (_var ${_vars}) - STRING(REGEX MATCH "^CMAKE" is_cmake_var ${_var}) - if(NOT is_cmake_var) - list(APPEND _PROJECT_CMAKE_ARGS -D${_var}=${${_var}}) - endif() - endforeach() - - # If clang-tidy is enabled, each project must generate compile_commands.json - if(ENABLE_TIDY) - list(APPEND _PROJECT_CMAKE_ARGS -DCMAKE_EXPORT_COMPILE_COMMANDS=ON) - endif() + generate_external_project_args(_PROJECT_CMAKE_ARGS) + list(APPEND _PROJECT_CMAKE_ARGS + -DCMAKE_TOOLCHAIN_FILE=${ADD_SUBPROJECT_TOOLCHAIN} + ) ExternalProject_Add( ${ADD_SUBPROJECT_TARGET} CMAKE_ARGS ${_PROJECT_CMAKE_ARGS} SOURCE_DIR ${ADD_SUBPROJECT_SOURCE_DIR} - BINARY_DIR ${BF_BUILD_DIR}/${ADD_SUBPROJECT_TARGET}/build - PREFIX ${BF_BUILD_DIR}/${ADD_SUBPROJECT_TARGET} - TMP_DIR ${BF_BUILD_DIR}/${ADD_SUBPROJECT_TARGET}/tmp - STAMP_DIR ${BF_BUILD_DIR}/${ADD_SUBPROJECT_TARGET}/stamp + BINARY_DIR ${BF_BUILD_PROJECTS_DIR}/${ADD_SUBPROJECT_TARGET}/build + PREFIX ${BF_BUILD_PROJECTS_DIR}/${ADD_SUBPROJECT_TARGET} + TMP_DIR ${BF_BUILD_PROJECTS_DIR}/${ADD_SUBPROJECT_TARGET}/tmp + STAMP_DIR ${BF_BUILD_PROJECTS_DIR}/${ADD_SUBPROJECT_TARGET}/stamp UPDATE_DISCONNECTED 0 UPDATE_COMMAND "" DEPENDS ${ADD_SUBPROJECT_DEPENDS} ) endfunction(add_subproject) +# Cmake variables to orchestrate adding VMM extensions to the build system +# using vmm_extension() and add_vmm_extensions() +set(VMM_EXTENSIONS "" + CACHE INTERNAL + "A list of target names for VMM extensions to be built" +) +set(VMM_EXTENSION_ARGS "" + CACHE INTERNAL + "A list of arguments to be passed to ExternalProject_Add() for each VMM extension in VMM_EXTENSIONS" +) + +# Add a VMM extension to the build system. This macro is intended to be used +# from a build configuration file, using any arguments compatible with cmake's +# built-in ExternalProject_Add() function. +# +# NOTE: Since this macro is intended to be called from a build configuration +# file, build variables and internal targets will not be defined when +# this macro is called. Therfore, DO NOT use any build variables inside this +# macro!! See add_vmm_extensions() for the "second half" of the extension +# registration process. +# +# Usage: vmm_extension(name argn ...) +# name = a unique name for this vmm extension +# argn = Any number of arguments compatible with ExternlProject_Add() +# +# Example: Add the Bareflank extended apis extension from GitHub +# vmm_extension( +# extended_apis +# GIT_REPOSITORY https://github.com/bareflank/extended_apis.git +# GIT_TAG dev +# ) +macro(vmm_extension) + set(EXTENSION_ARGS ${ARGN}) + list(GET EXTENSION_ARGS 0 EXTENSION_NAME) + list(FIND VMM_EXTENSIONS ${EXTENSION_NAME} EXTENSION_IDX) + if(NOT ${EXTENSION_IDX} EQUAL -1) + message(FATAL_ERROR "VMM extension already registered with name: ${EXTENSION_NAME}") + endif() + + # Reserve the suffix "_test" for auto-generated extension unit test targets + STRING(REGEX MATCH "_test$" has_test_keyword ${EXTENSION_NAME}) + if(has_test_keyword) + message( + FATAL_ERROR + "VMM extension names may not end in \"_test\", " + "failed to add VMM extension: ${EXTENSION_NAME}" + ) + endif() + + # Auto-generate an extension unit test build with the reserved "_test" + # suffix (appended to the given target name) + set(TEST_EXTENSION_ARGS ${ARGN}) + set(TEST_EXTENSION_NAME ${EXTENSION_NAME}_test) + list(REMOVE_AT TEST_EXTENSION_ARGS 0) + list(INSERT TEST_EXTENSION_ARGS 0 ${TEST_EXTENSION_NAME}) + + # For each extension dependency, add the generated name + "_test" + # as an additional dependency + cmake_parse_arguments(VMM_EX "" "" "DEPENDS" ${ARGN}) + if(VMM_EX_DEPENDS) + list(APPEND TEST_EXTENSION_ARGS "DEPENDS") + foreach(depend_name ${VMM_EX_DEPENDS}) + list(APPEND TEST_EXTENSION_ARGS ${depend_name}_test) + endforeach() + endif() + + # Add the extension and unit tests to a waiting list, to be added + # (registered) to the build system later when add_vmm_extensions() is called + string(REPLACE ";" " " ARG_STRING "${EXTENSION_ARGS}") + string(REPLACE ";" " " TEST_ARG_STRING "${TEST_EXTENSION_ARGS}") + list(APPEND VMM_EXTENSIONS ${EXTENSION_NAME}) + list(APPEND VMM_EXTENSIONS ${TEST_EXTENSION_NAME}) + list(APPEND VMM_EXTENSION_ARGS "${ARG_STRING}") + list(APPEND VMM_EXTENSION_ARGS "${TEST_ARG_STRING}") +endmacro(vmm_extension) + +# Add all components configured with vmm_extension() to the build system. +# NOTE: This macro needs to be called at the very end of +# the top-level CMakeLists.txt +macro(add_vmm_extensions) + if(VMM_EXTENSIONS) + generate_external_project_args(_EXTENSION_CMAKE_ARGS) + + list(LENGTH VMM_EXTENSION_ARGS count) + math(EXPR count "${count} - 1") + foreach(i RANGE ${count}) + list(GET VMM_EXTENSIONS ${i} EXTENSION_NAME) + list(GET VMM_EXTENSION_ARGS ${i} EXTENSION_ARGS) + string(REPLACE " " ";" EXTENSION_ARGS ${EXTENSION_ARGS}) + + STRING(REGEX MATCH "_test$" IS_TEST_EXTENSION ${EXTENSION_NAME}) + if(IS_TEST_EXTENSION) + # If unit testing for VMM extensions is turned off, don't add + # the auto-generated extension test projects + if(NOT UNITTEST_VMM_EXTENSIONS OR NOT ENABLE_UNITTESTING) + continue() + endif() + + # VMM extension unit test specific cmake arguments + list(APPEND EXTENSION_ARGS + DEPENDS bfvmm_test + CMAKE_ARGS + -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_PATH_UNITTEST} + -DVMM_EX_IS_UNITTEST_BUILD=ON + ) + + # Add the unit tests to the 'make test' target + add_custom_command( + TARGET test + COMMAND ${CMAKE_COMMAND} + --build ${BF_BUILD_EXTENSIONS_DIR}/${EXTENSION_NAME}/build + --target test + ) + if(ENABLE_DEVELOPER_MODE) + add_dependencies(test ${EXTENSION_NAME}) + endif() + else() + # VMM extension specific cmake arguments + list(APPEND EXTENSION_ARGS + DEPENDS bfvmm + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_PATH_VMM} + ) + endif() + + # Add the extension to the build system + ExternalProject_Add( + ${EXTENSION_ARGS} + CMAKE_ARGS ${_EXTENSION_CMAKE_ARGS} + BINARY_DIR ${BF_BUILD_EXTENSIONS_DIR}/${EXTENSION_NAME}/build + PREFIX ${BF_BUILD_EXTENSIONS_DIR}/${EXTENSION_NAME} + TMP_DIR ${BF_BUILD_EXTENSIONS_DIR}/${EXTENSION_NAME}/tmp + STAMP_DIR ${BF_BUILD_EXTENSIONS_DIR}/${EXTENSION_NAME}/stamp + UPDATE_DISCONNECTED 0 + UPDATE_COMMAND "" + ) + + list(APPEND REGISTERED_EXTENSIONS ${EXTENSION_NAME}) + endforeach() + + string(REPLACE ";" " " REGISTERED_EXTENSIONS "${REGISTERED_EXTENSIONS}") + message(STATUS "Registered VMM Extensions: ${REGISTERED_EXTENSIONS}") + endif() +endmacro(add_vmm_extensions) + +# ------------------------------------------------------------------------------ +# Build configuration and validation +# ------------------------------------------------------------------------------ -set(_validator_expressions "" CACHE INTERNAL "") -set(_validator_messages "" CACHE INTERNAL "") +# Cmake variables to orchestrate adding build rules to the build system +# using add_build_rule() and validate_build() +set(BUILD_RULES "" + CACHE INTERNAL + "A list of build validation rules added with the add_build_rule() macro" +) +set(BUILD_RULE_MESSAGES "" + CACHE INTERNAL + "Messages to be displayed when each of the above build rules fail" +) # Add a new rule to be validated by the build system # @arg FAIL_ON: Any valid cmake expression to be evalued by cmake's if(). If the @@ -114,20 +262,20 @@ macro(add_build_rule) cmake_parse_arguments(ADD_BUILD_RULE "" "${oneVal}" "${multiVal}" ${ARGN}) string(REPLACE ";" " " ADD_BUILD_RULE_FAIL_ON "${ADD_BUILD_RULE_FAIL_ON}") - list(APPEND _validator_expressions "${ADD_BUILD_RULE_FAIL_ON}") - list(APPEND _validator_messages "${ADD_BUILD_RULE_FAIL_MSG}") + list(APPEND BUILD_RULES "${ADD_BUILD_RULE_FAIL_ON}") + list(APPEND BUILD_RULE_MESSAGES "${ADD_BUILD_RULE_FAIL_MSG}") endmacro(add_build_rule) # Validates the current build configuration against all rules configured using # add_build_rule() macro(validate_build) message(STATUS "Validating build configuration...") - list(LENGTH _validator_expressions count) + list(LENGTH BUILD_RULES count) math(EXPR count "${count} - 1") foreach(i RANGE ${count}) - list(GET _validator_expressions ${i} e) - list(GET _validator_messages ${i} m) + list(GET BUILD_RULES ${i} e) + list(GET BUILD_RULE_MESSAGES ${i} m) string(REPLACE " " ";" e "${e}") if(${e}) message("ERROR - Build validation failed: ${m}") @@ -211,6 +359,10 @@ macro(add_config) endif() endmacro(add_config) +# ------------------------------------------------------------------------------ +# Miscellaneous +# ------------------------------------------------------------------------------ + # Print the Bareflank ASCII-art banner macro(print_banner) message(STATUS "${BoldMagenta} ___ __ _ _ ${ColorReset}") @@ -247,3 +399,25 @@ macro(copy_files_if_different) execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_EP_INSTALL_GLOB_DIR}/${file} ${_EP_INSTALL_INSTALL_DIR}/${file}) endforeach() endmacro(copy_files_if_different) + +# Platform independent symbolic link creation +macro(install_symlink filepath sympath) + if(WIN32) + install(CODE "execute_process(COMMAND mklink ${sympath} ${filepath})") + install(CODE "message(STATUS \"Created symlink: ${sympath} -> ${filepath}\")") + else() + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${filepath} ${sympath})") + install(CODE "message(STATUS \"Created symlink: ${sympath} -> ${filepath}\")") + endif() +endmacro(install_symlink) + +# Convenience wrapper around cmake's built-in find_program() +# @arg path: Will hold the path to the program given by "name" on success +# @arg name: The program to be searched for. +# If the program given by "name" is not found, cmake exits with an error +macro(check_program_installed path name) + find_program(${path} ${name}) + if(${path} MATCHES "-NOTFOUND$") + message(FATAL_ERROR "Unable to find ${name}, or ${name} is not installed") + endif() +endmacro(check_program_installed) diff --git a/scripts/cmake/macros_ex.cmake b/scripts/cmake/macros_ex.cmake new file mode 100644 index 000000000..ad2d6ce08 --- /dev/null +++ b/scripts/cmake/macros_ex.cmake @@ -0,0 +1,87 @@ +# +# Bareflank Hypervisor +# Copyright (C) 2015 Assured Information Security, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# ------------------------------------------------------------------------------ +# README +# ------------------------------------------------------------------------------ + +# This file gets included by all Bareflank extensions to provide convinience +# macros for intercting with the base Bareflank build system. These macros +# are for use by Bareflank extensions only (not the base build system). + +# Link the given target with all bfvmm and support libraries +# @arg target: The target to be linked with bfvmm libraries +macro(link_vmm_libs target) + if(VMM_EX_IS_UNITTEST_BUILD) + target_link_libraries(${target} bfcrt_userspace) + target_link_libraries(${target} test_catch) + else() + target_link_libraries(${target} -Wl,--whole-archive bfvmm_main -Wl,--no-whole-archive) + target_link_libraries(${target} --whole-archive -lbfcrt --no-whole-archive) + target_link_libraries(${target} c++) + target_link_libraries(${target} c++abi) + target_link_libraries(${target} pthread) + target_link_libraries(${target} bfunwind) + target_link_libraries(${target} bfsyscall) + target_link_libraries(${target} c) + endif() + + target_link_libraries(${target} bfvmm_support) + target_link_libraries(${target} bfvmm_vcpu_factory) + target_link_libraries(${target} bfvmm_vcpu) + target_link_libraries(${target} bfvmm_vcpu_manager) + target_link_libraries(${target} bfvmm_exit_handler) + target_link_libraries(${target} bfvmm_vmcs) + target_link_libraries(${target} bfvmm_vmxon) + target_link_libraries(${target} bfvmm_memory_manager) + target_link_libraries(${target} bfvmm_serial) + target_link_libraries(${target} bfvmm_debug_ring) + target_link_libraries(${target} bfvmm_intrinsics) +endmacro(link_vmm_libs) + +# Create a VMM executable to be linked with all bfvmm and support libraries +# Usage: call add_vmm_executable() with any arguments supported by cmake's +# built-in add_excecutable() function +macro(add_vmm_executable) + add_executable(${ARGN}) + set(ARGS ${ARGN}) + list(GET ARGS 0 EXE_NAME) + link_vmm_libs(${EXE_NAME}) +endmacro(add_vmm_executable) + +# Create a VMM library to be linked with all bfvmm and support libraries +# Usage: call add_vmm_library() with any arguments supported by cmake's +# built-in add_library() function +macro(add_vmm_library) + add_library(${ARGN}) + set(ARGS ${ARGN}) + list(GET ARGS 0 LIB_NAME) + link_vmm_libs(${LIB_NAME}) +endmacro(add_vmm_library) + +# Install executables to the base build system's vmm sysroot binary directory +# @arg target: The name of the target to be installed +macro(install_vmm_executable target) + install(TARGETS ${target} DESTINATION ${VMM_EX_SYSROOT}/bin) +endmacro(install_vmm_executable) + +# Install libraries to the base build system's vmm sysroot library directory +# @arg target: The name of the target to be installed +macro(install_vmm_library target) + install(TARGETS ${target} DESTINATION ${VMM_EX_SYSROOT}/lib) +endmacro(install_vmm_library) diff --git a/scripts/cmake/vmm_ex.cmake b/scripts/cmake/vmm_ex.cmake new file mode 100644 index 000000000..233f1fb65 --- /dev/null +++ b/scripts/cmake/vmm_ex.cmake @@ -0,0 +1,99 @@ +# +# Bareflank Hypervisor +# Copyright (C) 2015 Assured Information Security, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# ------------------------------------------------------------------------------ +# README +# ------------------------------------------------------------------------------ + +# This file gets included by all Bareflank extensions to set up some cmake +# boilerplate, and to set up default Bareflank conventions. The top level +# CMakeLists.txt for all Bareflank extensions should include this file using: +# +# include(${BF_VMM_EXTENSION}) +# + +# ------------------------------------------------------------------------------ +# Setup VMM extension cmake environment +# ------------------------------------------------------------------------------ + +include(${BF_SCRIPTS_DIR}/cmake/macros.cmake) +include(${BF_SCRIPTS_DIR}/cmake/macros_ex.cmake) +include(${BF_SCRIPTS_DIR}/cmake/config/default_ex.cmake) +if(EXISTS ${VMM_EX_CONFIGS}) + include(${VMM_EX_CONFIGS}) +endif() +include(${BF_FLAGS_DIR}/flags.cmake) + +if(VMM_EX_IS_UNITTEST_BUILD) + include(CTest) + enable_testing(true) + generate_flags( + USERSPACE + ADD_C_FLAGS + "-fvisibility=hidden" + "-DDEBUG_LEVEL=1" + "-DENABLE_UNITTESTING" + ADD_CXX_FLAGS + "-fvisibility=hidden" + "-fvisibility-inlines-hidden" + "-DDEBUG_LEVEL=1" + "-DENABLE_UNITTESTING" + VERBOSE ${BUILD_VERBOSE} + ) + + include_directories( + ${VMM_EX_INCLUDE_DIR} + ${BUILD_SYSROOT_OS}/include + ${BUILD_SYSROOT_TEST}/include + ) + + link_directories( + ${BUILD_SYSROOT_OS}/lib + ${BUILD_SYSROOT_TEST}/lib + ) +else() + generate_flags(VMM) + + include_directories( + ${VMM_EX_INCLUDE_DIR} + ${VMM_EX_SYSROOT}/include/c++/v1 + ${VMM_EX_SYSROOT}/include + ) + + link_directories(${BUILD_SYSROOT_VMM}/lib) +endif() + +# Force a dummy "install" target if this extension doesn't install any files +install(CODE "") + +# ------------------------------------------------------------------------------ +# VMM extension build system conventions +# ------------------------------------------------------------------------------ + +if(EXISTS ${VMM_EX_BUILD_RULES}) + include(${VMM_EX_BUILD_RULES}) + validate_build() +endif() + +if(EXISTS ${VMM_EX_SOURCE_DIR}/CMakeLists.txt) + add_subdirectory(${VMM_EX_SOURCE_DIR}) +endif() + +if(VMM_EX_IS_UNITTEST_BUILD AND EXISTS ${VMM_EX_UNITTEST_DIR}/CMakeLists.txt) + add_subdirectory(${VMM_EX_UNITTEST_DIR}) +endif() diff --git a/scripts/docs/build_instructions.md b/scripts/docs/build_instructions.md new file mode 100644 index 000000000..67d93ea42 --- /dev/null +++ b/scripts/docs/build_instructions.md @@ -0,0 +1,140 @@ +# Configuring and Building the Bareflank Hypervisor + +## Dependencies + +Although Bareflank can be made to run on most systems, the following are the +official supported platforms and their dependencies: + +* Arch Linux: +``` +sudo pacman -S git linux-headers nasm clang cmake +``` + +* Ubuntu 17.04 (or Higher): +``` +sudo apt-get install git build-essential linux-headers-$(uname -r) nasm clang cmake +``` + +Next, create a workspace to hold all Bareflank related source code, build +artifacts and extensions... + +``` +mkdir ~/bareflank +cd ~/bareflank +``` + +...then clone the Bareflank hypervisor repository, and create a build directory: + +``` +git clone -b dev https://github.com/bareflank/hypervisor.git +mkdir build +cd build +``` + +Your Bareflank workspace should look like this: +``` +| bareflank + | - build + | - hypervisor +``` + +Bareflank uses CMake (version 3.6+) to build VMM components, dependencies, and +Bareflank extension projects. In general, CMake requires that you create a +separate build directory for each build you would like to perform. +Build directories can be located anywhere, but we suggest keeping them +at the level of your Bareflank workspace to keep build outputs +close (but separate) from source code and extensions. Unless otherwise noted, +the rest of this document assumes you are building on Ubuntu 17.04 from within a +Bareflank workspace and build directory at ```~/bareflank/build``` + +## Basic Usage + +By default, Bareflank will configure itself for the host operating system and +architecture that you are currently building on. To configure and build with +default settings, run the following from your build directory: + +``` +cmake ../hypervisor +make +``` + +To speed up the build process, Bareflank also supports parallel +builds: + +``` +cmake ../hypervisor +make -j<#-of-cores + 1> +``` + +## Configuring Build Options + +You can change the default build options using a few different methods. +For changing only a few configurations, the easiest method is to specify them +as command line arguments to CMake. You can run cmake as many times as +necessary, specifying different options each time. For example: + +``` +cmake ../hypervisor -DBUILD_VERBOSE=ON +cmake ../hypervisor -DBUILD_TYPE=Release -DBUILD_TARGET_ARCH=x86_64 +``` + +If you would like to specify many build configuration options at once, you +should use a Bareflank build configuration file. By default, Bareflank +creates a file named *bfconfig.cmake* in your build directory, and uses any +options specified there (using CMake syntax) to configure your build. +An example bfconfig.cmake file might look like the following: + +``` +# ~/bareflank/build/bfconfig.cmake (comments start with '#') + +set(BUILD_TYPE Release) +set(BUILD_TARGET_ARCH x86_64) + +set(BUILD_VMM_SHARED OFF) +set(BUILD_VMM_STATIC ON) +set(ENABLE_DEVELOPER_MODE ON) +``` + +You can also specify a relative path to a Bareflank configuration file +explicity: + +``` +cmake ../hypervisor -DBFCONFIG=/path/to/bfconfig.cmake +``` + +To view and configure *all* of the provided build configuration options at once, +you can use the CMake configuration tools *ccmake* (from a command line) and +*cmake-gui* (for a graphical user interface). From your build directory: + +``` +sudo apt-get install cmake-curses-gui +cmake ../hypervisor +ccmake . +``` + +Each time you reconfigure Bareflank with new build options, the build system +validates your new build configuration. If you attempt to configure Bareflank +with (a combinations of) options that aren't supported, the build system +will fail and warn about options that need to be changed. If your build was +configured properly, a usage message will guide you to the next steps (usually +to run ```make```). + +## Developer features +Some build features that may be particularly useful if you would like to modify +Bareflank or develop your own extensions include: +* ENABLE_UNITTESTING - Enables unit testing support. You can can also turn unit +tests for specific projects on/off using the various UNITTEST_ +configurations +* ENABLE_TIDY - Enable support for clang-tidy static analysis checks +* ENABLE_ASTYLE - Enable support for astyle code formatting checks +* ENABLE_DEVELOPER_MODE - Enable all of the above options and automatically run +them on each build. These are the same checks performed by Bareflank CI before +pull requests will be accepted + +Additionally, developers may want to use Ninja to build Bareflank efficiently. +This is supportted by specifying ninja as a generator to CMake: + +``` +cmake ../hypervisor -G Ninja +ninja +``` diff --git a/scripts/docs/extension_instructions.md b/scripts/docs/extension_instructions.md new file mode 100644 index 000000000..3530da7a9 --- /dev/null +++ b/scripts/docs/extension_instructions.md @@ -0,0 +1,190 @@ +# Bareflank Extensions + +Bareflank extensions are the primary mechanism to add features to the base +hypervisor, which is a minimal VMM implementation that does almost nothing. +Extensions are encouraged to integrate with and build on top of other +extensions, and the base Bareflank hypervisor makes it easy to accomplish this. +This document assumes that you have a working Bareflank workspace as described +in the [base build instructions](./build_instructions.md), and that you are +working with the same Bareflank workspace directory structure. + +## Building and Integrating Extensions +Extensions can be added to the Bareflank build system by using the +*vmm_extension()* macro within a Bareflank build configuration file +(bfconfig.cmake). The vmm_extension macro is compatible with all valid arguments +to CMake's built-in +[ExternalProject_Add()](https://cmake.org/cmake/help/v3.6/module/ExternalProject.html) +function. For example, you could add the Bareflank extended apis extension from +GitHub by adding the following to your build configuration file +(bfconfig.cmake): + +``` +vmm_extension( + extended_apis + GIT_REPOSITORY https://github.com/bareflank/extended_apis.git + GIT_TAG dev +) +``` + +## Creating a new extension + +To begin writing your own extension, first create a directory to hold the +extension's source code in your Bareflank workspace: + +``` +mkdir ~/bareflank/my_extension +``` + +Inside your extension directory, create a file called CMakeLists.txt with the +following text: + +``` +cmake_minimum_required(VERSION 3.6) +project(my_extension C CXX) +include(${BF_VMM_EXTENSION}) +``` + +This accomplishes the following: +1. Declare the minimum version of CMake required to build your extension +2. Give your extension project a unique name (in this case: my_extension) +3. Integrate the base Bareflank build system into your extension + +Those three lines are the only requirements for your extension to implement, the +rest is up to you! Next, lets add the new extension to the Bareflank build +system and declare the Bareflank extended apis as a dependency. Add the +following to your build configuration file (bfconfig.cmake): + +``` +vmm_extension( + my_extension + SOURCE_DIR ../my_extension + DEPENDS extended_apis +) +``` + +And finally, build your extension from within your build directory: + +``` +cmake ../hypervisor +make +``` + +## Extension Build Configurations + +Much like the base Bareflank hypervisor, extensions can have their own +extension-specific build configurations. To declare a new configuration for an +extension, use a build configuration file (by convention named configs.cmake) +to the top level of your extension project. Then, use the *add_config()* macro +to add new configurations. For example: + +``` +# Add a config with selectable string values +add_config( + CONFIG_NAME EXAMPLE_BOOL_CONFIG + CONFIG_TYPE STRING + DEFAULT_VAL Option1 + OPTIONS Option1 Option2 Option3 + DESCRIPTION "An example selectable-string configuration" +) + +# Add a boolean configuration that only shows up in cmake-gui as "advanced" +add_config( + CONFIG_NAME EXAMPLE_BOOL_CONFIG + CONFIG_TYPE BOOL + DEFAULT_VAL ON + DESCRIPTION "An example boolean configuration" + ADVANCED +) + +# Add a path configuration +add_config( + CONFIG_NAME EXAMPLE_PATH_CONFIG + CONFIG_TYPE PATH + DEFAULT_VAL "/the/default/value/for/this/path" + DESCRIPTION "An example path configuration" +) + +# Add a file configuration that doesn't get validated by the build system +add_config( + CONFIG_NAME EXAMPLE_PATH_CONFIG + CONFIG_TYPE PATH + DEFAULT_VAL "/the/default/path/to/this/file.txt" + DESCRIPTION "An example file configuration" + SKIP_VALIDATION +) +``` + +Then, the build configuration file (bfconfig.cmake) can specify values for these +configs as follows: + +``` +vmm_extension( + my_extension + SOURCE_DIR ../my_extension + DEPENDS extended_apis + CMAKE_ARGS + -DEXAMPLE_BOOL_CONFIG=OFF + -DEXAMPLE_PATH_CONFIG=/a/path/different/from/the/deafult +) +``` + +Additionally, the base Bareflank build system provides some build configurations +to all Bareflank extensions by default. To view and manipulate all +extension-specific build configurations, use ccmake or cmake-gui: + +``` +ccmake ~/bareflank/build/extensions//build +``` + +## Extension Build Rules + +Bareflank extensions can also provide extension-specific build validation rules +using the same mechanism as the base hypervisor. If any of these build rules +are violated, the build system will error before it begins building the +extension. To declare extension-specific build rules, add a file named +build_rules.cmake to the top level directory of the extension, and use the +*add_build_rule* macro. For example: + +``` +# You can use build configs from the base hypervisor: +add_build_rule( + FAIL_ON ${BUILD_TARGET_ARCH} NOT STREQUAL x86_64 + FAIL_MSG "This extension is only supported on x86_64" +) + +# Or you can use extension-specific build configs: +add_build_rule( + FAIL_ON ${EXAMPLE_OPTION_CONFIG} STREQUAL Option3 AND NOT ${EXAMPLE_BOOL_CONFIG} + FAIL_MSG "Cannot build with EXAMPLE_OPTION_CONFIG Option3 while EXAMPLE_BOOL_CONFIG is OFF" +) +``` + +## Conventions and Default Behaviors + +The recommended structure for Bareflank extensions is as follows: + +``` +| bareflank/ (<-- workspace directory) + | - build/ + | - hypervisor/ + | - my_extension/ (<-- extension directory) + | - build_rules.cmake + | - CMakeLists.txt + | - config.cmake + | - include/ + | - src/ + | - test/ +``` + +If you follow this suggested structure, the Bareflank build system will +perform the following for you automatically: + +1. The ```include``` directory will be added to your extension's header include +path +2. CMake will add ```src``` as a build subdirectory +3. CMake will add both ```src``` and ```test``` as subdirectories for unit-test +builds +4. The build system will add any extension-specific build configurations +declared in config.cmake +5. The build system will validate any extension-specific build rules declared +in build_rules.cmake