@@ -577,6 +577,7 @@ pub fn clrex() void {
577
577
}
578
578
579
579
const vector_count = @sizeOf (microzig .chip .VectorTable ) / @sizeOf (usize );
580
+ const mregs = @import ("m-profile.zig" );
580
581
581
582
var ram_vectors : [vector_count ]usize align (256 ) = undefined ;
582
583
@@ -631,6 +632,15 @@ pub const startup_logic = struct {
631
632
@memcpy (data_start [0.. data_len ], data_src [0.. data_len ]);
632
633
}
633
634
635
+ // We want the hardfault to be split into smaller parts:
636
+ mregs .registers .system_control_block .shcrs .modify (.{
637
+ .memfault_enabled = true ,
638
+ .busfault_enabled = true ,
639
+ .usagefault_enabled = true ,
640
+ });
641
+
642
+ enable_fault_irq ();
643
+
634
644
// Move vector table to RAM if requested
635
645
if (interrupt .has_ram_vectors ()) {
636
646
// Copy vector table to RAM and set VTOR to point to it
@@ -639,7 +649,6 @@ pub const startup_logic = struct {
639
649
@export (& ram_vectors , .{
640
650
.name = "_ram_vectors" ,
641
651
.section = "ram_vectors" ,
642
- .linkage = .strong ,
643
652
});
644
653
} else {
645
654
@export (& ram_vectors , .{
@@ -666,6 +675,12 @@ pub const startup_logic = struct {
666
675
var tmp : VectorTable = .{
667
676
.initial_stack_pointer = microzig .config .end_of_stack ,
668
677
.Reset = .{ .c = microzig .cpu .startup_logic ._start },
678
+
679
+ .NMI = panic_handler ("NMI" ),
680
+ .HardFault = panic_handler ("HardFault" ),
681
+ .MemManageFault = panic_handler ("MemManageFault" ),
682
+ .BusFault = make_fault_handler (default_bus_fault_handler ), // Exception 5
683
+ .UsageFault = make_fault_handler (default_usage_fault_handler ), // Exception 6
669
684
};
670
685
671
686
for (@typeInfo (@TypeOf (microzig .options .interrupts )).@"struct" .fields ) | field | {
@@ -677,6 +692,109 @@ pub const startup_logic = struct {
677
692
678
693
break :blk tmp ;
679
694
};
695
+
696
+ fn panic_handler (comptime msg : []const u8 ) microzig.interrupt.Handler {
697
+ const T = struct {
698
+ fn do_panic () callconv (.C ) noreturn {
699
+ @panic (msg );
700
+ }
701
+ };
702
+
703
+ return .{ .c = T .do_panic };
704
+ }
705
+
706
+ const ContextStateFrame = extern struct {
707
+ r0 : u32 ,
708
+ r1 : u32 ,
709
+ r2 : u32 ,
710
+ r3 : u32 ,
711
+ r12 : u32 ,
712
+ lr : u32 ,
713
+ return_address : u32 ,
714
+ xpsr : u32 ,
715
+ };
716
+
717
+ fn make_fault_handler (comptime handler : * const fn (context : * ContextStateFrame ) callconv (.C ) void ) microzig.interrupt.Handler {
718
+ const T = struct {
719
+ fn invoke () callconv (.C ) void {
720
+ // See this article on how we use that:
721
+ // https://interrupt.memfault.com/blog/cortex-m-hardfault-debug
722
+ asm volatile (
723
+ \\
724
+ // Check 2th bit of LR.
725
+ \\tst lr, #4
726
+ // Do "if then else" equal
727
+ \\ite eq
728
+ // if equals, we use the MSP
729
+ \\mrseq r0, msp
730
+ // otherwise, we use the PSP
731
+ \\mrsne r0, psp
732
+ // Then we branch to our handler:
733
+ \\b %[handler]
734
+ :
735
+ : [handler ] "s" (handler ),
736
+ );
737
+ }
738
+ };
739
+
740
+ return .{ .c = T .invoke };
741
+ }
742
+
743
+ const logger = std .log .scoped (.cortex_m );
744
+
745
+ fn default_bus_fault_handler (context : * ContextStateFrame ) callconv (.C ) void {
746
+ const bfsr = mregs .registers .system_control_block .bfsr .read ();
747
+
748
+ logger .err ("Bus Fault:" , .{});
749
+ logger .err (" context = r0:0x{X:0>8} r1:0x{X:0>8} r2:0x{X:0>8} r3:0x{X:0>8}" , .{
750
+ context .r0 ,
751
+ context .r1 ,
752
+ context .r2 ,
753
+ context .r3 ,
754
+ });
755
+ logger .err (" r12:0x{X:0>8} lr:0x{X:0>8} ra:0x{X:0>8} xpsr:0x{X:0>8}" , .{
756
+ context .r12 ,
757
+ context .lr ,
758
+ context .return_address ,
759
+ context .xpsr ,
760
+ });
761
+ logger .err (" instruction bus error = {}" , .{bfsr .instruction_bus_error });
762
+ logger .err (" precice data bus error = {}" , .{bfsr .precice_data_bus_error });
763
+ logger .err (" imprecice data bus error = {}" , .{bfsr .imprecice_data_bus_error });
764
+ logger .err (" unstacking exception error = {}" , .{bfsr .unstacking_exception_error });
765
+ logger .err (" exception stacking error = {}" , .{bfsr .exception_stacking_error });
766
+ logger .err (" busfault address register valid = {}" , .{bfsr .busfault_address_register_valid });
767
+ if (bfsr .busfault_address_register_valid ) {
768
+ const address = mregs .registers .system_control_block .bfar .read ().ADDRESS ;
769
+ logger .err (" busfault address register = 0x{X:0>8}" , .{address });
770
+ }
771
+ }
772
+
773
+ fn default_usage_fault_handler (context : * ContextStateFrame ) callconv (.C ) void {
774
+ const ufsr = mregs .registers .system_control_block .ufsr .read ();
775
+
776
+ logger .err ("Usage Fault:" , .{});
777
+ logger .err (" context = r0:0x{X:0>8} r1:0x{X:0>8} r2:0x{X:0>8} r3:0x{X:0>8}" , .{
778
+ context .r0 ,
779
+ context .r1 ,
780
+ context .r2 ,
781
+ context .r3 ,
782
+ });
783
+ logger .err (" r12:0x{X:0>8} lr:0x{X:0>8} ra:0x{X:0>8} xpsr:0x{X:0>8}" , .{
784
+ context .r12 ,
785
+ context .lr ,
786
+ context .return_address ,
787
+ context .xpsr ,
788
+ });
789
+ logger .err (" undefined instruction = {}" , .{ufsr .undefined_instruction });
790
+ logger .err (" invalid state = {}" , .{ufsr .invalid_state });
791
+ logger .err (" invalid pc load = {}" , .{ufsr .invalid_pc_load });
792
+ logger .err (" missing coprocessor usage = {}" , .{ufsr .missing_coprocessor_usage });
793
+ logger .err (" unaligned memory access = {}" , .{ufsr .unaligned_memory_access });
794
+ logger .err (" divide by zero = {}" , .{ufsr .divide_by_zero });
795
+
796
+ @panic ("usage fault" );
797
+ }
680
798
};
681
799
682
800
fn is_ramimage () bool {
0 commit comments