Skip to content

Commit 9e32c57

Browse files
committed
linker: map vector table to RAM for AST1060 boot flow
AST1060 does not support XIP; instead, its ROM code copies the entire firmware image from flash to RAM and begins execution there. To support this flow, the vector table must reside in RAM starting at address 0x00000000, rather than being mapped to flash as assumed by the default cortex-m-rt layout. This change updates the linker script to correctly position the vector table for AST1060's ROM-based boot process. Signed-off-by: Steven Lee <steven_lee@aspeedtech.com>
1 parent 2f67ae5 commit 9e32c57

File tree

3 files changed

+238
-8
lines changed

3 files changed

+238
-8
lines changed

link.x

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/* # Developer notes
2+
3+
- Symbols that start with a double underscore (__) are considered "private"
4+
5+
- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
6+
overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
7+
static mut __sbss }`).
8+
9+
- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
10+
symbol if not dropped if it appears in or near the front of the linker arguments and "it's not
11+
needed" by any of the preceding objects (linker arguments)
12+
13+
- `PROVIDE` is used to provide default values that can be overridden by a user linker script
14+
15+
- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
16+
the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization
17+
routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see
18+
"Address (..) is out of bounds" in the disassembly produced by `objdump`.
19+
*/
20+
21+
/* Provides information about the memory layout of the device */
22+
/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */
23+
INCLUDE memory.x
24+
25+
/* # Entry point = reset vector */
26+
ENTRY(Reset);
27+
EXTERN(__RESET_VECTOR); /* depends on the `Reset` symbol */
28+
29+
/* # Exception vectors */
30+
/* This is effectively weak aliasing at the linker level */
31+
/* The user can override any of these aliases by defining the corresponding symbol themselves (cf.
32+
the `exception!` macro) */
33+
EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */
34+
35+
EXTERN(DefaultHandler);
36+
37+
PROVIDE(NonMaskableInt = DefaultHandler);
38+
EXTERN(HardFaultTrampoline);
39+
PROVIDE(MemoryManagement = DefaultHandler);
40+
PROVIDE(BusFault = DefaultHandler);
41+
PROVIDE(UsageFault = DefaultHandler);
42+
PROVIDE(SecureFault = DefaultHandler);
43+
PROVIDE(SVCall = DefaultHandler);
44+
PROVIDE(DebugMonitor = DefaultHandler);
45+
PROVIDE(PendSV = DefaultHandler);
46+
PROVIDE(SysTick = DefaultHandler);
47+
48+
PROVIDE(DefaultHandler = DefaultHandler_);
49+
PROVIDE(HardFault = HardFault_);
50+
51+
/* # Interrupt vectors */
52+
EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */
53+
54+
/* # Pre-initialization function */
55+
/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function,
56+
then the function this points to will be called before the RAM is initialized. */
57+
PROVIDE(__pre_init = DefaultPreInit);
58+
59+
/* # Sections */
60+
SECTIONS
61+
{
62+
PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM));
63+
64+
/* ## Sections in RAM */
65+
/* ### Vector table */
66+
.vector_table ORIGIN(RAM) :
67+
{
68+
/* Initial Stack Pointer (SP) value */
69+
LONG(_stack_start);
70+
71+
/* Reset vector */
72+
KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */
73+
__reset_vector = .;
74+
75+
/* Exceptions */
76+
KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */
77+
__eexceptions = .;
78+
79+
/* Device specific interrupts */
80+
KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */
81+
} > RAM
82+
83+
PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table));
84+
85+
/* ### .text */
86+
.text _stext :
87+
{
88+
/* place these 2 close to each other or the `b` instruction will fail to link */
89+
*(.PreResetTrampoline);
90+
*(.Reset);
91+
92+
*(.text .text.*);
93+
*(.HardFaultTrampoline);
94+
*(.HardFault.*);
95+
. = ALIGN(4);
96+
__etext = .;
97+
} > RAM
98+
99+
/* ### .rodata */
100+
.rodata __etext : ALIGN(4)
101+
{
102+
*(.rodata .rodata.*);
103+
104+
/* 4-byte align the end (VMA) of this section.
105+
This is required by LLD to ensure the LMA of the following .data
106+
section will have the correct alignment. */
107+
. = ALIGN(4);
108+
__erodata = .;
109+
} > RAM
110+
111+
/* ## Sections in RAM */
112+
/* ### .data */
113+
.data : ALIGN(4)
114+
{
115+
. = ALIGN(4);
116+
__sdata = .;
117+
*(.data .data.*);
118+
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
119+
__edata = .;
120+
} > RAM
121+
122+
/* LMA of .data */
123+
__sidata = LOADADDR(.data);
124+
125+
/* ### .bss */
126+
.bss (NOLOAD) : ALIGN(4)
127+
{
128+
. = ALIGN(4);
129+
__sbss = .;
130+
*(.bss .bss.*);
131+
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
132+
__ebss = .;
133+
} > RAM
134+
135+
/* ### .uninit */
136+
.uninit (NOLOAD) : ALIGN(4)
137+
{
138+
. = ALIGN(4);
139+
*(.uninit .uninit.*);
140+
. = ALIGN(4);
141+
} > RAM
142+
143+
/* Place the heap right after `.uninit` */
144+
. = ALIGN(4);
145+
__sheap = .;
146+
147+
/* ## .got */
148+
/* Dynamic relocations are unsupported. This section is only used to detect relocatable code in
149+
the input files and raise an error if relocatable code is found */
150+
.got (NOLOAD) :
151+
{
152+
KEEP(*(.got .got.*));
153+
}
154+
155+
/* ## Discarded sections */
156+
/DISCARD/ :
157+
{
158+
/* Unused exception related info that only wastes space */
159+
*(.ARM.exidx);
160+
*(.ARM.exidx.*);
161+
*(.ARM.extab.*);
162+
}
163+
}
164+
165+
/* Do not exceed this mark in the error messages below | */
166+
/* # Alignment checks */
167+
ASSERT(ORIGIN(RAM) % 4 == 0, "
168+
ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
169+
170+
ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
171+
BUG(cortex-m-rt): .data is not 4-byte aligned");
172+
173+
ASSERT(__sidata % 4 == 0, "
174+
BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned");
175+
176+
ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, "
177+
BUG(cortex-m-rt): .bss is not 4-byte aligned");
178+
179+
ASSERT(__sheap % 4 == 0, "
180+
BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
181+
182+
/* # Position checks */
183+
184+
/* ## .vector_table */
185+
ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, "
186+
BUG(cortex-m-rt): the reset vector is missing");
187+
188+
ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, "
189+
BUG(cortex-m-rt): the exception vectors are missing");
190+
191+
ASSERT(SIZEOF(.vector_table) > 0x40, "
192+
ERROR(cortex-m-rt): The interrupt vectors are missing.
193+
Possible solutions, from most likely to less likely:
194+
- Link to a svd2rust generated device crate
195+
- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency
196+
may be enabling it)
197+
- Supply the interrupt handlers yourself. Check the documentation for details.");
198+
199+
/* ## .text */
200+
ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, "
201+
ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section
202+
Set _stext to an address greater than the end of .vector_table (See output of `nm`)");
203+
204+
ASSERT(_stext + SIZEOF(.text) < ORIGIN(RAM) + LENGTH(RAM), "
205+
ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory.
206+
Set _stext to an address smaller than 'ORIGIN(RAM) + LENGTH(RAM)'");
207+
208+
/* # Other checks */
209+
ASSERT(SIZEOF(.got) == 0, "
210+
ERROR(cortex-m-rt): .got section detected in the input object files
211+
Dynamic relocations are not supported. If you are linking to C code compiled using
212+
the 'cc' crate then modify your build script to compile the C code _without_
213+
the -fPIC flag. See the documentation of the `cc::Build.pic` method for details.");
214+
/* Do not exceed this mark in the error messages above | */
215+
216+
/* Provides weak aliases (cf. PROVIDED) for device specific interrupt handlers */
217+
/* This will usually be provided by a device crate generated using svd2rust (see `device.x`) */
218+
INCLUDE device.x
219+
220+
ASSERT(SIZEOF(.vector_table) <= 0x400, "
221+
There can't be more than 240 interrupt handlers. This may be a bug in
222+
your device crate, or you may have registered more than 240 interrupt
223+
handlers.");
224+

memory.x

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
MEMORY
22
{
3-
/* NOTE 1 K = 1 KiBi = 1024 bytes */
4-
/* TODO Adjust these memory regions to match your device memory layout */
5-
/* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */
6-
FLASH : ORIGIN = 0x00000000, LENGTH = 128K
7-
RAM : ORIGIN = 0x20000, LENGTH = 128K
8-
RAM_NC : ORIGIN = 0xA0000, LENGTH = 128K
3+
FLASH : ORIGIN = 0x80000000, LENGTH = 1024K
4+
RAM : ORIGIN = 0x00000000, LENGTH = 640K
5+
RAM_NC : ORIGIN = 0x000A0000, LENGTH = 128K
96
}
107

118
/* This is where the call stack will be allocated. */
@@ -19,7 +16,7 @@ MEMORY
1916
section */
2017
/* This is required only on microcontrollers that store some configuration right
2118
after the vector table */
22-
_stext = ORIGIN(FLASH) + 0x420;
19+
_stext = ORIGIN(RAM) + 0x420;
2320

2421
/* Example of putting non-initialized variables into custom RAM locations. */
2522
/* This assumes you have defined a region RAM2 above, and in the Rust

src/main.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,20 @@ unsafe fn pre_init() {
3737
reg |= 0x1f << 25;
3838
write_volatile(jtag_pinmux_offset as *mut u32, reg);
3939

40+
// Disable Cache
4041
let cache_ctrl_offset: u32 = 0x7e6e2a58;
4142
write_volatile(cache_ctrl_offset as *mut u32, 0);
43+
44+
// Configure Cache Area and Invalidation
4245
let cache_area_offset: u32 = 0x7e6e2a50;
43-
let cache_val = 0x0003_ffff;
46+
let cache_val = 0x000f_ffff;
4447
write_volatile(cache_area_offset as *mut u32, cache_val);
48+
49+
let cache_inval_offset: u32 = 0x7e6e2a54;
50+
let cache_inval_val = 0x8660_0000;
51+
write_volatile(cache_inval_offset as *mut u32, cache_inval_val);
52+
53+
// Enable Cache
4554
write_volatile(cache_ctrl_offset as *mut u32, 1);
4655
}
4756

0 commit comments

Comments
 (0)