targets/emcraft_sf2_som: Add linker script for debugging

  * Allows building ELF file for use with MSS Softconsole SDK debugger.

Change-Id: I5a44c101dece59f9e7b63c644895fcdc8c0fd783
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/91421
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Sean Keys <skeys@google.com>
diff --git a/pw_package/py/pw_package/packages/smartfusion_mss.py b/pw_package/py/pw_package/packages/smartfusion_mss.py
index b9dbe49..ff37298 100644
--- a/pw_package/py/pw_package/packages/smartfusion_mss.py
+++ b/pw_package/py/pw_package/packages/smartfusion_mss.py
@@ -26,7 +26,7 @@
         super().__init__(*args,
                          name='smartfusion_mss',
                          url='https://github.com/seank/smartfusion_mss',
-                         commit='9f47db73d3df786eab04d082645da5e735e63d28',
+                         commit='bb22f26cc3a54df15bb901dc6c95662727158fed',
                          **kwargs)
 
     def info(self, path: pathlib.Path) -> Sequence[str]:
diff --git a/targets/emcraft_sf2_som/BUILD.gn b/targets/emcraft_sf2_som/BUILD.gn
index 9d77869..b375ebe 100644
--- a/targets/emcraft_sf2_som/BUILD.gn
+++ b/targets/emcraft_sf2_som/BUILD.gn
@@ -14,6 +14,7 @@
 
 import("//build_overrides/pigweed.gni")
 
+import("$dir_pw_build/linker_script.gni")
 import("$dir_pw_build/target_types.gni")
 import("$dir_pw_docgen/docs.gni")
 import("$dir_pw_malloc/backend.gni")
@@ -28,7 +29,73 @@
   }
 }
 
