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()
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
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
|
||||
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
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