arm: Add app data section alignment constraints
This patch adds application data section alignment constraints to match the region definition requirements for ARM MPUs. Most MPUs require a minimum of 32 bytes of alignment for any regions, but some require power of two alignment to the size of a region. This requires that the linker align the application data section to the size of the section. This requires a linker pass to determine the size. Once this is accomplished the correct value is added to a linker include file that is utilized in subsequent linker operations. Signed-off-by: Andy Gross <andy.gross@linaro.org>
This commit is contained in:
parent
1f0ff06e38
commit
e8860fe8be
5 changed files with 171 additions and 2 deletions
|
@ -514,6 +514,14 @@ if(CONFIG_APPLICATION_MEMORY)
|
||||||
endforeach()
|
endforeach()
|
||||||
endif() # CONFIG_APPLICATION_MEMORY
|
endif() # CONFIG_APPLICATION_MEMORY
|
||||||
|
|
||||||
|
# Declare MPU userspace dependencies before the linker scripts to make
|
||||||
|
# sure the order of dependencies are met
|
||||||
|
if(CONFIG_CPU_HAS_MPU AND CONFIG_USERSPACE)
|
||||||
|
if(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT)
|
||||||
|
set(ALIGN_SIZING_DEP app_sizing_prebuilt linker_app_sizing_script)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
function(construct_add_custom_command_for_linker_pass linker_output_name output_variable)
|
function(construct_add_custom_command_for_linker_pass linker_output_name output_variable)
|
||||||
set(linker_cmd_file_name ${linker_output_name}.cmd)
|
set(linker_cmd_file_name ${linker_output_name}.cmd)
|
||||||
|
|
||||||
|
@ -566,9 +574,11 @@ construct_add_custom_command_for_linker_pass(linker custom_command)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
${custom_command}
|
${custom_command}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
linker_script
|
linker_script
|
||||||
DEPENDS
|
DEPENDS
|
||||||
|
${ALIGN_SIZING_DEP}
|
||||||
linker.cmd
|
linker.cmd
|
||||||
offsets_h
|
offsets_h
|
||||||
)
|
)
|
||||||
|
@ -748,11 +758,59 @@ get_property(GKSF GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES)
|
||||||
get_property(TOPT GLOBAL PROPERTY TOPT)
|
get_property(TOPT GLOBAL PROPERTY TOPT)
|
||||||
set_ifndef( TOPT -T)
|
set_ifndef( TOPT -T)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
$ENV{ZEPHYR_BASE}/include/arch/arm/cortex_m/scripts/app_data_alignment.ld
|
||||||
|
${PROJECT_BINARY_DIR}/include/generated/app_data_alignment.ld)
|
||||||
|
|
||||||
|
if(CONFIG_CPU_HAS_MPU AND CONFIG_USERSPACE)
|
||||||
|
|
||||||
|
if(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT)
|
||||||
|
|
||||||
|
construct_add_custom_command_for_linker_pass(linker_app_sizing custom_command)
|
||||||
|
add_custom_command(
|
||||||
|
${custom_command}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
linker_app_sizing_script
|
||||||
|
DEPENDS
|
||||||
|
linker_app_sizing.cmd
|
||||||
|
offsets_h
|
||||||
|
)
|
||||||
|
|
||||||
|
set_property(TARGET
|
||||||
|
linker_app_sizing_script
|
||||||
|
PROPERTY INCLUDE_DIRECTORIES
|
||||||
|
${ZEPHYR_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# For systems with MPUs, the size of the application data section must
|
||||||
|
# be determined so that MPU alignment requirements can be met.
|
||||||
|
# Create a app_sizing_prebuilt target so we can do this before the
|
||||||
|
# other ELF files are built
|
||||||
|
set(GEN_APP_ALIGN $ENV{ZEPHYR_BASE}/scripts/gen_alignment_script.py)
|
||||||
|
add_executable( app_sizing_prebuilt misc/empty_file.c)
|
||||||
|
target_link_libraries(app_sizing_prebuilt ${TOPT} ${PROJECT_BINARY_DIR}/linker_app_sizing.cmd ${zephyr_lnk})
|
||||||
|
set_property(TARGET app_sizing_prebuilt PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_app_sizing.cmd)
|
||||||
|
add_dependencies( app_sizing_prebuilt linker_app_sizing_script offsets)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET app_sizing_prebuilt
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} ${GEN_APP_ALIGN}
|
||||||
|
--output ./include/generated/app_data_alignment.ld
|
||||||
|
--kernel $<TARGET_FILE:app_sizing_prebuilt>
|
||||||
|
VERBATIM
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# FIXME: Is there any way to get rid of empty_file.c?
|
# FIXME: Is there any way to get rid of empty_file.c?
|
||||||
add_executable( zephyr_prebuilt misc/empty_file.c)
|
add_executable( zephyr_prebuilt misc/empty_file.c)
|
||||||
target_link_libraries(zephyr_prebuilt ${TOPT} ${PROJECT_BINARY_DIR}/linker.cmd ${zephyr_lnk})
|
target_link_libraries(zephyr_prebuilt ${TOPT} ${PROJECT_BINARY_DIR}/linker.cmd ${zephyr_lnk})
|
||||||
set_property(TARGET zephyr_prebuilt PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker.cmd)
|
set_property(TARGET zephyr_prebuilt PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker.cmd)
|
||||||
add_dependencies( zephyr_prebuilt linker_script offsets)
|
add_dependencies( zephyr_prebuilt ${ALIGN_SIZING_DEP} linker_script offsets)
|
||||||
|
|
||||||
|
|
||||||
if(NOT CONFIG_NATIVE_APPLICATION)
|
if(NOT CONFIG_NATIVE_APPLICATION)
|
||||||
|
@ -769,9 +827,12 @@ if(GKOF OR GKSF)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
${custom_command}
|
${custom_command}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_target(
|
add_custom_target(
|
||||||
linker_pass_final_script
|
linker_pass_final_script
|
||||||
DEPENDS
|
DEPENDS
|
||||||
|
${ALIGN_SIZING_DEP}
|
||||||
|
zephyr_prebuilt
|
||||||
linker_pass_final.cmd
|
linker_pass_final.cmd
|
||||||
offsets_h
|
offsets_h
|
||||||
)
|
)
|
||||||
|
@ -784,7 +845,7 @@ if(GKOF OR GKSF)
|
||||||
add_executable( kernel_elf misc/empty_file.c ${GKSF})
|
add_executable( kernel_elf misc/empty_file.c ${GKSF})
|
||||||
target_link_libraries(kernel_elf ${GKOF} ${TOPT} ${PROJECT_BINARY_DIR}/linker_pass_final.cmd ${zephyr_lnk})
|
target_link_libraries(kernel_elf ${GKOF} ${TOPT} ${PROJECT_BINARY_DIR}/linker_pass_final.cmd ${zephyr_lnk})
|
||||||
set_property(TARGET kernel_elf PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_pass_final.cmd)
|
set_property(TARGET kernel_elf PROPERTY LINK_DEPENDS ${PROJECT_BINARY_DIR}/linker_pass_final.cmd)
|
||||||
add_dependencies( kernel_elf linker_pass_final_script)
|
add_dependencies( kernel_elf ${ALIGN_SIZING_DEP} linker_pass_final_script)
|
||||||
else()
|
else()
|
||||||
set(logical_target_for_zephyr_elf zephyr_prebuilt)
|
set(logical_target_for_zephyr_elf zephyr_prebuilt)
|
||||||
# Use the prebuilt elf as the final elf since we don't have a
|
# Use the prebuilt elf as the final elf since we don't have a
|
||||||
|
|
|
@ -225,6 +225,15 @@ config CPU_HAS_MPU
|
||||||
help
|
help
|
||||||
This option is enabled when the CPU has a Memory Protection Unit (MPU).
|
This option is enabled when the CPU has a Memory Protection Unit (MPU).
|
||||||
|
|
||||||
|
config MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT
|
||||||
|
bool
|
||||||
|
# Omit prompt to signify "hidden" option
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This option is enabled when the MPU requires a power of two alignment
|
||||||
|
and size for MPU regions.
|
||||||
|
|
||||||
|
|
||||||
menu "Floating Point Options"
|
menu "Floating Point Options"
|
||||||
depends on CPU_HAS_FPU
|
depends on CPU_HAS_FPU
|
||||||
|
|
||||||
|
|
9
include/arch/arm/cortex_m/scripts/app_data_alignment.ld
Normal file
9
include/arch/arm/cortex_m/scripts/app_data_alignment.ld
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Linaro Limited.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Set initial alignment to the 32 byte minimum for all MPUs */
|
||||||
|
_app_data_align = 32;
|
||||||
|
. = ALIGN(32);
|
|
@ -215,6 +215,9 @@ SECTIONS
|
||||||
#ifdef CONFIG_APPLICATION_MEMORY
|
#ifdef CONFIG_APPLICATION_MEMORY
|
||||||
SECTION_DATA_PROLOGUE(_APP_DATA_SECTION_NAME, (OPTIONAL),)
|
SECTION_DATA_PROLOGUE(_APP_DATA_SECTION_NAME, (OPTIONAL),)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#include <app_data_alignment.ld>
|
||||||
|
|
||||||
__app_ram_start = .;
|
__app_ram_start = .;
|
||||||
__app_data_ram_start = .;
|
__app_data_ram_start = .;
|
||||||
_image_ram_start = .;
|
_image_ram_start = .;
|
||||||
|
@ -242,7 +245,15 @@ SECTIONS
|
||||||
APP_INPUT_SECTION(".noinit.*")
|
APP_INPUT_SECTION(".noinit.*")
|
||||||
} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION)
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION)
|
||||||
|
|
||||||
|
__app_last_address_used = .;
|
||||||
|
|
||||||
|
/* Pad out application ram area to make MPU friendly */
|
||||||
|
SECTION_PROLOGUE(app_pad, (NOLOAD OPTIONAL),)
|
||||||
|
{
|
||||||
|
. = ALIGN(_app_data_align);
|
||||||
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION)
|
||||||
__app_ram_end = .;
|
__app_ram_end = .;
|
||||||
|
__app_ram_size = __app_ram_end - __app_ram_start;
|
||||||
#endif /* CONFIG_APPLICATION_MEMORY */
|
#endif /* CONFIG_APPLICATION_MEMORY */
|
||||||
|
|
||||||
SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),)
|
SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),)
|
||||||
|
|
79
scripts/gen_alignment_script.py
Executable file
79
scripts/gen_alignment_script.py
Executable file
|
@ -0,0 +1,79 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Linaro Limited
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import pprint
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
|
import elftools
|
||||||
|
from elftools.elf.elffile import ELFFile
|
||||||
|
from elftools.dwarf import descriptions
|
||||||
|
from elftools.elf.sections import SymbolTableSection
|
||||||
|
|
||||||
|
if LooseVersion(elftools.__version__) < LooseVersion('0.24'):
|
||||||
|
sys.stderr.write("pyelftools is out of date, need version 0.24 or later\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_symbols(obj):
|
||||||
|
for section in obj.iter_sections():
|
||||||
|
if isinstance(section, SymbolTableSection):
|
||||||
|
return {sym.name: sym.entry.st_value
|
||||||
|
for sym in section.iter_symbols()}
|
||||||
|
|
||||||
|
raise LookupError("Could not find symbol table")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
global args
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=__doc__,
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-k", "--kernel", required=True,
|
||||||
|
help="Input zephyr ELF binary")
|
||||||
|
parser.add_argument(
|
||||||
|
"-o", "--output", required=True,
|
||||||
|
help="Output linker file")
|
||||||
|
parser.add_argument(
|
||||||
|
"-v", "--verbose", action="store_true",
|
||||||
|
help="Print extra debugging information")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parse_args()
|
||||||
|
|
||||||
|
bit_len = None
|
||||||
|
|
||||||
|
with open(args.kernel, "rb") as fp:
|
||||||
|
elf = ELFFile(fp)
|
||||||
|
args.little_endian = elf.little_endian
|
||||||
|
syms = get_symbols(elf)
|
||||||
|
|
||||||
|
app_ram_size = syms['__app_last_address_used'] - \
|
||||||
|
syms['__app_ram_start']
|
||||||
|
bit_len = app_ram_size.bit_length()
|
||||||
|
|
||||||
|
if bit_len:
|
||||||
|
align_size = 1 << bit_len
|
||||||
|
else:
|
||||||
|
align_size = 32
|
||||||
|
|
||||||
|
with open(args.output, "w") as fp:
|
||||||
|
fp.write("/***********************************************\n")
|
||||||
|
fp.write(" * Generated file, do not modify\n")
|
||||||
|
fp.write(" **********************************************/\n")
|
||||||
|
fp.write("_app_data_align = " + str(align_size) + ";\n")
|
||||||
|
fp.write(". = ALIGN(_app_data_align);\n")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Add table
Add a link
Reference in a new issue