+config("emcraft_ddr_init") {
+  # Emcraft's DDR config must be manually set by a custom init function. This
+  # conflicts with the built-in MSS init function. I have not looked into this
+  # myself to see if it's absoutely needed or not.
+  defines = [ "MSS_SYS_MDDR_CONFIG_BY_CORTEX=0" ]
+}
+
 if (current_toolchain != default_toolchain) {
+  pw_linker_script("mddr_debug_linker_script") {
+    defines = [
+      "PW_BOOT_CODE_BEGIN=0x00000200",  # After vector table.
+
+      # TODO(skeys) Bootloader is capable of loading 16M of uncompressed code
+      # from SPI flash to external RAM. For now use the allocated eNVM flash
+      # (256K - Bootloader - InSystemProgrammer = 192K)
+      "PW_BOOT_CODE_SIZE=0x30000",
+
+      # TODO(pwbug/219): Currently "pw_tokenizer/detokenize_test" requires at
+      # least 6K bytes in heap when using pw_malloc_freelist. The heap size
+      # required for tests should be investigated.
+      "PW_BOOT_HEAP_SIZE=4M",
+
+      # With external RAM remapped, we use the entire internal ram for the
+      # stack (64K).
+      "PW_BOOT_MIN_STACK_SIZE=64K",
+
+      # Using external DDR RAM, we just need to make sure we go past our ROM
+      # sections.
+      "PW_BOOT_RAM_BEGIN=0xA1000000",
+
+      # We assume that the bootloader loaded all 16M of text.
+      "PW_BOOT_RAM_SIZE=48M",
+      "PW_BOOT_VECTOR_TABLE_BEGIN=0x00000000",
+      "PW_BOOT_VECTOR_TABLE_SIZE=512",
+    ]
+    linker_script = "emcraft_sf2_som_mddr_debug.ld"
+  }
+  pw_linker_script("mddr_production_linker_script") {
+    defines = [
+      "PW_BOOT_FLASH_BEGIN=0x00000200",  # After vector table.
+
+      # TODO(skeys) Bootloader is capable of loading 16M of uncompressed code
+      # from SPI flash to external RAM. For now use the allocated eNVM flash
+      # (256K - Bootloader - InSystemProgrammer = 192K)
+      "PW_BOOT_FLASH_SIZE=0x30000",
+
+      # TODO(pwbug/219): Currently "pw_tokenizer/detokenize_test" requires at
+      # least 6K bytes in heap when using pw_malloc_freelist. The heap size
+      # required for tests should be investigated.
+      "PW_BOOT_HEAP_SIZE=4M",
+
+      # With external RAM remapped, we use the entire internal ram for the
+      # stack (64K).
+      "PW_BOOT_MIN_STACK_SIZE=1024K",
+
+      # Using external DDR RAM, we just need to make sure we go past our ROM
+      # sections.
+      "PW_BOOT_RAM_BEGIN=0xA1000000",
+
+      # We assume that the bootloader loaded all 16M of text.
+      "PW_BOOT_RAM_SIZE=48M",
+      "PW_BOOT_VECTOR_TABLE_BEGIN=0x00000000",
+      "PW_BOOT_VECTOR_TABLE_SIZE=512",
+    ]
+    linker_script = "$dir_pw_boot_cortex_m/basic_cortex_m.ld"
+  }
+
   pw_source_set("pre_init") {
     configs = [ ":pw_malloc_active" ]
     deps = [
@@ -49,6 +116,7 @@
 
   config("config_includes") {
     include_dirs = [ "config" ]
+    configs = [ ":emcraft_ddr_init" ]
   }
 
   pw_source_set("sf2_mss_hal_config") {
@@ -81,33 +149,8 @@
     pw_third_party_freertos_PORT = "$dir_pw_third_party/freertos:arm_cm3"
     pw_sys_io_BACKEND = dir_pw_sys_io_emcraft_sf2
 
-    # Non-debug build for use with the boot loader.
-    pw_boot_cortex_m_LINK_CONFIG_DEFINES = [
-      "PW_BOOT_FLASH_BEGIN=0x00000200",  # After vector table.
-
-      # TODO(skeys) Bootloader is capable of loading 16M of uncompressed code
-      # from SPI flash to external RAM. For now use the allocated eNVM flash
-      # (256K - Bootloader - InSystemProgrammer = 192K)
-      "PW_BOOT_FLASH_SIZE=0x30000",
-
-      # TODO(pwbug/219): Currently "pw_tokenizer/detokenize_test" requires at
-      # least 6K bytes in heap when using pw_malloc_freelist. The heap size
-      # required for tests should be investigated.
-      "PW_BOOT_HEAP_SIZE=4M",
-
-      # With external RAM remapped, we use the entire internal ram for the
-      # stack (64K).
-      "PW_BOOT_MIN_STACK_SIZE=1024K",
-
-      # Using external DDR RAM, we just need to make sure we go past our ROM
-      # sections.
-      "PW_BOOT_RAM_BEGIN=0xA1000000",
-
-      # We assume that the bootloader loaded all 16M of text.
-      "PW_BOOT_RAM_SIZE=48M",
-      "PW_BOOT_VECTOR_TABLE_BEGIN=0x00000000",
-      "PW_BOOT_VECTOR_TABLE_SIZE=512",
-    ]
+    pw_boot_cortex_m_LINKER_SCRIPT =
+        "//targets/emcraft_sf2_som:mddr_production_linker_script"
   }
 }
 
@@ -127,20 +170,11 @@
     pw_third_party_freertos_PORT = "$dir_pw_third_party/freertos:arm_cm3"
     pw_sys_io_BACKEND = dir_pw_sys_io_emcraft_sf2
 
-    pw_boot_cortex_m_LINK_CONFIG_DEFINES = [
-      "PW_BOOT_FLASH_BEGIN=0x00000200",
-      "PW_BOOT_FLASH_SIZE=200K",
-
-      # TODO(pwbug/219): Currently "pw_tokenizer/detokenize_test" requires at
-      # least 6K bytes in heap when using pw_malloc_freelist. The heap size
-      # required for tests should be investigated.
-      "PW_BOOT_HEAP_SIZE=7K",
-      "PW_BOOT_MIN_STACK_SIZE=1K",
-      "PW_BOOT_RAM_BEGIN=0x20000000",
-      "PW_BOOT_RAM_SIZE=64K",
-      "PW_BOOT_VECTOR_TABLE_BEGIN=0x00000000",
-      "PW_BOOT_VECTOR_TABLE_SIZE=512",
-    ]
+    # Override the default pw_boot_cortex_m linker script and set the memory
+    # regions for the target.
+    pw_boot_cortex_m_LINKER_SCRIPT =
+        "//targets/emcraft_sf2_som:mddr_debug_linker_script"
+    pw_third_party_smartfusion_mss_CONFIG = "debug"
   }
 }
 
