kernel: app_smem: allowing pinning memory partitions

This allows memory partitions to be put into the pinned
section so they are available during boot. For example,
the stack guard (in libc partition) is needed during boot
but before the paging mechanism is initialized. Without
pinning it in physical memory, it would fault in early
boot process.

A new cmake property app_smem,pinned_partitions is
introduced so that additional partitions can be pinned
if needed.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2021-07-12 13:33:32 -07:00 committed by Christopher Friedt
parent e88afd2c37
commit 2117a2a44b
10 changed files with 216 additions and 26 deletions

View file

@ -355,6 +355,7 @@ endif()
# Declare MPU userspace dependencies before the linker scripts to make
# sure the order of dependencies are met
if(CONFIG_USERSPACE)
add_custom_target(app_smem)
set(APP_SMEM_ALIGNED_DEP app_smem_aligned_linker)
set(APP_SMEM_UNALIGNED_DEP app_smem_unaligned_linker)
endif()
@ -985,18 +986,42 @@ toolchain_ld_configure_files()
if(CONFIG_USERSPACE)
set(APP_SMEM_ALIGNED_LD "${PROJECT_BINARY_DIR}/include/generated/app_smem_aligned.ld")
set(APP_SMEM_UNALIGNED_LD "${PROJECT_BINARY_DIR}/include/generated/app_smem_unaligned.ld")
if(CONFIG_LINKER_USE_PINNED_SECTION)
set(APP_SMEM_PINNED_ALIGNED_LD
"${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_aligned.ld")
set(APP_SMEM_PINNED_UNALIGNED_LD
"${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_unaligned.ld")
if(NOT CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT)
# The libc partition may hold symbols that are required during boot process,
# for example, stack guard (if enabled). So the libc partition must be pinned
# if not sections are in physical memory at boot, as the paging mechanism is
# only initialized post-kernel.
set_property(TARGET app_smem APPEND PROPERTY pinned_partitions "z_libc_partition")
endif()
get_property(APP_SMEM_PINNED_PARTITION_LIST TARGET app_smem PROPERTY pinned_partitions)
if(APP_SMEM_PINNED_PARTITION_LIST)
list(JOIN APP_SMEM_PINNED_PARTITION_LIST "," APP_SMEM_PINNED_PARTITION_LIST_ARG_CSL)
set(APP_SMEM_PINNED_PARTITION_LIST_ARG "--pinpartitions=${APP_SMEM_PINNED_PARTITION_LIST_ARG_CSL}")
endif()
endif()
set(OBJ_FILE_DIR "${PROJECT_BINARY_DIR}/../")
add_custom_target(
${APP_SMEM_ALIGNED_DEP}
DEPENDS
${APP_SMEM_ALIGNED_LD}
${APP_SMEM_PINNED_ALIGNED_LD}
)
add_custom_target(
${APP_SMEM_UNALIGNED_DEP}
DEPENDS
${APP_SMEM_UNALIGNED_LD}
${APP_SMEM_PINNED_UNALIGNED_LD}
)
if(CONFIG_NEWLIB_LIBC)
@ -1007,11 +1032,13 @@ if(CONFIG_USERSPACE)
endif()
add_custom_command(
OUTPUT ${APP_SMEM_UNALIGNED_LD}
OUTPUT ${APP_SMEM_UNALIGNED_LD} ${APP_SMEM_PINNED_UNALIGNED_LD}
COMMAND ${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/gen_app_partitions.py
-d ${OBJ_FILE_DIR}
-o ${APP_SMEM_UNALIGNED_LD}
$<$<BOOL:${APP_SMEM_PINNED_UNALIGNED_LD}>:--pinoutput=${APP_SMEM_PINNED_UNALIGNED_LD}>
${APP_SMEM_PINNED_PARTITION_LIST_ARG}
${NEWLIB_PART}
$<TARGET_PROPERTY:zephyr_property_target,COMPILE_OPTIONS>
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
@ -1029,6 +1056,7 @@ if(CONFIG_USERSPACE)
${CODE_RELOCATION_DEP}
${APP_SMEM_UNALIGNED_DEP}
${APP_SMEM_UNALIGNED_LD}
${APP_SMEM_PINNED_UNALIGNED_LD}
zephyr_generated_headers
)
@ -1061,11 +1089,13 @@ if(CONFIG_USERSPACE)
add_dependencies( app_smem_unaligned_prebuilt linker_app_smem_unaligned_script ${OFFSETS_LIB})
add_custom_command(
OUTPUT ${APP_SMEM_ALIGNED_LD}
OUTPUT ${APP_SMEM_ALIGNED_LD} ${APP_SMEM_PINNED_ALIGNED_LD}
COMMAND ${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/gen_app_partitions.py
-e $<TARGET_FILE:app_smem_unaligned_prebuilt>
-o ${APP_SMEM_ALIGNED_LD}
$<$<BOOL:${APP_SMEM_PINNED_ALIGNED_LD}>:--pinoutput=${APP_SMEM_PINNED_ALIGNED_LD}>
${APP_SMEM_PINNED_PARTITION_LIST_ARG}
${NEWLIB_PART}
$<TARGET_PROPERTY:zephyr_property_target,COMPILE_OPTIONS>
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>

View file

@ -18,4 +18,18 @@ macro(toolchain_ld_configure_files)
configure_file(
${ZEPHYR_BASE}/include/linker/app_smem_unaligned.ld
${PROJECT_BINARY_DIR}/include/generated/app_smem_unaligned.ld)
if(CONFIG_LINKER_USE_PINNED_SECTION)
configure_file(
${ZEPHYR_BASE}/include/linker/app_smem_pinned.ld
${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned.ld)
configure_file(
${ZEPHYR_BASE}/include/linker/app_smem_pinned_aligned.ld
${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_aligned.ld)
configure_file(
${ZEPHYR_BASE}/include/linker/app_smem_pinned_unaligned.ld
${PROJECT_BINARY_DIR}/include/generated/app_smem_pinned_unaligned.ld)
endif()
endmacro()

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This hackish way of including files is due to CMake issues:
* https://gitlab.kitware.com/cmake/cmake/issues/11985
* https://gitlab.kitware.com/cmake/cmake/issues/13718
*
* When using the "Unix Makefiles" generator, CMake simply
* greps for "#include" to generate dependency list.
* So if doing it normally, both files are being included
* in the dependency list. This creates weird dependency
* issue:
*
* 1. Using A.ld to create a linker script A.cmd.
* 2. Using A.cmd to generate A_prebuilt.elf.
* 3. Using A_prebuilt.elf to create B.ld.
* 4. Creating B.cmd with B.ld.
* 5. Creating B_prebuilt.elf using B.cmd.
*
* Since the dependency list of A.cmd contains both
* A.ld and B.ld, when make is invoked again, B.ld
* is newer than A.cmd so everything from this point on
* gets rebuilt. In order to break this cycle, this
* hackish needs to be used since CMake does not parse
* macros, and thus these will not appear in
* the dependency list. The dependencies should then be
* put in CMakeLists.txt instead.
*
* Note: Ninja generator does not suffer from this issue.
*/
#ifdef LINKER_APP_SMEM_UNALIGNED
#define APP_SMEM_LD <app_smem_pinned_unaligned.ld>
#else
#define APP_SMEM_LD <app_smem_pinned_aligned.ld>
#endif
#include APP_SMEM_LD
#undef APP_SMEM_LD

View file

@ -0,0 +1,7 @@
/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Empty file */

View file

@ -0,0 +1,7 @@
/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Empty file */

View file

@ -197,6 +197,13 @@ extern char _app_smem_size[];
extern char _app_smem_rom_start[];
extern char _app_smem_num_words[];
#ifdef CONFIG_LINKER_USE_PINNED_SECTION
extern char _app_smem_pinned_start[];
extern char _app_smem_pinned_end[];
extern char _app_smem_pinned_size[];
extern char _app_smem_pinned_num_words[];
#endif
/* Memory owned by the kernel. Start and end will be aligned for memory
* management/protection hardware for the target architecture.
*

View file

@ -28,6 +28,8 @@
#define _APP_BSS_SECTION_NAME app_bss
#define _APP_NOINIT_SECTION_NAME app_noinit
#define _APP_SMEM_PINNED_SECTION_NAME app_smem_pinned
#define _UNDEFINED_SECTION_NAME undefined
/* Interrupts */

View file

@ -21,6 +21,7 @@
#include <sys/libc-hooks.h>
#include <sys/mutex.h>
#include <inttypes.h>
#include <linker/linker-defs.h>
#ifdef Z_LIBC_PARTITION_EXISTS
K_APPMEM_PARTITION_DEFINE(z_libc_partition);
@ -859,7 +860,29 @@ static int app_shmem_bss_zero(const struct device *unused)
region = (struct z_app_region *)&__app_shmem_regions_start;
for ( ; region < end; region++) {
(void)memset(region->bss_start, 0, region->bss_size);
#if defined(CONFIG_DEMAND_PAGING) && !defined(CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT)
/* When BSS sections are not present at boot, we need to wait for
* paging mechanism to be initialized before we can zero out BSS.
*/
extern bool z_sys_post_kernel;
bool do_clear = z_sys_post_kernel;
/* During pre-kernel init, z_sys_post_kernel == false, but
* with pinned rodata region, so clear. Otherwise skip.
* In post-kernel init, z_sys_post_kernel == true,
* skip those in pinned rodata region as they have already
* been cleared and possibly already in use. Otherwise clear.
*/
if (((uint8_t *)region->bss_start >= (uint8_t *)_app_smem_pinned_start) &&
((uint8_t *)region->bss_start < (uint8_t *)_app_smem_pinned_end)) {
do_clear = !do_clear;
}
if (do_clear)
#endif /* CONFIG_DEMAND_PAGING && !CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT */
{
(void)memset(region->bss_start, 0, region->bss_size);
}
}
return 0;
@ -867,6 +890,13 @@ static int app_shmem_bss_zero(const struct device *unused)
SYS_INIT(app_shmem_bss_zero, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#if defined(CONFIG_DEMAND_PAGING) && !defined(CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT)
/* When BSS sections are not present at boot, we need to wait for
* paging mechanism to be initialized before we can zero out BSS.
*/
SYS_INIT(app_shmem_bss_zero, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
#endif /* CONFIG_DEMAND_PAGING && !CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT */
/*
* Default handlers if otherwise unimplemented
*/

View file

@ -75,16 +75,24 @@ footer_template = """
"""
linker_start_seq = """
SECTION_PROLOGUE(_APP_SMEM_SECTION_NAME,,)
{
SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,)
{{
APP_SHARED_ALIGN;
_app_smem_start = .;
_app_smem{0}_start = .;
"""
linker_end_seq = """
APP_SHARED_ALIGN;
_app_smem_end = .;
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
_app_smem{0}_end = .;
}} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
"""
empty_app_smem = """
SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,)
{{
_app_smem{0}_start = .;
_app_smem{0}_end = .;
}} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
"""
size_cal_string = """
@ -159,23 +167,29 @@ def parse_elf_file(partitions):
partitions[partition_name][SZ] += size
def generate_final_linker(linker_file, partitions):
string = linker_start_seq
size_string = ''
for partition, item in partitions.items():
string += data_template.format(partition)
if LIB in item:
for lib in item[LIB]:
string += library_data_template.format(lib)
string += bss_template.format(partition)
if LIB in item:
for lib in item[LIB]:
string += library_bss_template.format(lib)
string += footer_template.format(partition)
size_string += size_cal_string.format(partition)
def generate_final_linker(linker_file, partitions, lnkr_sect=""):
string = ""
if len(partitions) > 0:
string = linker_start_seq.format(lnkr_sect, lnkr_sect.upper())
size_string = ''
for partition, item in partitions.items():
string += data_template.format(partition)
if LIB in item:
for lib in item[LIB]:
string += library_data_template.format(lib)
string += bss_template.format(partition, lnkr_sect)
if LIB in item:
for lib in item[LIB]:
string += library_bss_template.format(lib)
string += footer_template.format(partition)
size_string += size_cal_string.format(partition)
string += linker_end_seq.format(lnkr_sect)
string += size_string
else:
string = empty_app_smem.format(lnkr_sect, lnkr_sect.upper())
string += linker_end_seq
string += size_string
with open(linker_file, "w") as fw:
fw.write(string)
@ -196,6 +210,10 @@ def parse_args():
parser.add_argument("-l", "--library", nargs=2, action="append", default=[],
metavar=("LIBRARY", "PARTITION"),
help="Include globals for a particular library or object filename into a designated partition")
parser.add_argument("--pinoutput", required=False,
help="Output ld file for pinned sections")
parser.add_argument("--pinpartitions", action="store", required=False, default="",
help="Comma separated names of partitions to be pinned in physical memory")
args = parser.parse_args()
@ -220,11 +238,20 @@ def main():
else:
partitions[ptn][LIB].append(lib)
if args.pinoutput:
pin_part_names = args.pinpartitions.split(',')
generic_partitions = {key: value for key, value in partitions.items()
if key not in pin_part_names}
pinned_partitions = {key: value for key, value in partitions.items()
if key in pin_part_names}
else:
generic_partitions = partitions
# Sample partitions.items() list before sorting:
# [ ('part1', {'size': 64}), ('part3', {'size': 64}, ...
# ('part0', {'size': 334}) ]
decreasing_tuples = sorted(partitions.items(),
decreasing_tuples = sorted(generic_partitions.items(),
key=lambda x: (x[1][SZ], x[0]), reverse=True)
partsorted = OrderedDict(decreasing_tuples)
@ -237,6 +264,20 @@ def main():
partsorted[key][SZ],
partsorted[key][SRC]))
if args.pinoutput:
decreasing_tuples = sorted(pinned_partitions.items(),
key=lambda x: (x[1][SZ], x[0]), reverse=True)
partsorted = OrderedDict(decreasing_tuples)
generate_final_linker(args.pinoutput, partsorted, lnkr_sect="_pinned")
if args.verbose:
print("Pinned partitions retrieved:")
for key in partsorted:
print(" {0}: size {1}: {2}".format(key,
partsorted[key][SZ],
partsorted[key][SRC]))
if __name__ == '__main__':
main()

View file

@ -514,6 +514,14 @@ def find_kobjects(elf, syms):
app_smem_start = syms["_app_smem_start"]
app_smem_end = syms["_app_smem_end"]
if "CONFIG_LINKER_USE_PINNED_SECTION" in syms and "_app_smem_pinned_start" in syms:
app_smem_pinned_start = syms["_app_smem_pinned_start"]
app_smem_pinned_end = syms["_app_smem_pinned_end"]
else:
app_smem_pinned_start = app_smem_start
app_smem_pinned_end = app_smem_end
user_stack_start = syms["z_user_stacks_start"]
user_stack_end = syms["z_user_stacks_end"]
@ -630,7 +638,9 @@ def find_kobjects(elf, syms):
continue
_, user_ram_allowed, _ = kobjects[ko.type_obj.name]
if not user_ram_allowed and app_smem_start <= addr < app_smem_end:
if (not user_ram_allowed and
((app_smem_start <= addr < app_smem_end)
or (app_smem_pinned_start <= addr < app_smem_pinned_end))):
debug("object '%s' found in invalid location %s"
% (ko.type_obj.name, hex(addr)))
continue