system.zig (3818B)
1 const mem = @import("./mem.zig"); 2 3 pub const SystemControlRegister = packed struct { 4 pub const Endian = enum(u1) { 5 LittleEndian = 0, 6 BigEndian = 1, 7 }; 8 9 pub const ExceptionVectorBaseAddress = enum(u1) { 10 Normal = 0, 11 High = 1, 12 }; 13 14 pub const CacheReplacementStrategy = enum(u1) { 15 Random = 0, 16 RoundRobin = 1, 17 }; 18 19 mmu_enabled: bool, 20 strict_alignment: bool, 21 level_one_data_cache: bool, 22 _reserved_3: bool, 23 _reserved_6_4: u3, 24 endian: Endian, 25 mmu_protection: bool, 26 rom_protection: bool, 27 _reserved_10: bool, 28 branch_prediction: bool, 29 level_one_instruction_cache: bool, 30 exception_vector_base_address: ExceptionVectorBaseAddress, 31 cache_replacement_strategy: CacheReplacementStrategy, 32 set_t_bit: bool, 33 _reserved_16: bool, 34 _deprecated_17: bool, 35 _reserved_18: bool, 36 _deprecated_18: bool, 37 _reserved_20_19: bool, 38 low_latency_fiq: bool, 39 unaligned_data_access: bool, 40 extended_page_tables: bool, 41 vic_interface: bool, 42 cpsr_e_bit: bool, 43 _reserved_27_26: u2, 44 tex_remap: bool, 45 force_access_protection: bool, 46 _reserved_31_30: u2, 47 48 pub inline fn get() @This() { 49 return asm volatile ("MRC p15, 0, %[result], c1, c0, 0" 50 : [result] "=r" (-> @This()), 51 ); 52 } 53 54 pub inline fn set(reg: *const @This()) void { 55 return asm volatile ("MCR p15, 0, %[value], c1, c0, 0" 56 : 57 : [value] "r" (@as(u32, @bitCast(reg.*))), 58 ); 59 } 60 }; 61 62 inline fn invalidate_entire_instruction_cache() void { 63 asm volatile ("MCR p15, 0, %[value], c7, c5, 0" 64 : 65 : [value] "r" (0), 66 ); 67 } 68 69 inline fn invalidate_entire_data_cache() void { 70 asm volatile ("MCR p15, 0, %[value], c7, c6, 0" 71 : 72 : [value] "r" (0), 73 ); 74 } 75 76 pub inline fn clear_entire_data_cache() void { 77 asm volatile ("MCR p15, 0, %[value], c7, c14, 0" 78 : 79 : [value] "r" (0), 80 ); 81 } 82 83 // Probably affected by ARM bug too 84 // inline fn invalidate_both_caches() void { 85 // asm volatile ("MCR p15, 0, %[value], c7, c7, 0" 86 // : 87 // : [value] "r" (0), 88 // ); 89 // } 90 91 pub inline fn invalidate_instruction_TLB() void { 92 asm volatile ("MCR p15, 0, %[value], c8, c5, 0" 93 : 94 : [value] "r" (0), 95 ); 96 } 97 98 pub inline fn invalidate_data_TLB() void { 99 asm volatile ("MCR p15, 0, %[value], c8, c6, 0" 100 : 101 : [value] "r" (0), 102 ); 103 } 104 105 pub inline fn invalidate_TLB() void { 106 asm volatile ("MCR p15, 0, %[value], c8, c7, 0" 107 : 108 : [value] "r" (0), 109 ); 110 } 111 112 // https://elixir.bootlin.com/linux/latest/source/arch/arm/mm/cache-v6.S 113 // How TF does this even happen 114 pub inline fn invalidate_icache() void { 115 invalidate_entire_instruction_cache(); 116 invalidate_entire_instruction_cache(); 117 invalidate_entire_instruction_cache(); 118 invalidate_entire_instruction_cache(); 119 120 asm volatile ( 121 \\ .rept 11 122 \\ nop 123 \\ .endr 124 ); 125 } 126 127 pub inline fn invalidate_dcache() void { 128 invalidate_entire_data_cache(); 129 } 130 131 pub inline fn invalidate_all_caches() void { 132 invalidate_dcache(); 133 invalidate_icache(); 134 } 135 136 /// 2.7.5 137 /// 138 /// Call after: 139 /// 140 /// 1. Enabling/Disabling MMU 141 /// 2. Writing new data to instruction memory 142 /// 3. Writing new mapping to PTE 143 /// 4. Changing TTBR0, TTBR1, TTBCR 144 /// 5. Changing context ID 145 /// 146 /// Always perform a prefetch buffer afterwards (3-74) 147 pub inline fn flush_btb() void { 148 asm volatile ("mcr p15, 0, %[value], c7, c5, 6" 149 : 150 : [value] "r" (0), 151 ); 152 } 153 154 // 2.7.2 (B2-22) 155 pub inline fn flush_self_modifying_code() void { 156 clear_entire_data_cache(); 157 mem.barrier(.Write); 158 invalidate_icache(); 159 flush_btb(); 160 mem.barrier(.Write); 161 mem.barrier(.Instruction); 162 }