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