Skip to content

Commit

Permalink
kernel: app_smem: allowing pinning memory partitions
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dcpleung authored and cfriedt committed Aug 27, 2021
1 parent e88afd2 commit 2117a2a
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 27 deletions.
34 changes: 32 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Expand All @@ -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>
Expand All @@ -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
)

Expand Down Expand Up @@ -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>
Expand Down
14 changes: 14 additions & 0 deletions cmake/linker/ld/target_configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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()
42 changes: 42 additions & 0 deletions include/linker/app_smem_pinned.ld
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions include/linker/app_smem_pinned_aligned.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/

/* Empty file */
7 changes: 7 additions & 0 deletions include/linker/app_smem_pinned_unaligned.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright (c) 2021 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/

/* Empty file */
7 changes: 7 additions & 0 deletions include/linker/linker-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
2 changes: 2 additions & 0 deletions include/linker/sections.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
32 changes: 31 additions & 1 deletion kernel/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -859,14 +860,43 @@ 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;
}

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
*/
Expand Down
87 changes: 64 additions & 23 deletions scripts/gen_app_partitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,24 @@
"""

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 = """
Expand Down Expand Up @@ -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)

string += linker_end_seq
string += size_string
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())

with open(linker_file, "w") as fw:
fw.write(string)

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

Expand All @@ -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)
Expand All @@ -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()
12 changes: 11 additions & 1 deletion scripts/gen_kobject_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 2117a2a

Please sign in to comment.