blob: 209cac48092bf5ec7b53e2d8580a115d3632d634 [file] [log] [blame]
Armando Montanez70095662020-01-09 14:25:04 -08001// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15// !!!WARNING!!!
16//
17// Some of the code in this file is run without static initialization expected
18// by C/C++. Any accesses to statically initialized objects/variables before
19// memory is initialized will result in undefined values and violates the C
20// specification. Only code run after memory initialization is complete will be
21// compliant and truly safe to run. In general, make early initialization code
22// run AFTER memory initialization has completed unless it is ABSOLUTELY
23// NECESSARY to modify the way memory is initialized.
24//
25// This file is similar to a traditional assembly startup file. It turns out
26// that everything typically done in ARMv7-M assembly startup can be done
27// straight from C code. This makes startup code easier to maintain, modify,
28// and read.
29//
30// When execution begins due to SoC power-on (or the device is reset), three
31// key things must happen to properly enter C++ execution context:
32// 1. Static variables must be loaded from flash to RAM.
33// 2. Zero-initialized variables must be zero-initialized.
34// 3. Statically allocated objects must have their constructors run.
35// The SoC doesn't inherently have a notion of how to do this, so this is
36// handled in StaticInit();
37//
38// Following this, execution is handed over to pw_PreMainInit() to facilitate
39// platform, project, or application pre-main initialization. When
40// pw_PreMainInit() returns, main() is executed.
41//
42// The simple flow is as follows:
43// 1. Power on
44// 2. PC and SP set (from vector_table by SoC, or by bootloader)
45// 3. pw_BootEntry()
46// 3.1. Static-init RAM (.data, .bss, C++ constructors)
47// 3.2. pw_PreMainInit()
48// 3.3. main()
49
50#include <stdbool.h>
51#include <stdint.h>
52#include <string.h>
53
54#include "pw_boot_armv7m/boot.h"
55#include "pw_preprocessor/compiler.h"
56
57// Extern symbols provided by linker script.
58// These symbols tell us where various memory sections start and end.
59extern uint8_t _pw_static_init_ram_start;
60extern uint8_t _pw_static_init_ram_end;
61extern uint8_t _pw_static_init_flash_start;
62extern uint8_t _pw_zero_init_ram_start;
63extern uint8_t _pw_zero_init_ram_end;
64
65// Functions called as part of firmware initialization.
66void __libc_init_array(void);
67
68// WARNING: Be EXTREMELY careful when running code before this function
69// completes. The context before this function violates the C spec
70// (Section 6.7.8, paragraph 10 for example, which requires uninitialized static
71// values to be zero-initialized).
72void StaticInit(void) {
73 // Static-init RAM (load static values into ram, .data section init).
74 memcpy(&_pw_static_init_ram_start,
75 &_pw_static_init_flash_start,
76 &_pw_static_init_ram_end - &_pw_static_init_ram_start);
77
78 // Zero-init RAM (.bss section init).
79 memset(&_pw_zero_init_ram_start,
80 0,
81 &_pw_zero_init_ram_end - &_pw_zero_init_ram_start);
82
83 // Call static constructors.
84 __libc_init_array();
85}
86
87// WARNING: This code is run immediately upon boot, and performs initialization
88// of RAM. Note that code running before this function finishes memory
89// initialization will violate the C spec (Section 6.7.8, paragraph 10 for
90// example, which requires uninitialized static values to be zero-initialized).
91// Be EXTREMELY careful when running code before this function finishes RAM
92// initialization.
93//
94// This function runs immediately at boot because it is at index 1 of the
95// interrupt vector table.
96void pw_BootEntry() {
97 StaticInit();
98
99 // This function is not provided by pw_boot_armv7m, a platform layer, project,
100 // or application is expected to implement it.
101 pw_PreMainInit();
102
103 // Run main.
104 main();
105
106 // In case main() returns, just sit here until the device is reset.
107 while (true) {
108 }
109}