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:
Andy Gross 2018-02-01 01:12:32 -06:00 committed by Andrew Boie
commit e8860fe8be
5 changed files with 171 additions and 2 deletions

View file

@ -514,6 +514,14 @@ if(CONFIG_APPLICATION_MEMORY)
endforeach()
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)
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(
${custom_command}
)
add_custom_target(
linker_script
DEPENDS
${ALIGN_SIZING_DEP}
linker.cmd
offsets_h
)
@ -748,11 +758,59 @@ get_property(GKSF GLOBAL PROPERTY GENERATED_KERNEL_SOURCE_FILES)
get_property(TOPT GLOBAL PROPERTY TOPT)
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?
add_executable( zephyr_prebuilt misc/empty_file.c)
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)
add_dependencies( zephyr_prebuilt linker_script offsets)
add_dependencies( zephyr_prebuilt ${ALIGN_SIZING_DEP} linker_script offsets)
if(NOT CONFIG_NATIVE_APPLICATION)
@ -769,9 +827,12 @@ if(GKOF OR GKSF)
add_custom_command(
${custom_command}
)
add_custom_target(
linker_pass_final_script
DEPENDS
${ALIGN_SIZING_DEP}
zephyr_prebuilt
linker_pass_final.cmd
offsets_h
)
@ -784,7 +845,7 @@ if(GKOF OR 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})
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()
set(logical_target_for_zephyr_elf zephyr_prebuilt)
# Use the prebuilt elf as the final elf since we don't have a

View file

@ -225,6 +225,15 @@ config CPU_HAS_MPU
help
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"
depends on CPU_HAS_FPU

View 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);

View file

@ -215,6 +215,9 @@ SECTIONS
#ifdef CONFIG_APPLICATION_MEMORY
SECTION_DATA_PROLOGUE(_APP_DATA_SECTION_NAME, (OPTIONAL),)
{
#include <app_data_alignment.ld>
__app_ram_start = .;
__app_data_ram_start = .;
_image_ram_start = .;
@ -242,7 +245,15 @@ SECTIONS
APP_INPUT_SECTION(".noinit.*")
} 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_size = __app_ram_end - __app_ram_start;
#endif /* CONFIG_APPLICATION_MEMORY */
SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),)

79
scripts/gen_alignment_script.py Executable file
View 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()