From acda9bf9cec8cc366e5a319f7f35cc234a6e34d3 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Sat, 6 Mar 2021 17:44:44 -0800 Subject: [PATCH] linker-tool-gcc: revise for MMU support We need to do a few things differently if we are to support a virtual memory map, i.e. CONFIG_MMU where CONFIG_KERNEL_VM_BASE is not the same as CONFIG_SRAM_BASE_ADDRESS. - All sections must be specified with a VMA and LMA, where VMA is the virtual address and LMA is the physical memory location. - All sections must be specified with ALIGN_WITH_INPUT to keep VMAs and LMAs synchronized To do this, the existing linker macros need some adjustment: - GROUP_LINK_IN undefined when CONFIG_KERNEL_VM_BASE is not the same as CONFIG_SRAM_BASE_ADDRESS. - New macro GROUP_ROM_LINK_IN for text/rodata sections - New macro GROUP_NOLOAD_LINK_IN for bss/noinit sections - Implicit ALIGN_WITH_INPUT for all sections GROUP_FOLLOWS_AT is unused anywhere in the kernel for years now and has been removed. Signed-off-by: Andrew Boie Signed-off-by: Daniel Leung --- include/arch/x86/ia32/linker.ld | 8 +- include/arch/x86/intel64/linker.ld | 20 +-- include/linker/common-noinit.ld | 2 +- include/linker/common-rom.ld | 20 +-- include/linker/cplusplus-ram.ld | 4 +- include/linker/cplusplus-rom.ld | 2 +- include/linker/intlist.ld | 6 +- include/linker/linker-defs.h | 2 +- include/linker/linker-tool-gcc.h | 141 ++++++++++++++++------ include/linker/thread-local-storage.ld | 4 +- include/sys/mem_manage.h | 7 ++ subsys/testsuite/coverage/coverage_ram.ld | 6 +- 12 files changed, 151 insertions(+), 71 deletions(-) diff --git a/include/arch/x86/ia32/linker.ld b/include/arch/x86/ia32/linker.ld index 75be8137fb..c4c525f4e4 100644 --- a/include/arch/x86/ia32/linker.ld +++ b/include/arch/x86/ia32/linker.ld @@ -43,7 +43,7 @@ #include -#ifdef CONFIG_XIP +#if defined(CONFIG_XIP) || defined(Z_VM_KERNEL) #define ROMABLE_REGION ROM #define RAMABLE_REGION RAM #else @@ -122,7 +122,7 @@ SECTIONS #include MMU_PAGE_ALIGN_PERM - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) _image_text_end = .; _image_text_size = _image_text_end - _image_text_start; @@ -161,7 +161,7 @@ SECTIONS #include #include - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #include @@ -234,7 +234,7 @@ SECTIONS */ . = ALIGN(4); __bss_end = .; - } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + } GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) __bss_num_words = (__bss_end - __bss_start) >> 2; diff --git a/include/arch/x86/intel64/linker.ld b/include/arch/x86/intel64/linker.ld index ef091a4de6..7eb9987544 100644 --- a/include/arch/x86/intel64/linker.ld +++ b/include/arch/x86/intel64/linker.ld @@ -31,7 +31,7 @@ SECTIONS * ... there is no 16-bit code yet, but there will be when we add SMP. */ - .locore : ALIGN(16) + SECTION_PROLOGUE(.locore,,) { _locore_start = .; *(.locore) @@ -85,8 +85,9 @@ SECTIONS * placed above 1MB to avoid the by memory hole at 0x90000-0xFFFFF). */ - SECTION_PROLOGUE(_TEXT_SECTION_NAME,,ALIGN(16)) + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) { + . = ALIGN(16); _image_rom_start = .; _image_text_start = .; z_mapped_start = .; @@ -96,7 +97,7 @@ SECTIONS #include MMU_PAGE_ALIGN_PERM - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) _image_text_end = .; _image_text_size = _image_text_end - _image_text_start; @@ -105,8 +106,9 @@ SECTIONS #include #include - SECTION_PROLOGUE(_RODATA_SECTION_NAME,,ALIGN(16)) + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) { + . = ALIGN(16); *(.rodata) *(.rodata.*) @@ -121,7 +123,7 @@ SECTIONS #endif /* CONFIG_X86_MMU */ #include - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #include @@ -148,8 +150,9 @@ SECTIONS * be put in BSS section. That causes gcov not work properly */ #include - SECTION_PROLOGUE(_BSS_SECTION_NAME, (NOLOAD), ALIGN(16)) + SECTION_PROLOGUE(_BSS_SECTION_NAME, (NOLOAD),) { + . = ALIGN(16); MMU_PAGE_ALIGN_PERM #ifndef CONFIG_USERSPACE _image_ram_start = .; @@ -161,7 +164,7 @@ SECTIONS *(COMMON) . = ALIGN(4); /* so __bss_num_dwords is exact */ __bss_end = .; - } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + } GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) __bss_num_dwords = (__bss_end - __bss_start) >> 2; @@ -169,8 +172,9 @@ SECTIONS #include - SECTION_PROLOGUE(_DATA_SECTION_NAME,,ALIGN(16)) + SECTION_PROLOGUE(_DATA_SECTION_NAME,,) { + . = ALIGN(16); *(.data) *(.data.*) #include diff --git a/include/linker/common-noinit.ld b/include/linker/common-noinit.ld index a2fe9cd9d5..bf940c8ae6 100644 --- a/include/linker/common-noinit.ld +++ b/include/linker/common-noinit.ld @@ -23,4 +23,4 @@ SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),) */ #include -} GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) +} GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) diff --git a/include/linker/common-rom.ld b/include/linker/common-rom.ld index e2e7804515..9ee0b85818 100644 --- a/include/linker/common-rom.ld +++ b/include/linker/common-rom.ld @@ -15,7 +15,7 @@ CREATE_OBJ_LEVEL(init, APPLICATION) CREATE_OBJ_LEVEL(init, SMP) __init_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #if defined(CONFIG_GEN_SW_ISR_TABLE) && !defined(CONFIG_DYNAMIC_INTERRUPTS) SECTION_PROLOGUE(sw_isr_table,,) @@ -27,7 +27,7 @@ */ . = ALIGN(CONFIG_ARCH_SW_ISR_TABLE_ALIGN); *(_SW_ISR_TABLE_SECTION_SYMS) - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif /* verify we don't have rogue .init_ initlevel sections */ @@ -62,7 +62,7 @@ LONG(0) __CTOR_END__ = .; #endif - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) SECTION_PROLOGUE(init_array,,) { @@ -70,7 +70,7 @@ __init_array_start = .; KEEP(*(SORT_BY_NAME(".init_array*"))) __init_array_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif #ifdef CONFIG_USERSPACE /* Build-time assignment of permissions to kernel objects to @@ -84,7 +84,7 @@ __app_shmem_regions_start = .; KEEP(*(SORT(.app_regions.*))); __app_shmem_regions_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #if defined(CONFIG_NET_SOCKETS) Z_ITERABLE_SECTION_ROM(net_socket_register, 4) @@ -154,14 +154,14 @@ __log_const_start = .; KEEP(*(SORT(.log_const_*))); __log_const_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) SECTION_DATA_PROLOGUE(log_backends_sections,,) { __log_backends_start = .; KEEP(*("._log_backend.*")); __log_backends_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) Z_ITERABLE_SECTION_ROM(shell, 4) @@ -170,14 +170,14 @@ __shell_root_cmds_start = .; KEEP(*(SORT(.shell_root_cmd_*))); __shell_root_cmds_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) SECTION_DATA_PROLOGUE(font_entry_sections,,) { __font_entry_start = .; KEEP(*(SORT_BY_NAME("._cfb_font.*"))) __font_entry_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) Z_ITERABLE_SECTION_ROM(tracing_backend, 4) @@ -190,4 +190,4 @@ KEEP(*(SORT(.__device_handles_pass1*))); #endif /* LINKER_PASS2 */ __device_handles_end = .; - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) diff --git a/include/linker/cplusplus-ram.ld b/include/linker/cplusplus-ram.ld index 64474e79db..fd696df593 100644 --- a/include/linker/cplusplus-ram.ld +++ b/include/linker/cplusplus-ram.ld @@ -5,8 +5,8 @@ */ #if defined (CONFIG_CPLUSPLUS) - SECTION_PROLOGUE(.gcc_except_table,,ONLY_IF_RW) + SECTION_DATA_PROLOGUE(.gcc_except_table,,ONLY_IF_RW) { *(.gcc_except_table .gcc_except_table.*) - } GROUP_LINK_IN(RAMABLE_REGION) + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif diff --git a/include/linker/cplusplus-rom.ld b/include/linker/cplusplus-rom.ld index bb41e50d17..d4b730a591 100644 --- a/include/linker/cplusplus-rom.ld +++ b/include/linker/cplusplus-rom.ld @@ -8,5 +8,5 @@ SECTION_PROLOGUE(.gcc_except_table,,ONLY_IF_RO) { *(.gcc_except_table .gcc_except_table.*) - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif diff --git a/include/linker/intlist.ld b/include/linker/intlist.ld index 1eced6b623..dd000513cc 100644 --- a/include/linker/intlist.ld +++ b/include/linker/intlist.ld @@ -34,9 +34,9 @@ #ifndef LINKER_PASS2 SECTION_PROLOGUE(.intList,,) { - KEEP(*(.irq_info*)) - KEEP(*(.intList*)) -} GROUP_LINK_IN(IDT_LIST) + KEEP(*(.irq_info)) + KEEP(*(.intList)) +} GROUP_ROM_LINK_IN(IDT_LIST, IDT_LIST) #else /DISCARD/ : { diff --git a/include/linker/linker-defs.h b/include/linker/linker-defs.h index 03b8da543e..48abc28a8d 100644 --- a/include/linker/linker-defs.h +++ b/include/linker/linker-defs.h @@ -61,7 +61,7 @@ SECTION_PROLOGUE(struct_type##_area,,SUBALIGN(subalign)) \ { \ Z_LINK_ITERABLE(struct_type); \ - } GROUP_LINK_IN(ROMABLE_REGION) + } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) /* Define an output section which will set up an iterable area * of equally-sized data structures. For use with Z_STRUCT_SECTION_ITERABLE. diff --git a/include/linker/linker-tool-gcc.h b/include/linker/linker-tool-gcc.h index 63e901ccdf..67d9c9da3b 100644 --- a/include/linker/linker-tool-gcc.h +++ b/include/linker/linker-tool-gcc.h @@ -15,6 +15,8 @@ #ifndef ZEPHYR_INCLUDE_LINKER_LINKER_TOOL_GCC_H_ #define ZEPHYR_INCLUDE_LINKER_LINKER_TOOL_GCC_H_ +#include + #if defined(CONFIG_ARM) #if defined(CONFIG_ARM64) #define OUTPUT_FORMAT_ "elf64-littleaarch64" @@ -63,72 +65,139 @@ #define GROUP_START(where) #define GROUP_END(where) -/* +/** + * @def GROUP_LINK_IN + * + * Route memory to a specified memory area + * * The GROUP_LINK_IN() macro is located at the end of the section * description and tells the linker that this section is located in - * the memory area specified by argument. + * the memory area specified by 'where' argument. + * + * This macro is intentionally undefined for CONFIG_MMU systems when + * CONFIG_KERNEL_VM_BASE is not the same as CONFIG_SRAM_BASE_ADDRESS, + * as both the LMA and VMA destinations must be known for all sections + * as this corresponds to physical vs. virtual location. + * + * @param where Destination memory area */ #if defined(CONFIG_ARCH_POSIX) #define GROUP_LINK_IN(where) -#else +#elif !defined(Z_VM_KERNEL) #define GROUP_LINK_IN(where) > where #endif -/* - * As GROUP_LINK_IN(), but takes a second argument indicating the - * memory region (e.g. "ROM") for the load address. Used for - * initialized data sections that on XIP platforms must be copied at +/** + * @def GROUP_ROM_LINK_IN + * + * Route memory for a read-only section + * + * The GROUP_ROM_LINK_IN() macro is located at the end of the section + * description and tells the linker that this a read-only section + * that is physically placed at the 'lregion` argument. + * + * If CONFIG_XIP is active, the 'lregion' area is flash memory. + * + * If CONFIG_MMU is active, the vregion argument will be used to + * determine where this is located in the virtual memory map, otherwise + * it is ignored. + * + * @param vregion Output VMA (only used if CONFIG_MMU where LMA != VMA) + * @param lregion Output LMA + */ +#if defined(CONFIG_ARCH_POSIX) +#define GROUP_ROM_LINK_IN(vregion, lregion) +#elif defined(Z_VM_KERNEL) +#define GROUP_ROM_LINK_IN(vregion, lregion) > vregion AT > lregion +#else +#define GROUP_ROM_LINK_IN(vregion, lregion) > lregion +#endif + +/** + * @def GROUP_DATA_LINK_IN + * + * Route memory for read-write sections that are loaded. + * + * Used for initialized data sections that on XIP platforms must be copied at * startup. * - * And, because output directives in GNU ld are "sticky", this must - * also be used on the first section *after* such an initialized data - * section, specifying the same memory region (e.g. "RAM") for both - * vregion and lregion. + * @param vregion Output VMA + * @param lregion Output LMA (only used if CONFIG_MMU if VMA != LMA, + * or CONFIG_XIP) */ #if defined(CONFIG_ARCH_POSIX) #define GROUP_DATA_LINK_IN(vregion, lregion) -#else -#ifdef CONFIG_XIP -#define GROUP_DATA_LINK_IN(vregion, lregion) > vregion AT> lregion +#elif defined(CONFIG_XIP) || defined(Z_VM_KERNEL) +#define GROUP_DATA_LINK_IN(vregion, lregion) > vregion AT > lregion #else #define GROUP_DATA_LINK_IN(vregion, lregion) > vregion #endif -#endif /*CONFIG_ARCH_POSIX*/ -/* - * The GROUP_FOLLOWS_AT() macro is located at the end of the section - * and indicates that the section does not specify an address at which - * it is to be loaded, but that it follows a section which did specify - * such an address +/** + * @def GROUP_NOLOAD_LINK_IN + * + * Route memory for read-write sections that are NOT loaded; typically this + * is only used for 'BSS' and 'noinit'. + * + * @param vregion Output VMA + * @param lregion Output LMA (only used if CONFIG_MMU if VMA != LMA, + * corresponds to physical location) */ -#ifdef CONFIG_ARCH_POSIX -#define GROUP_FOLLOWS_AT(where) +#if defined(CONFIG_ARCH_POSIX) +#define GROUP_NOLOAD_LINK_IN(vregion, lregion) +#elif defined(Z_VM_KERNEL) +#define GROUP_NOLOAD_LINK_IN(vregion, lregion) > vregion AT > lregion +#elif defined(CONFIG_XIP) +#define GROUP_NOLOAD_LINK_IN(vregion, lregion) > vregion AT > vregion #else -#define GROUP_FOLLOWS_AT(where) AT > where +#define GROUP_NOLOAD_LINK_IN(vregion, lregion) > vregion #endif -/* +/** + * @def SECTION_PROLOGUE + * * The SECTION_PROLOGUE() macro is used to define the beginning of a section. - * The parameter is the name of the section, and the