diff --git a/targets/emcraft_sf2_som/boot.cc b/targets/emcraft_sf2_som/boot.cc
index bb786c8..ecb2eae 100644
--- a/targets/emcraft_sf2_som/boot.cc
+++ b/targets/emcraft_sf2_som/boot.cc
@@ -42,6 +42,8 @@
 
 }  // namespace
 
+extern "C" void Reset_Handler(void);
+
 // Functions needed when configGENERATE_RUN_TIME_STATS is on.
 extern "C" void configureTimerForRunTimeStats(void) {}
 extern "C" unsigned long getRunTimeCounterValue(void) { return 10 /* FIXME */; }
@@ -183,6 +185,13 @@
   PW_UNREACHABLE;
 }
 
+extern "C" void sf2_SocInit() {
+#if SF2_MSS_NO_BOOTLOADER
+  Reset_Handler();
+#endif
+  pw_boot_Entry();
+}
+
 // This `main()` stub prevents another main function from being linked since
 // this target deliberately doesn't run `main()`.
 extern "C" int main() {}
diff --git a/targets/emcraft_sf2_som/config/sf2_mss_hal_conf.h b/targets/emcraft_sf2_som/config/sf2_mss_hal_conf.h
index 0e82d68..4deb476 100644
--- a/targets/emcraft_sf2_som/config/sf2_mss_hal_conf.h
+++ b/targets/emcraft_sf2_som/config/sf2_mss_hal_conf.h
@@ -14,8 +14,10 @@
 
 #pragma once
 
+#include "../drivers_config/sys_config/sys_config.h"
+
 #if (MSS_SYS_MDDR_CONFIG_BY_CORTEX == 1)
-#error "Please turn off DDR initialization! See the comment in this file above."
+#error "Please turn off DDR initialization! See the comment in BUILD.gn file."
 #endif
 
 #define HAL_GPIO_MODULE_ENABLED
