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
36
37#include <stdint.h>
38
39#include "ra8_boot_entry.h"
40#include "ra8_exception.h"
41#include "ra8_lpm_safe_boot.h"
42
43/* =============================================================================
44 * Linker-provided symbols
45 * =============================================================================
46 *
47 * Project convention: linker symbols carry the `g_ra8_ls_` prefix so they
48 * are not in the reserved leading-underscore namespace that ISO C (and
49 * cert-dcl37-c / bugprone-reserved-identifier) reject. The linker script
50 * (the app-local linker_script.ld or the shared
51 * libs/ra8_board_ra8p1/ld/linker_script.ld) defines them with this
52 * exact spelling.
53 */
54
55extern uint32_t g_ra8_ls_stack_top;
56extern uint32_t g_ra8_ls_sdata;
57extern uint32_t g_ra8_ls_edata;
58extern uint32_t g_ra8_ls_sidata;
59extern uint32_t g_ra8_ls_sbss;
60extern uint32_t g_ra8_ls_ebss;
61
62/* =============================================================================
63 * Handler declarations
64 * =============================================================================
65 */
66
67typedef void (*exc_handler_t)(void);
68
69void Reset_Handler(void);
70
71void HardFault_Handler(void);
72
73void MemManage_Handler(void);
74
75void BusFault_Handler(void);
76
77void UsageFault_Handler(void);
78
79/* Core exceptions (Cortex-M85). HardFault / MemManage / BusFault /
80 * UsageFault each get a dedicated naked trampoline below which
81 * forwards to ra8_exception_report(). The rest are weak-aliased to
82 * Default_Handler and may be overridden by application code.
83 *
84 * Mach-O (macOS host) does not support `__attribute__((alias(...)))`.
85 * On the host syntax-check / unit-test build we drop the alias and
86 * keep only `weak`; the host build never branches through these
87 * symbols (the firmware vector table is not exercised on the test
88 * host), so we just need them to exist for the `&` references in
89 * `g_ra8_vector_table_start` to be well-formed. */
90#ifndef __APPLE__
91[[gnu::weak, gnu::alias("Default_Handler")]] void NMI_Handler(void);
92[[gnu::weak, gnu::alias("Default_Handler")]] void SecureFault_Handler(void);
93[[gnu::weak, gnu::alias("Default_Handler")]] void SVC_Handler(void);
94[[gnu::weak, gnu::alias("Default_Handler")]] void DebugMon_Handler(void);
95[[gnu::weak, gnu::alias("Default_Handler")]] void PendSV_Handler(void);
96#else
97[[gnu::weak]] void NMI_Handler(void);
98[[gnu::weak]] void SecureFault_Handler(void);
99[[gnu::weak]] void SVC_Handler(void);
100[[gnu::weak]] void DebugMon_Handler(void);
101[[gnu::weak]] void PendSV_Handler(void);
102#endif
103
116extern void SysTick_Handler(void);
117
118/* =============================================================================
119 * Peripheral IRQ handlers
120 * =============================================================================
121 *
122 * The RA Interrupt Control Unit exposes 112 routable interrupt lines
123 * to the NVIC (per HUM table 13.x). We declare them all weak-aliased
124 * to Default_Handler so a driver can override any single one.
125 */
126
127enum : uint16_t {
129};
130
131/* Mach-O does not support `alias`; on Apple hosts we keep only
132 * `weak` so the symbols exist but are not aliased. The host build
133 * never invokes these vectors. */
134#ifndef __APPLE__
136#define RA8_IRQ_STUB(n) [[gnu::weak, gnu::alias("Default_Handler")]] void IRQ##n##_Handler(void)
137#else
139#define RA8_IRQ_STUB(n) [[gnu::weak]] void IRQ##n##_Handler(void)
140#endif
141
142RA8_IRQ_STUB(0);
143RA8_IRQ_STUB(1);
144RA8_IRQ_STUB(2);
145RA8_IRQ_STUB(3);
146RA8_IRQ_STUB(4);
147RA8_IRQ_STUB(5);
148RA8_IRQ_STUB(6);
149RA8_IRQ_STUB(7);
150RA8_IRQ_STUB(8);
151RA8_IRQ_STUB(9);
152RA8_IRQ_STUB(10);
153RA8_IRQ_STUB(11);
154RA8_IRQ_STUB(12);
155RA8_IRQ_STUB(13);
156RA8_IRQ_STUB(14);
157RA8_IRQ_STUB(15);
158RA8_IRQ_STUB(16);
159RA8_IRQ_STUB(17);
160RA8_IRQ_STUB(18);
161RA8_IRQ_STUB(19);
162RA8_IRQ_STUB(20);
163RA8_IRQ_STUB(21);
164RA8_IRQ_STUB(22);
165RA8_IRQ_STUB(23);
166RA8_IRQ_STUB(24);
167RA8_IRQ_STUB(25);
168RA8_IRQ_STUB(26);
169RA8_IRQ_STUB(27);
170RA8_IRQ_STUB(28);
171RA8_IRQ_STUB(29);
172RA8_IRQ_STUB(30);
173RA8_IRQ_STUB(31);
174RA8_IRQ_STUB(32);
175RA8_IRQ_STUB(33);
176RA8_IRQ_STUB(34);
177RA8_IRQ_STUB(35);
178RA8_IRQ_STUB(36);
179RA8_IRQ_STUB(37);
180RA8_IRQ_STUB(38);
181RA8_IRQ_STUB(39);
182RA8_IRQ_STUB(40);
183RA8_IRQ_STUB(41);
184RA8_IRQ_STUB(42);
185RA8_IRQ_STUB(43);
186RA8_IRQ_STUB(44);
187RA8_IRQ_STUB(45);
188RA8_IRQ_STUB(46);
189RA8_IRQ_STUB(47);
190RA8_IRQ_STUB(48);
191RA8_IRQ_STUB(49);
192RA8_IRQ_STUB(50);
193RA8_IRQ_STUB(51);
194RA8_IRQ_STUB(52);
195RA8_IRQ_STUB(53);
196RA8_IRQ_STUB(54);
197RA8_IRQ_STUB(55);
198RA8_IRQ_STUB(56);
199RA8_IRQ_STUB(57);
200RA8_IRQ_STUB(58);
201RA8_IRQ_STUB(59);
202RA8_IRQ_STUB(60);
203RA8_IRQ_STUB(61);
204RA8_IRQ_STUB(62);
205RA8_IRQ_STUB(63);
206RA8_IRQ_STUB(64);
207RA8_IRQ_STUB(65);
208RA8_IRQ_STUB(66);
209RA8_IRQ_STUB(67);
210RA8_IRQ_STUB(68);
211RA8_IRQ_STUB(69);
212RA8_IRQ_STUB(70);
213RA8_IRQ_STUB(71);
214RA8_IRQ_STUB(72);
215RA8_IRQ_STUB(73);
216RA8_IRQ_STUB(74);
217RA8_IRQ_STUB(75);
218RA8_IRQ_STUB(76);
219RA8_IRQ_STUB(77);
220RA8_IRQ_STUB(78);
221RA8_IRQ_STUB(79);
222RA8_IRQ_STUB(80);
223RA8_IRQ_STUB(81);
224RA8_IRQ_STUB(82);
225RA8_IRQ_STUB(83);
226RA8_IRQ_STUB(84);
227RA8_IRQ_STUB(85);
228RA8_IRQ_STUB(86);
229RA8_IRQ_STUB(87);
230RA8_IRQ_STUB(88);
231RA8_IRQ_STUB(89);
232RA8_IRQ_STUB(90);
233RA8_IRQ_STUB(91);
234RA8_IRQ_STUB(92);
235RA8_IRQ_STUB(93);
236RA8_IRQ_STUB(94);
237RA8_IRQ_STUB(95);
238RA8_IRQ_STUB(96);
239RA8_IRQ_STUB(97);
240RA8_IRQ_STUB(98);
241RA8_IRQ_STUB(99);
242RA8_IRQ_STUB(100);
243RA8_IRQ_STUB(101);
244RA8_IRQ_STUB(102);
245RA8_IRQ_STUB(103);
246RA8_IRQ_STUB(104);
247RA8_IRQ_STUB(105);
248RA8_IRQ_STUB(106);
249RA8_IRQ_STUB(107);
250RA8_IRQ_STUB(108);
251RA8_IRQ_STUB(109);
252RA8_IRQ_STUB(110);
253RA8_IRQ_STUB(111);
254
255#undef RA8_IRQ_STUB
256
257/* =============================================================================
258 * Vector table
259 * =============================================================================
260 *
261 * Placed in its own section so the linker script can pin it to the
262 * start of MRAM. The Cortex-M85 reads the initial MSP from offset 0
263 * and the reset vector from offset 4.
264 */
265
266/* Mach-O `section()` requires a `"segment,section"` form, but on the
267 * host syntax-check / unit-test build we only need this array to
268 * exist as a normal global -- the host never reads it from a fixed
269 * vector address. So drop the section pinning on Apple hosts. */
270#ifndef __APPLE__
271[[gnu::section(".vectors"), gnu::used]]
272#else
273[[gnu::used]]
274#endif
276 /* Core exceptions (slots 0..15). */
277 (exc_handler_t)&g_ra8_ls_stack_top, /* 0 Initial main stack pointer. */
278 Reset_Handler, /* 1 Reset vector. */
279 NMI_Handler, /* 2 NMI. */
280 HardFault_Handler, /* 3 HardFault. */
281 MemManage_Handler, /* 4 MemManage. */
282 BusFault_Handler, /* 5 BusFault. */
283 UsageFault_Handler, /* 6 UsageFault. */
284 SecureFault_Handler, /* 7 SecureFault. */
285 0, /* 8 Reserved. */
286 0, /* 9 Reserved. */
287 0, /* 10 Reserved. */
288 SVC_Handler, /* 11 SVC. */
289 DebugMon_Handler, /* 12 DebugMon. */
290 0, /* 13 Reserved. */
291 PendSV_Handler, /* 14 PendSV. */
292 SysTick_Handler, /* 15 SysTick. */
293
294/* Peripheral IRQs 0..111. */
296#define E(n) IRQ##n##_Handler
297 E(0),
298 E(1),
299 E(2),
300 E(3),
301 E(4),
302 E(5),
303 E(6),
304 E(7),
305 E(8),
306 E(9),
307 E(10),
308 E(11),
309 E(12),
310 E(13),
311 E(14),
312 E(15),
313 E(16),
314 E(17),
315 E(18),
316 E(19),
317 E(20),
318 E(21),
319 E(22),
320 E(23),
321 E(24),
322 E(25),
323 E(26),
324 E(27),
325 E(28),
326 E(29),
327 E(30),
328 E(31),
329 E(32),
330 E(33),
331 E(34),
332 E(35),
333 E(36),
334 E(37),
335 E(38),
336 E(39),
337 E(40),
338 E(41),
339 E(42),
340 E(43),
341 E(44),
342 E(45),
343 E(46),
344 E(47),
345 E(48),
346 E(49),
347 E(50),
348 E(51),
349 E(52),
350 E(53),
351 E(54),
352 E(55),
353 E(56),
354 E(57),
355 E(58),
356 E(59),
357 E(60),
358 E(61),
359 E(62),
360 E(63),
361 E(64),
362 E(65),
363 E(66),
364 E(67),
365 E(68),
366 E(69),
367 E(70),
368 E(71),
369 E(72),
370 E(73),
371 E(74),
372 E(75),
373 E(76),
374 E(77),
375 E(78),
376 E(79),
377 E(80),
378 E(81),
379 E(82),
380 E(83),
381 E(84),
382 E(85),
383 E(86),
384 E(87),
385 E(88),
386 E(89),
387 E(90),
388 E(91),
389 E(92),
390 E(93),
391 E(94),
392 E(95),
393 E(96),
394 E(97),
395 E(98),
396 E(99),
397 E(100),
398 E(101),
399 E(102),
400 E(103),
401 E(104),
402 E(105),
403 E(106),
404 E(107),
405 E(108),
406 E(109),
407 E(110),
408 E(111),
409#undef E
410};
411
412/* =============================================================================
413 * Reset handler: copy .data from MRAM to SRAM, zero .bss, call main()
414 * =============================================================================
415 */
416
430{
431 /* Must be first: clear LPSCR / SBYCR / DPSBYCR before any code
432 * can execute WFI. Survives a previous app leaving LPSCR set to
433 * software-standby across SYSRESETREQ (the SYSC LPM block is in
434 * a separate reset domain). See libs/ra8_hal/inc/ra8_lpm_safe_boot.h. */
436
437 /* Step 1: core-level init (VTOR, FPU, caches, priority grouping,
438 * interrupts masked). Runs before we touch .data or .bss so it
439 * must not read or write any global variables. */
440 SystemInit();
441
442 /* Step 2: copy initialized data from flash/MRAM to SRAM. */
443 const uint32_t* src = &g_ra8_ls_sidata;
444 uint32_t* dst = &g_ra8_ls_sdata;
445 while (dst < &g_ra8_ls_edata) {
446 *dst++ = *src++;
447 }
448
449 /* Step 3: zero BSS. */
450 dst = &g_ra8_ls_sbss;
451 while (dst < &g_ra8_ls_ebss) {
452 *dst++ = 0U;
453 }
454
455 /* Step 4: enter C. `main()` is responsible for enabling interrupts
456 * via `__enable_irq()` once all drivers are ready. */
457 main();
458
459 /* main() should never return; if it does, halt. */
460 while (1) {
461 __asm__ volatile("wfi");
462 }
463}
464
465/* =============================================================================
466 * HardFault / MemManage / BusFault / UsageFault naked trampolines
467 * =============================================================================
468 *
469 * Each trampoline picks the stack pointer the fault was taken on
470 * (MSP if `EXC_RETURN[2]=0`, PSP otherwise), packs an `exception
471 * number` in `r1`, and tail-calls `ra8_exception_report()`. See
472 * `ra8_exception.h` for the frame layout and HUM reference.
473 */
474
485
486#ifndef RA8_OFF_TARGET
499[[gnu::naked, noreturn]] void HardFault_Handler(void)
500{
501 __asm__ volatile("tst lr, #4 \n"
502 "ite eq \n"
503 "mrseq r0, msp \n"
504 "mrsne r0, psp \n"
505 "mov r1, #3 \n"
506 "b ra8_exception_report\n");
507}
508
521[[gnu::naked, noreturn]] void MemManage_Handler(void)
522{
523 __asm__ volatile("tst lr, #4 \n"
524 "ite eq \n"
525 "mrseq r0, msp \n"
526 "mrsne r0, psp \n"
527 "mov r1, #4 \n"
528 "b ra8_exception_report\n");
529}
530
543[[gnu::naked, noreturn]] void BusFault_Handler(void)
544{
545 __asm__ volatile("tst lr, #4 \n"
546 "ite eq \n"
547 "mrseq r0, msp \n"
548 "mrsne r0, psp \n"
549 "mov r1, #5 \n"
550 "b ra8_exception_report\n");
551}
552
565[[gnu::naked, noreturn]] void UsageFault_Handler(void)
566{
567 __asm__ volatile("tst lr, #4 \n"
568 "ite eq \n"
569 "mrseq r0, msp \n"
570 "mrsne r0, psp \n"
571 "mov r1, #6 \n"
572 "b ra8_exception_report\n");
573}
574#else
575/* Host build: fault handlers trap directly to the reporter. The host
576 * compiler does not know `ra8_exception_report` is noreturn through
577 * the extern declaration, so we add `__builtin_unreachable()` after
578 * each call to keep the `noreturn` attribute on the handler valid. */
579[[noreturn]] void HardFault_Handler(void)
580{
582 __builtin_unreachable();
583}
584[[noreturn]] void MemManage_Handler(void)
585{
587 __builtin_unreachable();
588}
589[[noreturn]] void BusFault_Handler(void)
590{
592 __builtin_unreachable();
593}
594[[noreturn]] void UsageFault_Handler(void)
595{
597 __builtin_unreachable();
598}
599#endif
600
601/* =============================================================================
602 * Default trap
603 * =============================================================================
604 */
605
607{
608 /* Stop here so an attached debugger can inspect stack / faults. */
609#ifndef RA8_OFF_TARGET
610 __asm__ volatile("bkpt #0");
611 while (1) {
612 __asm__ volatile("wfi");
613 }
614#endif
615}
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
Cortex-M85 CPU exception diagnostic helpers.
void ra8_exception_report(const ra8_exception_frame_t *frame, uint32_t exc_number)
Emit a full fault dump over the log backend.
Self-healing LPM register reset for very early boot.
static void ra8_lpm_safe_boot(void)
Restore LPSCR / SBYCR / DPSBYCR to cold-reset values.