1#
2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6
7# This module provides `DeclareRootserver` for making an executable target a rootserver
8# and bundling it with a kernel.elf and any required loaders into an `images` directory
9# in the top level build directory.
10include_guard(GLOBAL)
11
12# Helper function for modifying the linker flags of a target to set the entry point as _sel4_start
13function(SetSeL4Start target)
14    set_property(
15        TARGET ${target}
16        APPEND_STRING
17        PROPERTY LINK_FLAGS " -Wl,-u_sel4_start -Wl,-e_sel4_start "
18    )
19endfunction(SetSeL4Start)
20
21# We need to the real non symlinked list path in order to find the linker script that is in
22# the common-tool directory
23find_file(
24    TLS_ROOTSERVER tls_rootserver.lds
25    PATHS "${CMAKE_CURRENT_LIST_DIR}"
26    CMAKE_FIND_ROOT_PATH_BOTH
27)
28mark_as_advanced(TLS_ROOTSERVER)
29
30find_file(UIMAGE_TOOL make-uimage PATHS "${CMAKE_CURRENT_LIST_DIR}" CMAKE_FIND_ROOT_PATH_BOTH)
31mark_as_advanced(UIMAGE_TOOL)
32
33config_option(
34    UseRiscVBBL RISCV_BBL "Use the Berkeley Boot Loader."
35    DEFAULT ON
36    DEPENDS "KernelArchRiscV"
37)
38
39if(UseRiscVBBL)
40    set(BBL_PATH ${CMAKE_SOURCE_DIR}/tools/riscv-pk CACHE STRING "BBL Folder location")
41    mark_as_advanced(FORCE BBL_PATH)
42endif()
43
44function(DeclareRootserver rootservername)
45    SetSeL4Start(${rootservername})
46    set_property(
47        TARGET ${rootservername}
48        APPEND_STRING
49        PROPERTY LINK_FLAGS " -Wl,-T ${TLS_ROOTSERVER} "
50    )
51    if("${KernelArch}" STREQUAL "x86")
52        set(
53            IMAGE_NAME
54            "${CMAKE_BINARY_DIR}/images/${rootservername}-image-${KernelSel4Arch}-${KernelPlatform}"
55        )
56        set(
57            KERNEL_IMAGE_NAME
58            "${CMAKE_BINARY_DIR}/images/kernel-${KernelSel4Arch}-${KernelPlatform}"
59        )
60        # Declare targets for building the final kernel image
61        if(Kernel64)
62            add_custom_command(
63                OUTPUT "${KERNEL_IMAGE_NAME}"
64                COMMAND
65                    ${CMAKE_OBJCOPY} -O elf32-i386 $<TARGET_FILE:kernel.elf> "${KERNEL_IMAGE_NAME}"
66                VERBATIM
67                DEPENDS kernel.elf
68                COMMENT "objcopy kernel into bootable elf"
69            )
70        else()
71            add_custom_command(
72                OUTPUT "${KERNEL_IMAGE_NAME}"
73                COMMAND cp $<TARGET_FILE:kernel.elf> "${KERNEL_IMAGE_NAME}"
74                VERBATIM
75                DEPENDS kernel.elf
76            )
77        endif()
78        add_custom_command(
79            OUTPUT "${IMAGE_NAME}"
80            COMMAND cp $<TARGET_FILE:${rootservername}> "${IMAGE_NAME}"
81            DEPENDS ${rootservername}
82        )
83        add_custom_target(
84            rootserver_image ALL
85            DEPENDS
86                "${IMAGE_NAME}"
87                "${KERNEL_IMAGE_NAME}"
88                kernel.elf
89                $<TARGET_FILE:${rootservername}>
90                ${rootservername}
91        )
92    elseif(KernelArchARM OR KernelArchRiscV)
93        set(
94            IMAGE_NAME
95            "${CMAKE_BINARY_DIR}/images/${rootservername}-image-${KernelArch}-${KernelPlatform}"
96        )
97        set(elf_target_file $<TARGET_FILE:elfloader>)
98        if(KernelArchRiscV)
99            if(KernelSel4ArchRiscV32)
100                set(march rv32imafdc)
101            else()
102                set(march rv64imafdc)
103            endif()
104            if(UseRiscVBBL)
105                # Package up our final elf image into the Berkeley boot loader.
106                # The host string is extracted from the cross compiler setting
107                # minus the trailing '-'
108                if("${CROSS_COMPILER_PREFIX}" STREQUAL "")
109                    message(FATAL_ERROR "CROSS_COMPILER_PREFIX not set.")
110                endif()
111
112                string(
113                    REGEX
114                    REPLACE
115                        "^(.*)-$"
116                        "\\1"
117                        host
118                        "${CROSS_COMPILER_PREFIX}"
119                )
120                get_filename_component(host ${host} NAME)
121                file(GLOB_RECURSE deps)
122                add_custom_command(
123                    OUTPUT "${CMAKE_BINARY_DIR}/bbl/bbl"
124                    COMMAND mkdir -p ${CMAKE_BINARY_DIR}/bbl
125                    COMMAND
126                        cd ${CMAKE_BINARY_DIR}/bbl && ${BBL_PATH}/configure
127                        --quiet
128                        --host=${host}
129                        --with-arch=${march}
130                        --with-payload=${elf_target_file}
131                            && make -s clean && make -s > /dev/null
132                    DEPENDS ${elf_target_file} elfloader ${USES_TERMINAL_DEBUG}
133                )
134                set(elf_target_file "${CMAKE_BINARY_DIR}/bbl/bbl")
135            endif()
136        endif()
137        set(binary_efi_list "binary;efi")
138        if(${ElfloaderImage} IN_LIST binary_efi_list)
139            # If not an elf we construct an intermediate rule to do an objcopy to binary
140            add_custom_command(
141                OUTPUT "${IMAGE_NAME}"
142                COMMAND
143                    ${CMAKE_OBJCOPY} -O binary ${elf_target_file} "${IMAGE_NAME}"
144                DEPENDS ${elf_target_file} elfloader
145            )
146        elseif("${ElfloaderImage}" STREQUAL "uimage")
147            # Construct payload for U-Boot.
148
149            if("${KernelArmSel4Arch}" STREQUAL "aarch32")
150                set(UIMAGE_ARCH "arm")
151            elseif(KernelSel4ArchAarch64)
152                set(UIMAGE_ARCH "arm64")
153            else()
154                message(FATAL_ERROR "uimage: Unsupported architecture: ${KernelArch}")
155            endif()
156
157            add_custom_command(
158                OUTPUT "${IMAGE_NAME}"
159                COMMAND
160                    ${UIMAGE_TOOL} ${CMAKE_OBJCOPY} ${elf_target_file} ${UIMAGE_ARCH} ${IMAGE_NAME}
161                DEPENDS ${elf_target_file} elfloader
162            )
163        else()
164            add_custom_command(
165                OUTPUT "${IMAGE_NAME}"
166                COMMAND
167                    ${CMAKE_COMMAND} -E copy ${elf_target_file} "${IMAGE_NAME}"
168                DEPENDS ${elf_target_file} elfloader
169            )
170        endif()
171        add_custom_target(rootserver_image ALL DEPENDS "${IMAGE_NAME}" elfloader ${rootservername})
172        # Set the output name for the rootserver instead of leaving it to the generator. We need
173        # to do this so that we can put the rootserver image name as a property and have the
174        # elfloader pull it out using a generator expression, since generator expression cannot
175        # nest (i.e. in the expansion of $<TARGET_FILE:tgt> 'tgt' cannot itself be a generator
176        # expression. Nor can a generator expression expand to another generator expression and
177        # get expanded again. As a result we just fix the output name and location of the rootserver
178        set_property(TARGET "${rootservername}" PROPERTY OUTPUT_NAME "${rootservername}")
179        get_property(rootimage TARGET "${rootservername}" PROPERTY OUTPUT_NAME)
180        get_property(dir TARGET "${rootservername}" PROPERTY BINARY_DIR)
181        set_property(TARGET rootserver_image PROPERTY ROOTSERVER_IMAGE "${dir}/${rootimage}")
182    else()
183        message(FATAL_ERROR "Unsupported architecture.")
184    endif()
185    # Store the image and kernel image as properties
186    # We use relative paths to the build directory
187    file(RELATIVE_PATH IMAGE_NAME_REL ${CMAKE_BINARY_DIR} ${IMAGE_NAME})
188    if(NOT "${KERNEL_IMAGE_NAME}" STREQUAL "")
189        file(RELATIVE_PATH KERNEL_IMAGE_NAME_REL ${CMAKE_BINARY_DIR} ${KERNEL_IMAGE_NAME})
190    endif()
191    set_property(TARGET rootserver_image PROPERTY IMAGE_NAME "${IMAGE_NAME_REL}")
192    set_property(TARGET rootserver_image PROPERTY KERNEL_IMAGE_NAME "${KERNEL_IMAGE_NAME_REL}")
193endfunction(DeclareRootserver)
194