diff --git a/targets/emcraft_sf2_som/emcraft_sf2_som_mddr_debug.ld b/targets/emcraft_sf2_som/emcraft_sf2_som_mddr_debug.ld
new file mode 100644
index 0000000..05e8615
--- /dev/null
+++ b/targets/emcraft_sf2_som/emcraft_sf2_som_mddr_debug.ld
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2022 The Pigweed Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/* This relatively simplified linker script will work with many ARMv7-M and
+ * ARMv8-M cores that have on-board memory-mapped RAM and FLASH. For more
+ * complex projects and devices, it's possible this linker script will not be
+ * sufficient as-is.
+ *
+ * This linker script is likely not suitable for a project with a bootloader.
+ */
+
+/* Provide useful error messages when required configurations are not set. */
+#ifndef PW_BOOT_VECTOR_TABLE_BEGIN
+#error "PW_BOOT_VECTOR_TABLE_BEGIN is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_VECTOR_TABLE_BEGIN
+
+#ifndef PW_BOOT_VECTOR_TABLE_SIZE
+#error "PW_BOOT_VECTOR_TABLE_SIZE is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_VECTOR_TABLE_SIZE
+
+#ifndef PW_BOOT_CODE_BEGIN
+#error "PW_BOOT_CODE_BEGIN is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_CODE_BEGIN
+
+#ifndef PW_BOOT_CODE_SIZE
+#error "PW_BOOT_CODE_SIZE is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_CODE_SIZE
+
+#ifndef PW_BOOT_RAM_BEGIN
+#error "PW_BOOT_RAM_BEGIN is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_RAM_BEGIN
+
+#ifndef PW_BOOT_RAM_SIZE
+#error "PW_BOOT_RAM_SIZE is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_RAM_SIZE
+
+#ifndef PW_BOOT_HEAP_SIZE
+#error "PW_BOOT_HEAP_SIZE is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_HEAP_SIZE
+
+#ifndef PW_BOOT_MIN_STACK_SIZE
+#error "PW_BOOT_MIN_STACK_SIZE is not defined, and is required to use pw_boot_cortex_m"
+#endif  // PW_BOOT_MIN_STACK_SIZE
+
+
+/* Note: This technically doesn't set the firmware's entry point. Setting the
+ *       firmware entry point is done by setting vector_table[1]
+ *       (Reset_Handler). However, this DOES tell the compiler how to optimize
+ *       when --gc-sections is enabled.
+ */
+ENTRY(pw_boot_Entry)
+
+MEMORY
+{
+  /* TODO(pwbug/57): Make it possible for projects to freely customize
+   * memory regions.
+   */
+
+  /* Vector Table */
+  VECTOR_TABLE(rx) : \
+    ORIGIN = PW_BOOT_VECTOR_TABLE_BEGIN, \
+    LENGTH = PW_BOOT_VECTOR_TABLE_SIZE
+  /* External RAM being used for code. */
+  TEXT_EXTERNAL_RAM(rx) : \
+    ORIGIN = PW_BOOT_CODE_BEGIN, \
+    LENGTH = PW_BOOT_CODE_SIZE
+  /* External DDR RAM */
+  EXTERNAL_RAM(rwx) : \
+    ORIGIN = PW_BOOT_RAM_BEGIN, \
+    LENGTH = PW_BOOT_RAM_SIZE
+}
+
+SECTIONS
+{
+  /* This is the link-time vector table. If used, the VTOR (Vector Table Offset
+   * Register) MUST point to this memory location in order to be used. This can
+   * be done by ensuring this section exists at the default location of the VTOR
+   * so it's used on reset, or by explicitly setting the VTOR in a bootloader
+   * manually to point to &pw_boot_vector_table_addr before interrupts are enabled.
+   */
+  .vector_table : ALIGN(512)
+  {
+    pw_boot_vector_table_addr = .;
+    KEEP(*(.vector_table))
+  } >VECTOR_TABLE
+
+  /* Main executable code. */
+  .code : ALIGN(0x10)
+  {
+   CREATE_OBJECT_SYMBOLS
+    __text_load = LOADADDR(.code);
+    /* Application code. */
+    *(.text)
+    *(.text*)
+    KEEP(*(.init))
+    KEEP(*(.fini))
+
+    . = ALIGN(0x10);
+    /* Constants.*/
+    *(.rodata)
+    *(.rodata*)
+
+    /* .preinit_array, .init_array, .fini_array are used by libc.
+     * Each section is a list of function pointers that are called pre-main and
+     * post-exit for object initialization and tear-down.
+     * Since the region isn't explicitly referenced, specify KEEP to prevent
+     * link-time garbage collection. SORT is used for sections that have strict
+     * init/de-init ordering requirements. */
+    . = ALIGN(0x10);
+    PROVIDE_HIDDEN(__preinit_array_start = .);
+    KEEP(*(.preinit_array*))
+    PROVIDE_HIDDEN(__preinit_array_end = .);
+
+    PROVIDE_HIDDEN(__init_array_start = .);
+    KEEP(*(SORT(.init_array.*)))
+    KEEP(*(.init_array*))
+    PROVIDE_HIDDEN(__init_array_end = .);
+
+    PROVIDE_HIDDEN(__fini_array_start = .);
+    KEEP(*(SORT(.fini_array.*)))
+    KEEP(*(.fini_array*))
+    PROVIDE_HIDDEN(__fini_array_end = .);
+  } >TEXT_EXTERNAL_RAM
+
+  /* Used by unwind-arm/ */
+  .ARM : ALIGN(0x10) {
+    __exidx_start = .;
+    *(.ARM.exidx*)
+    __exidx_end = .;
+  } >TEXT_EXTERNAL_RAM
+  
+  /* Explicitly initialized global and static data. (.data)*/
+  .static_init_ram : ALIGN(0x10)
+  {
+    *(.data)
+    *(.data*)
+    . = ALIGN(0x10);
+  } >EXTERNAL_RAM AT> TEXT_EXTERNAL_RAM
+
+  /* Zero initialized global/static data. (.bss)
+   * This section is zero initialized in pw_boot_Entry(). */
+  .zero_init_ram : ALIGN(0x10)
+  {
+    *(.bss)
+    *(.bss*)
+    *(COMMON)
+    . = ALIGN(0x10);
+  } >EXTERNAL_RAM
+
+  .heap : ALIGN(8)
+  {
+    pw_boot_heap_low_addr = .;
+    . = . + PW_BOOT_HEAP_SIZE;
+    . = ALIGN(8);
+    pw_boot_heap_high_addr = .;
+  } >EXTERNAL_RAM
+
+  /* Link-time check for stack overlaps. */
+  .stack (NOLOAD) : ALIGN(8)
+  {
+    /* Set the address that the main stack pointer should be initialized to. */
+    pw_boot_stack_low_addr = .;
+    HIDDEN(_stack_size = ORIGIN(EXTERNAL_RAM) + LENGTH(EXTERNAL_RAM) - .);
+    /* Align the stack to a lower address to ensure it isn't out of range. */
+    HIDDEN(_stack_high = (. + _stack_size) & ~0x7);
+    ASSERT(_stack_high - . >= PW_BOOT_MIN_STACK_SIZE,
+           "Error: Not enough RAM for desired minimum stack size.");
+    . = _stack_high;
+    pw_boot_stack_high_addr = .;
+  } >EXTERNAL_RAM
+
+  /* Discard unwind info. */
+  .ARM.extab 0x0 (INFO) :
+  {
+    KEEP(*(.ARM.extab*))
+  }
+
+  /*
+   * Do not declare any output sections after this comment. This area is
+   * reserved only for declaring unused sections of memory. These sections are
+   * used by pw_bloat.bloaty_config to create the utilization data source for
+   * bloaty.
+   */
+  .VECTOR_TABLE.unused_space (NOLOAD) : ALIGN(8)
+  {
+    . = ABSOLUTE(ORIGIN(VECTOR_TABLE) + LENGTH(VECTOR_TABLE));
+  } >VECTOR_TABLE
+
+  .TEXT_EXTERNAL_RAM.unused_space (NOLOAD) : ALIGN(8)
+  {
+    . = ABSOLUTE(ORIGIN(TEXT_EXTERNAL_RAM) + LENGTH(TEXT_EXTERNAL_RAM));
+  } >TEXT_EXTERNAL_RAM
+
+  .EXTERNAL_RAM.unused_space (NOLOAD) : ALIGN(8)
+  {
+    . = ABSOLUTE(ORIGIN(EXTERNAL_RAM) + LENGTH(EXTERNAL_RAM));
+  } >EXTERNAL_RAM
+}
+
+/* Symbols used by core_init.c: */
+/* Start of .static_init_ram in TEXT_EXTERNAL_RAM. */
+_pw_static_init_flash_start = LOADADDR(.static_init_ram);
+
+/* Region of .static_init_ram in RAM. */
+_pw_static_init_ram_start = ADDR(.static_init_ram);
+_pw_static_init_ram_end = _pw_static_init_ram_start + SIZEOF(.static_init_ram);
+
+/* Region of .zero_init_ram. */
+_pw_zero_init_ram_start = ADDR(.zero_init_ram);
+_pw_zero_init_ram_end = _pw_zero_init_ram_start + SIZEOF(.zero_init_ram);
+
+/* arm-none-eabi expects `end` symbol to point to start of heap for sbrk. */
+PROVIDE(end = _pw_zero_init_ram_end);
+
+/* These symbols are used by pw_bloat.bloaty_config to create the memoryregions
+ * data source for bloaty in this format (where the optional _N defaults to 0):
+ * pw_bloat_config_memory_region_NAME_{start,end}{_N,} */
+pw_bloat_config_memory_region_VECTOR_TABLE_start = ORIGIN(VECTOR_TABLE);
+pw_bloat_config_memory_region_VECTOR_TABLE_end =
+    ORIGIN(VECTOR_TABLE) + LENGTH(VECTOR_TABLE);
+pw_bloat_config_memory_region_FLASH_start = ORIGIN(TEXT_EXTERNAL_RAM);
+pw_bloat_config_memory_region_FLASH_end = ORIGIN(TEXT_EXTERNAL_RAM) + LENGTH(TEXT_EXTERNAL_RAM);
+pw_bloat_config_memory_region_RAM_start = ORIGIN(EXTERNAL_RAM);
+pw_bloat_config_memory_region_RAM_end = ORIGIN(EXTERNAL_RAM) + LENGTH(EXTERNAL_RAM);
+
+/* Symbol mapping used by MSS Startup and Debugger. */
+PROVIDE (__smartfusion2_memory_remap = 2);  /* Remap according to LMA (this script) */
+PROVIDE (__mirrored_nvm = 1);   /* GDB will load to LMA directly no need to load again. */
+PROVIDE (_estack = pw_boot_stack_high_addr);
+PROVIDE (__stack_start__ = pw_boot_stack_low_addr);
+PROVIDE (__vector_table_load = LOADADDR(.vector_table));
+PROVIDE (__vector_table_start = pw_boot_vector_table_addr);
+PROVIDE (__vector_table_vma_base_address = __vector_table_start);  /* required by debugger for start address */
+PROVIDE (__text_end =  __exidx_end);
+PROVIDE (__heap_start__ = pw_boot_heap_low_addr);
+PROVIDE (_eheap = pw_boot_heap_high_addr);
+PROVIDE (_etext =  __exidx_end);
+PROVIDE (_evector_table = pw_boot_vector_table_addr);
+PROVIDE (__data_start = _pw_static_init_ram_start);
+PROVIDE (_edata = _pw_static_init_ram_end);
+PROVIDE (__text_start = __text_load);
+PROVIDE (__bss_start__ = _pw_zero_init_ram_start);
+PROVIDE (__bss_end__ = _pw_static_init_ram_end);
+PROVIDE (__data_load = _pw_static_init_flash_start);
diff --git a/targets/emcraft_sf2_som/vector_table.c b/targets/emcraft_sf2_som/vector_table.c
index a4f5f7f..5205404 100644
--- a/targets/emcraft_sf2_som/vector_table.c
+++ b/targets/emcraft_sf2_som/vector_table.c
@@ -44,6 +44,7 @@
 void SVC_Handler(void);
 void PendSV_Handler(void);
 void SysTick_Handler(void);
+void sf2_SocInit(void);
 
 PW_KEEP_IN_SECTION(".vector_table")
 const InterruptHandler vector_table[] = {
@@ -55,7 +56,7 @@
 
     // Reset handler, dictates how to handle reset interrupt. This is the
     // address that the Program Counter (PC) is initialized to at boot.
-    [1] = pw_boot_Entry,
+    [1] = sf2_SocInit,
 
     // NMI handler.
     [2] = DefaultFaultHandler,
diff --git a/third_party/smartfusion_mss/README.md b/third_party/smartfusion_mss/README.md
index 7532545..90cfc61 100644
--- a/third_party/smartfusion_mss/README.md
+++ b/third_party/smartfusion_mss/README.md
@@ -2,5 +2,5 @@
 
 The folder provides build scripts and configuration recipes for building
 the SmartFusion2 Microcontroller Subsystem library. The source code needs to be downloaded by the user, or
-via the support in pw_package "pw package install sf2mss". For gn build,
+via the support in pw_package "pw package install smartfusion_mss". For gn build,
 set `dir_pw_third_party_smartfusion_mss` to point to the path of the source code.