88
99//! Architecture-specific code.
1010
11+ use arm_sysregs:: {
12+ CacheLevel , CacheType , CsselrEl1 , SctlrEl2 , read_ccsidr_el1, read_clidr_el1, read_sctlr_el2,
13+ write_csselr_el1,
14+ } ;
1115use core:: arch:: { asm, naked_asm} ;
1216
1317/// Data Synchronization Barrier.
@@ -34,64 +38,6 @@ pub fn isb() {
3438 }
3539}
3640
37- macro_rules! sys_reg {
38- ( $name: ident, { $( $const_name: ident: $const_val: expr) ,* } ) => {
39- pub mod $name {
40- use core:: arch:: asm;
41- $( pub const $const_name: u64 = $const_val; ) *
42-
43- #[ doc = concat!( "Read the `" , stringify!( $name) , "` system register." ) ]
44- #[ allow( unused) ]
45- pub fn read( ) -> u64 {
46- let val: u64 ;
47- // SAFETY: Reading a register is always safe.
48- unsafe {
49- asm!( concat!( "mrs {}, " , stringify!( $name) ) , out( reg) val, options( nostack, preserves_flags) ) ;
50- }
51- val
52- }
53-
54- #[ doc = concat!( "Write the `" , stringify!( $name) , "` system register." ) ]
55- ///
56- /// # Safety
57- ///
58- /// This function allows fundamental changes to the CPU state. To avoid Undefined
59- /// Behavior, the caller must guarantee:
60- ///
61- /// * The register is writable at the current Exception Level.
62- /// * The write must not invalidate the stack, the heap, or any active Rust references
63- /// (e.g., by disabling the MMU).
64- /// * This function emits a raw `MSR`. The caller is responsible for issuing context
65- /// synchronization (e.g., `ISB`) or memory barriers (`DSB`) if required.
66- #[ allow( unused) ]
67- pub unsafe fn write( val: u64 ) {
68- // SAFETY: The caller must ensure that the register is safely writeable.
69- unsafe {
70- asm!( concat!( "msr " , stringify!( $name) , ", {}" ) , in( reg) val, options( nostack, preserves_flags) ) ;
71- }
72- }
73- }
74- } ;
75- ( $name: ident) => {
76- sys_reg!( $name, { } ) ;
77- } ;
78- }
79-
80- sys_reg ! ( sctlr_el2, {
81- M : 1 << 0 ,
82- C : 1 << 2 ,
83- I : 1 << 12
84- } ) ;
85- sys_reg ! ( clidr_el1) ;
86- sys_reg ! ( csselr_el1) ;
87- sys_reg ! ( ccsidr_el1) ;
88- sys_reg ! ( hcr_el2) ;
89- sys_reg ! ( cntvoff_el2) ;
90- sys_reg ! ( cnthctl_el2) ;
91- sys_reg ! ( spsr_el2) ;
92- sys_reg ! ( elr_el2) ;
93- sys_reg ! ( sp_el1) ;
94-
9541/// Disables MMU and caches.
9642///
9743/// # Safety
@@ -105,7 +51,7 @@ sys_reg!(sp_el1);
10551///
10652/// # Registers
10753///
108- /// This function clobbers x27 and x28.
54+ /// In addition to the regular caller-saved registers, this function clobbers x27 and x28.
10955#[ unsafe( naked) ]
11056pub ( super ) unsafe extern "C" fn disable_mmu_and_caches ( ) {
11157 naked_asm ! (
@@ -137,53 +83,55 @@ extern "C" fn disable_mmu_and_caches_impl() -> u64 {
13783 invalidate_dcache ( ) ;
13884
13985 // Disable MMU and caches
140- let mut sctlr = sctlr_el2 :: read ( ) ;
141- sctlr &= !sctlr_el2 :: M ; // MMU Enable
142- sctlr &= !sctlr_el2 :: C ; // Data Cache Enable
143- sctlr &= !sctlr_el2 :: I ; // Instruction Cache Enable
144- sctlr
86+ let mut sctlr = read_sctlr_el2 ( ) ;
87+ sctlr. remove ( SctlrEl2 :: M ) ; // MMU Enable
88+ sctlr. remove ( SctlrEl2 :: C ) ; // Data Cache Enable
89+ sctlr. remove ( SctlrEl2 :: I ) ; // Instruction Cache Enable
90+ sctlr. bits ( )
14591}
14692
14793/// Invalidate D-cache by set/way to the point of coherency.
14894pub fn invalidate_dcache ( ) {
14995 dmb ( ) ;
15096
15197 // Cache Level ID Register
152- let clidr = clidr_el1 :: read ( ) ;
98+ let clidr = read_clidr_el1 ( ) ;
15399
154- // Level of Coherence (LoC) - Bits [26:24]
155- let loc = ( clidr >> 24 ) & 0x7 ;
100+ // Level of Coherence (LoC)
101+ let loc = clidr. loc ( ) ;
156102
157- for level in 0 ..loc {
158- let cache_type = ( clidr >> ( level * 3 ) ) & 0x7 ;
159-
160- // Cache Types: 0=None, 1=Instruction, 2=Data, 3=Split, 4=Unified
103+ for level in 1 ..=loc {
161104 // We don't care about No cache or Instruction cache
162- if cache_type < 2 {
163- continue ;
105+ let level = CacheLevel :: new ( level) ;
106+ match clidr. cache_type ( level) {
107+ CacheType :: NoCache | CacheType :: InstructionOnly => {
108+ continue ;
109+ }
110+ CacheType :: DataOnly | CacheType :: SeparateInstructionAndData | CacheType :: Unified => { }
164111 }
165112
166113 // Select the Cache Level in CSSELR (Cache Size Selection Register)
167- // SAFETY: Writing to `csselr_el1` is always safe, assuming the cache level exists.
168- unsafe {
169- csselr_el1:: write ( level << 1 ) ;
170- }
114+ write_csselr_el1 ( CsselrEl1 :: new ( false , level, false ) ) ;
171115
172116 // Barrier to ensure CSSELR write finishes before reading CCSIDR
173117 isb ( ) ;
174118
175119 // Cache Size ID Register (CCSIDR)
176- let ccsidr = ccsidr_el1 :: read ( ) ;
120+ let ccsidr = read_ccsidr_el1 ( ) ;
177121
178- let line_power = ( ccsidr & 0x7 ) + 4 ;
179- let ways = ( ccsidr >> 3 ) & 0x3FF ;
180- let sets = ( ccsidr >> 13 ) & 0x7FFF ;
122+ let line_size = ccsidr. linesize ( ) ;
123+ let ways = ( ccsidr. bits ( ) >> 3 ) & 0x3FF ;
124+ let sets = ( ccsidr. bits ( ) >> 13 ) & 0x7FFF ;
181125
182126 let way_shift = ( ways as u32 ) . leading_zeros ( ) ;
183127
184128 for set in 0 ..=sets {
185129 for way in 0 ..=ways {
186- let dc_val = ( way << way_shift) | ( set << line_power) | ( level << 1 ) ;
130+ const LEVEL_SHIFT : u8 = 1 ;
131+ const SET_WAY_SHIFT : u8 = 4 ;
132+ let dc_val = ( way << way_shift)
133+ | ( set << ( line_size + SET_WAY_SHIFT ) )
134+ | ( u64:: from ( level. level ( ) ) << LEVEL_SHIFT ) ;
187135
188136 // SAFETY: `dc cisw` is always safe, assuming the cache line exists.
189137 unsafe {
0 commit comments