ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
vector_table.c
Go to the documentation of this file.
1
26
27#include <stdint.h>
28
29#include "ra8_boot_entry.h"
30
31/* =============================================================================
32 * Linker-provided symbols
33 * =============================================================================
34 *
35 * Project convention: linker symbols carry the `g_ra8_ls_` prefix so they
36 * are not in the reserved leading-underscore namespace that ISO C (and
37 * cert-dcl37-c / bugprone-reserved-identifier) reject. The linker script
38 * in blink/linker_script.ld defines them with this exact spelling.
39 */
40
41extern uint32_t g_ra8_ls_stack_top;
42extern uint32_t g_ra8_ls_sdata;
43extern uint32_t g_ra8_ls_edata;
44extern uint32_t g_ra8_ls_sidata;
45extern uint32_t g_ra8_ls_sbss;
46extern uint32_t g_ra8_ls_ebss;
47
48/* =============================================================================
49 * Handler declarations
50 * =============================================================================
51 */
52
53typedef void (*exc_handler_t)(void);
54
55void Reset_Handler(void);
56void HardFault_Handler(void);
57void MemManage_Handler(void);
58void BusFault_Handler(void);
59void UsageFault_Handler(void);
60
61/* Core exceptions (Cortex-M85). HardFault / MemManage / BusFault /
62 * UsageFault each get a dedicated naked trampoline below which
63 * forwards to ra8_exception_report(). The rest are weak-aliased to
64 * Default_Handler and may be overridden by application code.
65 *
66 * Mach-O (macOS host) does not support `__attribute__((alias(...)))`.
67 * On the host syntax-check / unit-test build we drop the alias and
68 * keep only `weak`; the host build never branches through these
69 * symbols (the firmware vector table is not exercised on the test
70 * host), so we just need them to exist for the `&` references in
71 * `g_ra8_vector_table_start` to be well-formed. */
72#ifndef __APPLE__
73[[gnu::weak, gnu::alias("Default_Handler")]] void NMI_Handler(void);
74[[gnu::weak, gnu::alias("Default_Handler")]] void SecureFault_Handler(void);
75[[gnu::weak, gnu::alias("Default_Handler")]] void SVC_Handler(void);
76[[gnu::weak, gnu::alias("Default_Handler")]] void DebugMon_Handler(void);
77[[gnu::weak, gnu::alias("Default_Handler")]] void PendSV_Handler(void);
78#else
79[[gnu::weak]] void NMI_Handler(void);
80[[gnu::weak]] void SecureFault_Handler(void);
81[[gnu::weak]] void SVC_Handler(void);
82[[gnu::weak]] void DebugMon_Handler(void);
83[[gnu::weak]] void PendSV_Handler(void);
84#endif
85
86/* SysTick provided by libs/ra8_core/src/ra8_time.c (weak) so RTOS apps may override. */
87extern void SysTick_Handler(void);
88
89/* =============================================================================
90 * Peripheral IRQ handlers
91 * =============================================================================
92 *
93 * The RA Interrupt Control Unit exposes 112 routable interrupt lines
94 * to the NVIC (per HUM table 13.x). We declare them all weak-aliased
95 * to Default_Handler so a driver can override any single one.
96 */
97
98enum : uint16_t {
100};
101
102/* Mach-O does not support `alias`; on Apple hosts we keep only
103 * `weak` so the symbols exist but are not aliased. The host build
104 * never invokes these vectors. */
105#ifndef __APPLE__
107#define RA8_IRQ_STUB(n) [[gnu::weak, gnu::alias("Default_Handler")]] void IRQ##n##_Handler(void)
108#else
110#define RA8_IRQ_STUB(n) [[gnu::weak]] void IRQ##n##_Handler(void)
111#endif
112
113RA8_IRQ_STUB(0);
114RA8_IRQ_STUB(1);
115RA8_IRQ_STUB(2);
116RA8_IRQ_STUB(3);
117RA8_IRQ_STUB(4);
118RA8_IRQ_STUB(5);
119RA8_IRQ_STUB(6);
120RA8_IRQ_STUB(7);
121RA8_IRQ_STUB(8);
122RA8_IRQ_STUB(9);
123RA8_IRQ_STUB(10);
124RA8_IRQ_STUB(11);
125RA8_IRQ_STUB(12);
126RA8_IRQ_STUB(13);
127RA8_IRQ_STUB(14);
128RA8_IRQ_STUB(15);
129RA8_IRQ_STUB(16);
130RA8_IRQ_STUB(17);
131RA8_IRQ_STUB(18);
132RA8_IRQ_STUB(19);
133RA8_IRQ_STUB(20);
134RA8_IRQ_STUB(21);
135RA8_IRQ_STUB(22);
136RA8_IRQ_STUB(23);
137RA8_IRQ_STUB(24);
138RA8_IRQ_STUB(25);
139RA8_IRQ_STUB(26);
140RA8_IRQ_STUB(27);
141RA8_IRQ_STUB(28);
142RA8_IRQ_STUB(29);
143RA8_IRQ_STUB(30);
144RA8_IRQ_STUB(31);
145RA8_IRQ_STUB(32);
146RA8_IRQ_STUB(33);
147RA8_IRQ_STUB(34);
148RA8_IRQ_STUB(35);
149RA8_IRQ_STUB(36);
150RA8_IRQ_STUB(37);
151RA8_IRQ_STUB(38);
152RA8_IRQ_STUB(39);
153RA8_IRQ_STUB(40);
154RA8_IRQ_STUB(41);
155RA8_IRQ_STUB(42);
156RA8_IRQ_STUB(43);
157RA8_IRQ_STUB(44);
158RA8_IRQ_STUB(45);
159RA8_IRQ_STUB(46);
160RA8_IRQ_STUB(47);
161RA8_IRQ_STUB(48);
162RA8_IRQ_STUB(49);
163RA8_IRQ_STUB(50);
164RA8_IRQ_STUB(51);
165RA8_IRQ_STUB(52);
166RA8_IRQ_STUB(53);
167RA8_IRQ_STUB(54);
168RA8_IRQ_STUB(55);
169RA8_IRQ_STUB(56);
170RA8_IRQ_STUB(57);
171RA8_IRQ_STUB(58);
172RA8_IRQ_STUB(59);
173RA8_IRQ_STUB(60);
174RA8_IRQ_STUB(61);
175RA8_IRQ_STUB(62);
176RA8_IRQ_STUB(63);
177RA8_IRQ_STUB(64);
178RA8_IRQ_STUB(65);
179RA8_IRQ_STUB(66);
180RA8_IRQ_STUB(67);
181RA8_IRQ_STUB(68);
182RA8_IRQ_STUB(69);
183RA8_IRQ_STUB(70);
184RA8_IRQ_STUB(71);
185RA8_IRQ_STUB(72);
186RA8_IRQ_STUB(73);
187RA8_IRQ_STUB(74);
188RA8_IRQ_STUB(75);
189RA8_IRQ_STUB(76);
190RA8_IRQ_STUB(77);
191RA8_IRQ_STUB(78);
192RA8_IRQ_STUB(79);
193RA8_IRQ_STUB(80);
194RA8_IRQ_STUB(81);
195RA8_IRQ_STUB(82);
196RA8_IRQ_STUB(83);
197RA8_IRQ_STUB(84);
198RA8_IRQ_STUB(85);
199RA8_IRQ_STUB(86);
200RA8_IRQ_STUB(87);
201RA8_IRQ_STUB(88);
202RA8_IRQ_STUB(89);
203RA8_IRQ_STUB(90);
204RA8_IRQ_STUB(91);
205RA8_IRQ_STUB(92);
206RA8_IRQ_STUB(93);
207RA8_IRQ_STUB(94);
208RA8_IRQ_STUB(95);
209RA8_IRQ_STUB(96);
210RA8_IRQ_STUB(97);
211RA8_IRQ_STUB(98);
212RA8_IRQ_STUB(99);
213RA8_IRQ_STUB(100);
214RA8_IRQ_STUB(101);
215RA8_IRQ_STUB(102);
216RA8_IRQ_STUB(103);
217RA8_IRQ_STUB(104);
218RA8_IRQ_STUB(105);
219RA8_IRQ_STUB(106);
220RA8_IRQ_STUB(107);
221RA8_IRQ_STUB(108);
222RA8_IRQ_STUB(109);
223RA8_IRQ_STUB(110);
224RA8_IRQ_STUB(111);
225
226#undef RA8_IRQ_STUB
227
228/* =============================================================================
229 * Vector table
230 * =============================================================================
231 *
232 * Placed in its own section so the linker script can pin it to the
233 * start of MRAM. The Cortex-M85 reads the initial MSP from offset 0
234 * and the reset vector from offset 4.
235 */
236
237/* Mach-O `section()` requires a `"segment,section"` form, but on the
238 * host syntax-check / unit-test build we only need this array to
239 * exist as a normal global -- the host never reads it from a fixed
240 * vector address. So drop the section pinning on Apple hosts. */
241#ifndef __APPLE__
242[[gnu::section(".vectors"), gnu::used]]
243#else
244[[gnu::used]]
245#endif
247 /* Core exceptions (slots 0..15). */
248 (exc_handler_t)&g_ra8_ls_stack_top, /* 0 Initial main stack pointer. */
249 Reset_Handler, /* 1 Reset vector. */
250 NMI_Handler, /* 2 NMI. */
251 HardFault_Handler, /* 3 HardFault. */
252 MemManage_Handler, /* 4 MemManage. */
253 BusFault_Handler, /* 5 BusFault. */
254 UsageFault_Handler, /* 6 UsageFault. */
255 SecureFault_Handler, /* 7 SecureFault. */
256 0, /* 8 Reserved. */
257 0, /* 9 Reserved. */
258 0, /* 10 Reserved. */
259 SVC_Handler, /* 11 SVC. */
260 DebugMon_Handler, /* 12 DebugMon. */
261 0, /* 13 Reserved. */
262 PendSV_Handler, /* 14 PendSV. */
263 SysTick_Handler, /* 15 SysTick. */
264
265/* Peripheral IRQs 0..111. */
267#define E(n) IRQ##n##_Handler
268 E(0),
269 E(1),
270 E(2),
271 E(3),
272 E(4),
273 E(5),
274 E(6),
275 E(7),
276 E(8),
277 E(9),
278 E(10),
279 E(11),
280 E(12),
281 E(13),
282 E(14),
283 E(15),
284 E(16),
285 E(17),
286 E(18),
287 E(19),
288 E(20),
289 E(21),
290 E(22),
291 E(23),
292 E(24),
293 E(25),
294 E(26),
295 E(27),
296 E(28),
297 E(29),
298 E(30),
299 E(31),
300 E(32),
301 E(33),
302 E(34),
303 E(35),
304 E(36),
305 E(37),
306 E(38),
307 E(39),
308 E(40),
309 E(41),
310 E(42),
311 E(43),
312 E(44),
313 E(45),
314 E(46),
315 E(47),
316 E(48),
317 E(49),
318 E(50),
319 E(51),
320 E(52),
321 E(53),
322 E(54),
323 E(55),
324 E(56),
325 E(57),
326 E(58),
327 E(59),
328 E(60),
329 E(61),
330 E(62),
331 E(63),
332 E(64),
333 E(65),
334 E(66),
335 E(67),
336 E(68),
337 E(69),
338 E(70),
339 E(71),
340 E(72),
341 E(73),
342 E(74),
343 E(75),
344 E(76),
345 E(77),
346 E(78),
347 E(79),
348 E(80),
349 E(81),
350 E(82),
351 E(83),
352 E(84),
353 E(85),
354 E(86),
355 E(87),
356 E(88),
357 E(89),
358 E(90),
359 E(91),
360 E(92),
361 E(93),
362 E(94),
363 E(95),
364 E(96),
365 E(97),
366 E(98),
367 E(99),
368 E(100),
369 E(101),
370 E(102),
371 E(103),
372 E(104),
373 E(105),
374 E(106),
375 E(107),
376 E(108),
377 E(109),
378 E(110),
379 E(111),
380#undef E
381};
382
383/* =============================================================================
384 * Reset handler: copy .data from MRAM to SRAM, zero .bss, call main()
385 * =============================================================================
386 */
387
389{
390 /* Step 1: core-level init (VTOR, FPU, caches, priority grouping,
391 * interrupts masked). Runs before we touch .data or .bss so it
392 * must not read or write any global variables. */
393 SystemInit();
394
395 /* Step 2: copy initialized data from flash/MRAM to SRAM. */
396 // NOLINTBEGIN(clang-analyzer-security.ArrayBound) -- Linker symbols define ranges, not one-element arrays.
397 const uint32_t* src = &g_ra8_ls_sidata;
398 uint32_t* dst = &g_ra8_ls_sdata;
399 while (dst < &g_ra8_ls_edata) {
400 *dst++ = *src++;
401 }
402
403 /* Step 3: zero BSS. */
404 dst = &g_ra8_ls_sbss;
405 while (dst < &g_ra8_ls_ebss) {
406 *dst++ = 0U;
407 }
408
409 // NOLINTEND(clang-analyzer-security.ArrayBound)
410
411 /* Step 4: enter C. `main()` is responsible for enabling interrupts
412 * via `__enable_irq()` once all drivers are ready. */
413 main();
414
415 /* main() should never return; if it does, halt. */
416 while (1) {
417 __asm__ volatile("wfi");
418 }
419}
420
421/* =============================================================================
422 * HardFault / MemManage / BusFault / UsageFault naked trampolines
423 * =============================================================================
424 *
425 * Each trampoline picks the stack pointer the fault was taken on
426 * (MSP if `EXC_RETURN[2]=0`, PSP otherwise), packs an `exception
427 * number` in `r1`, and tail-calls `ra8_exception_report()`. See
428 * `ra8_exception.h` for the frame layout and HUM reference.
429 */
430
431extern void ra8_exception_report(const void* frame, uint32_t exc_number);
432
443
444#ifndef RA8_OFF_TARGET
445[[gnu::naked, noreturn]] void HardFault_Handler(void)
446{
447 __asm__ volatile("tst lr, #4 \n"
448 "ite eq \n"
449 "mrseq r0, msp \n"
450 "mrsne r0, psp \n"
451 "mov r1, #3 \n"
452 "b ra8_exception_report\n");
453}
454
455[[gnu::naked, noreturn]] void MemManage_Handler(void)
456{
457 __asm__ volatile("tst lr, #4 \n"
458 "ite eq \n"
459 "mrseq r0, msp \n"
460 "mrsne r0, psp \n"
461 "mov r1, #4 \n"
462 "b ra8_exception_report\n");
463}
464
465[[gnu::naked, noreturn]] void BusFault_Handler(void)
466{
467 __asm__ volatile("tst lr, #4 \n"
468 "ite eq \n"
469 "mrseq r0, msp \n"
470 "mrsne r0, psp \n"
471 "mov r1, #5 \n"
472 "b ra8_exception_report\n");
473}
474
475[[gnu::naked, noreturn]] void UsageFault_Handler(void)
476{
477 __asm__ volatile("tst lr, #4 \n"
478 "ite eq \n"
479 "mrseq r0, msp \n"
480 "mrsne r0, psp \n"
481 "mov r1, #6 \n"
482 "b ra8_exception_report\n");
483}
484#else
485/* Host build: fault handlers trap directly to the reporter. The host
486 * compiler does not know `ra8_exception_report` is noreturn through
487 * the extern declaration, so we add `__builtin_unreachable()` after
488 * each call to keep the `noreturn` attribute on the handler valid. */
489[[noreturn]] void HardFault_Handler(void)
490{
492 __builtin_unreachable();
493}
494[[noreturn]] void MemManage_Handler(void)
495{
497 __builtin_unreachable();
498}
499[[noreturn]] void BusFault_Handler(void)
500{
502 __builtin_unreachable();
503}
504[[noreturn]] void UsageFault_Handler(void)
505{
507 __builtin_unreachable();
508}
509#endif
510
511/* =============================================================================
512 * Default trap
513 * =============================================================================
514 */
515
517{
518 /* Stop here so an attached debugger can inspect stack / faults. */
519#ifndef RA8_OFF_TARGET
520 __asm__ volatile("bkpt #0");
521 while (1) {
522 __asm__ volatile("wfi");
523 }
524#endif
525}
void UsageFault_Handler(void)
Capture a UsageFault and transfer to the common exception reporter.
void HardFault_Handler(void)
Capture a HardFault and transfer to the common exception reporter.
void MemManage_Handler(void)
Capture a MemManage fault and transfer to the exception reporter.
void SVC_Handler(void)
void Default_Handler(void)
Catch-all handler for every exception slot nothing else claims.
void PendSV_Handler(void)
void NMI_Handler(void)
Cortex-M85 NMI handler (vector table slot 2).
void BusFault_Handler(void)
Capture a BusFault and transfer to the common exception reporter.
#define E(n)
void SysTick_Handler(void)
Service the SysTick exception selected by the linked application.
Definition ra8_time.c:244
void SecureFault_Handler(void)
Cortex-M85 SecureFault handler (vector table slot 7).
void DebugMon_Handler(void)
void Reset_Handler(void)
Enter the Secure e-reader image after processor reset.
#define RA8_IRQ_STUB(n)
RA8 IRQ STUB.
void SecureFault_Handler(void)
Cortex-M85 SecureFault handler (vector table slot 7).
uint32_t g_ra8_ls_stack_top
void SystemInit(void)
Earliest C code the image runs: bring the core up before RAM init.
const uint32_t g_ra8_vector_table_start[]
void UsageFault_Handler(void)
Capture a UsageFault and transfer to the common exception reporter.
void HardFault_Handler(void)
Capture a HardFault and transfer to the common exception reporter.
void MemManage_Handler(void)
Capture a MemManage fault and transfer to the exception reporter.
void SVC_Handler(void)
uint32_t g_ra8_ls_sidata
Source of .data in MRAM.
ra8_vector_exc_t
Exception numbers matching the Cortex-M vector table slots.
@ k_ra8_vector_hardfault
RA8 vector hardfault.
@ k_ra8_vector_usagefault
RA8 vector usagefault.
@ k_ra8_vector_busfault
RA8 vector busfault.
@ k_ra8_vector_memmanage
RA8 vector memmanage.
uint32_t g_ra8_ls_edata
End of .data in SRAM.
void PendSV_Handler(void)
uint32_t g_ra8_ls_sdata
Start of .data in SRAM.
uint32_t g_ra8_ls_sbss
Start of .bss in SRAM.
void BusFault_Handler(void)
Capture a BusFault and transfer to the common exception reporter.
void SysTick_Handler(void)
Service the SysTick exception selected by the linked application.
Definition ra8_time.c:244
void(* exc_handler_t)(void)
@ k_ra8_irq_count
RA8 IRQ count.
void DebugMon_Handler(void)
void Reset_Handler(void)
Enter an EK-RA8D2 firmware image after processor reset.
uint32_t g_ra8_ls_ebss
End of .bss in SRAM.
void NMI_Handler(void)
Cortex-M85 NMI handler (vector table slot 2).
Boot entry points shared between a vector table and its startup code.
void main(void)
The application entry point Reset_Handler hands control to.
Definition main.c:298
void ra8_exception_report(const ra8_exception_frame_t *frame, uint32_t exc_number)
Emit a full fault dump over the log backend.