Skip to main content

cortexm/
scb.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Cortex-M System Control Block (SCB)
6//!
7//! <http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/CIHFDJCA.html>
8
9use kernel::utilities::StaticRef;
10use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
11use kernel::utilities::registers::{ReadOnly, ReadWrite, register_bitfields, register_structs};
12
13register_structs! {
14    /// In an ARMv7-M processor, a System Control Block (SCB) in the SCS
15    /// provides key status information and control features for the processor.
16    ScbRegisters {
17        /// CPUID Base Register
18        (0x00 => cpuid: ReadOnly<u32, CpuId::Register>),
19
20        /// Interrupt Control and State Register
21        (0x04 => icsr: ReadWrite<u32, InterruptControlAndState::Register>),
22
23        /// Vector Table Offset Register
24        (0x08 => vtor: ReadWrite<u32, VectorTableOffset::Register>),
25
26        /// Application Interrupt and Reset Control Register
27        (0x0c => aircr: ReadWrite<u32, ApplicationInterruptAndReset::Register>),
28
29        /// System Control Register
30        (0x10 => scr: ReadWrite<u32, SystemControl::Register>),
31
32        /// Configuration and Control Register
33        (0x14 => ccr: ReadWrite<u32, ConfigurationAndControl::Register>),
34
35        /// System Handler Priority Register (1-4)
36        (0x18 => shp: [ReadWrite<u32, SystemHandlerPriority::Register>; 3]),
37
38        /// System Handler Control and State Register
39        (0x24 => shcsr: ReadWrite<u32, SystemHandlerControlAndState::Register>),
40
41        /// Configurable Fault Status Register
42        (0x28 => cfsr: ReadWrite<u32, ConfigurableFaultStatus::Register>),
43
44        /// HardFault Status Register
45        (0x2c => hfsr: ReadWrite<u32, HardFaultStatus::Register>),
46
47        /// Debug Fault Status Register
48        (0x30 => dfsr: ReadWrite<u32, DebugFaultStatus::Register>),
49
50        /// MemManage Fault Address Register
51        (0x34 => mmfar: ReadWrite<u32, FaultAddress::Register>),
52
53        /// BusFault Address Register
54        (0x38 => bfar: ReadWrite<u32, FaultAddress::Register>),
55
56        /// Auxiliary Fault Status Register
57        (0x3c => afsr: ReadWrite<u32, FaultAddress::Register>),
58
59        /// 0xE000ED40-7C, Reserved for CPUID registers.
60        (0x40 => _reserved0),
61
62        /// 0xE000ED80-84, Reserved.
63        (0x80 => _reserved1),
64
65        /// Coprocessor Access Control Register
66        (0x88 => cpacr: ReadWrite<u32, CoprocessorAccessControl::Register>),
67
68        /// 0xE000ED8C, Reserved.
69        (0x8c => _reserved2),
70
71        (0x90 => @END),
72    }
73}
74
75register_bitfields![u32,
76    CpuId [
77        /// Implementer code assigned by ARM. ARM implementations are 0x41.
78        IMPLEMENTER     OFFSET(24)  NUMBITS(8),
79
80        /// Implementer-defined variant number.
81        VARIANT         OFFSET(20)  NUMBITS(4),
82
83        /// Archtiecture always reads as 0xF for Cortex-M
84        ARCHITECTURE    OFFSET(16)  NUMBITS(4),
85
86        /// Implementer-defined part number.
87        PARTNO          OFFSET(4)   NUMBITS(12),
88
89        /// Implementer-defined revision number.
90        REVISION        OFFSET(0)   NUMBITS(4)
91    ],
92
93    InterruptControlAndState [
94        /// Non-Maskable Interrupt.
95        /// Write 0 is no-op, write 1 triggers. Read returns whether NMI is active.
96        /// RW.
97        NMIPENDSET      OFFSET(31)  NUMBITS(1),
98
99        /// Pendable SerVice.
100        /// Write 0 is no-op, write 1 triggers. Read returns whether PendSV is active.
101        /// RW.
102        PENDSVSET       OFFSET(28)  NUMBITS(1),
103
104        /// Write 1 to clear PendSV.
105        /// WO.
106        PENDSVCLR       OFFSET(27)  NUMBITS(1),
107
108        /// Pendable SysTick.
109        /// Write 0 is no-op, write 1 triggers. Read returns whether PendST is active.
110        /// RW.
111        PENDSTSET       OFFSET(26)  NUMBITS(1),
112
113        /// Write 1 to clear PendST.
114        /// WO.
115        PENDSTCLR       OFFSET(25)  NUMBITS(1),
116
117        /// Whether an exception will be serviced when existing debug state.
118        /// RO.
119        ISRPREEMPT      OFFSET(23)  NUMBITS(1),
120
121        /// Whether an external interrupt (from NVIC) is pending.
122        /// RO.
123        ISRPENDING      OFFSET(22)  NUMBITS(1),
124
125        /// Highest pending exception. Zero if none pending.
126        /// RO.
127        VECTACTIVE      OFFSET(0)   NUMBITS(9)
128    ],
129
130    /// Note: Software can write all 1s to `TBLOFF` and read result to learn
131    /// maximum supported value.
132    VectorTableOffset [
133        /// Bits [31:7] of the vector table address
134        /// n.b. bits [6:0] are always 0.
135        TBLOFF          OFFSET(7)   NUMBITS(25)
136    ],
137
138    ApplicationInterruptAndReset [
139        /// Key field. Must write 0x05FA or write is ignored. Reads as 0xFA05.
140        /// RW.
141        VECTKEY         OFFSET(16)  NUMBITS(16),
142
143        /// 0=Little endian, 1=Big endian.
144        /// RO.
145        ENDIANNESS      OFFSET(15)  NUMBITS(1),
146
147        /// Binary point position for priority grouping. Defaults to 0b000.
148        /// RW.
149        PRIGROUP        OFFSET(8)   NUMBITS(3),
150
151        /// Writing 1 to this bit requests a Local reset. Cleared to 0b0 on reset.
152        /// RW.
153        SYSRESETREQ     OFFSET(2)   NUMBITS(1),
154
155        /// Writing 1 clears all state information for exceptions.
156        /// WARN: Writing this bit when not in a Debug halt is UNPREDICTABLE.
157        /// WO.
158        VECTCLRACTIVE   OFFSET(1)   NUMBITS(1),
159
160        /// Writing 1 causes a local system reset.
161        /// WARN: Writing this bit when not in a Debug halt is UNPREDICTABLE.
162        /// WARN: Writing this and `SYSRESETREQ` is UNPREDICTABLE.
163        /// WO.
164        VECTRESET       OFFSET(0)   NUMBITS(1)
165    ],
166
167    SystemControl [
168        SEVONPEND       OFFSET(4)   NUMBITS(1),
169        SLEEPDEEP       OFFSET(2)   NUMBITS(1),
170        SLEEPONEXIT     OFFSET(1)   NUMBITS(1)
171    ],
172
173    ConfigurationAndControl [
174        STKALIGN        OFFSET(9)   NUMBITS(1),
175        BFHFNMIGN       OFFSET(8)   NUMBITS(1),
176        DIV_0_TRAP      OFFSET(4)   NUMBITS(1),
177        UNALIGN_TRP     OFFSET(3)   NUMBITS(1),
178        USERSETMPEND    OFFSET(1)   NUMBITS(1),
179        NONBASETHRDENA  OFFSET(0)   NUMBITS(1)
180    ],
181
182    // Note: Simplified
183    SystemHandlerPriority [
184        PRI_N3          OFFSET(24)  NUMBITS(4),
185        PRI_N2          OFFSET(16)  NUMBITS(4),
186        PRI_N1          OFFSET(8)   NUMBITS(4),
187        PRI_N0          OFFSET(0)   NUMBITS(4)
188    ],
189
190    SystemHandlerControlAndState [
191        USGFAULTENA     OFFSET(18)  NUMBITS(1),
192        BUSFAULTENA     OFFSET(17)  NUMBITS(1),
193        MEMFAULTENA     OFFSET(16)  NUMBITS(1),
194        SVCALLPENDED    OFFSET(15)  NUMBITS(1),
195        BUSFAULTPENDED  OFFSET(14)  NUMBITS(1),
196        MEMFAULTPENDED  OFFSET(14)  NUMBITS(1),
197        USGFAULTPENDED  OFFSET(14)  NUMBITS(1),
198        SYSTICKACT      OFFSET(11)  NUMBITS(1),
199        PENDSVACT       OFFSET(10)  NUMBITS(1),
200        MONITORACT      OFFSET(8)   NUMBITS(1),
201        SVCALLACT       OFFSET(7)   NUMBITS(1),
202        USGFAULTACT     OFFSET(3)   NUMBITS(1),
203        BUSFAULTACT     OFFSET(1)   NUMBITS(1),
204        MEMFAULTACT     OFFSET(0)   NUMBITS(1)
205    ],
206
207    ConfigurableFaultStatus [
208        UsageFault      OFFSET(16)  NUMBITS(16),
209        BusFault        OFFSET(8)   NUMBITS(8),
210        MemManage       OFFSET(0)   NUMBITS(8)
211    ],
212
213    MemManageStatus [
214        MMARVALID       OFFSET(7)   NUMBITS(1),
215        MLSPERR         OFFSET(5)   NUMBITS(1),
216        MSTKERR         OFFSET(4)   NUMBITS(1),
217        MUNSTKERR       OFFSET(3)   NUMBITS(1),
218        DACCVIOL        OFFSET(1)   NUMBITS(1),
219        IACCVIOL        OFFSET(1)   NUMBITS(1)
220    ],
221
222    BusFaultStatus [
223        BFARVALID       OFFSET(7)   NUMBITS(1),
224        LSPERR          OFFSET(5)   NUMBITS(1),
225        STKERR          OFFSET(4)   NUMBITS(1),
226        UNSTKERR        OFFSET(3)   NUMBITS(1),
227        IMPRECISERR     OFFSET(2)   NUMBITS(1),
228        PRECISERR       OFFSET(1)   NUMBITS(1),
229        IBUSERR         OFFSET(0)   NUMBITS(1)
230    ],
231
232    UsageFaultStatus [
233        DIVBYZERO       OFFSET(9)   NUMBITS(1),
234        UNALIGNED       OFFSET(8)   NUMBITS(1),
235        NOCP            OFFSET(3)   NUMBITS(1),
236        INVPC           OFFSET(2)   NUMBITS(1),
237        INVSTATE        OFFSET(1)   NUMBITS(1),
238        UNDEFINSTR      OFFSET(0)   NUMBITS(1)
239    ],
240
241    HardFaultStatus [
242        DEBUGEVT        OFFSET(31)  NUMBITS(1),
243        FORCED          OFFSET(30)  NUMBITS(1),
244        VECTTBL         OFFSET(1)   NUMBITS(1)
245    ],
246
247    DebugFaultStatus [
248        EXTERNAL        OFFSET(4)   NUMBITS(1),
249        VCATCH          OFFSET(3)   NUMBITS(1),
250        DWTTRAP         OFFSET(2)   NUMBITS(1),
251        BKPT            OFFSET(1)   NUMBITS(1),
252        HALTED          OFFSET(0)   NUMBITS(1)
253    ],
254
255    FaultAddress [
256        ADDRESS         OFFSET(0)   NUMBITS(32)
257    ],
258
259    CoprocessorAccessControl [
260        CP11            OFFSET(22)  NUMBITS(2),
261        CP10            OFFSET(20)  NUMBITS(2),
262        CP7             OFFSET(14)  NUMBITS(2),
263        CP6             OFFSET(12)  NUMBITS(2),
264        CP5             OFFSET(10)  NUMBITS(2),
265        CP4             OFFSET(8)  NUMBITS(2),
266        CP3             OFFSET(6)  NUMBITS(2),
267        CP2             OFFSET(4)  NUMBITS(2),
268        CP1             OFFSET(2)  NUMBITS(2),
269        CP0             OFFSET(0)  NUMBITS(2)
270    ]
271];
272
273const SCB: StaticRef<ScbRegisters> = unsafe { StaticRef::new(0xE000ED00 as *const ScbRegisters) };
274
275/// Allow the core to go into deep sleep on WFI.
276///
277/// The specific definition of "deep sleep" is chip specific.
278#[cfg(all(target_arch = "arm", target_os = "none"))]
279pub unsafe fn set_sleepdeep() {
280    use core::arch::asm;
281
282    SCB.scr.modify(SystemControl::SLEEPDEEP::SET);
283
284    // # Safety
285    //
286    // - INPUTS: This does not use the existing value of any registers.
287    // - OUTPUTS: This does not write any registers.
288    // - Options set:
289    //   - nomem: We do not read or write memory.
290    //   - nostack: This does not use the stack.
291    //   - preserves_flags: This does not change flags.
292    // - Options not set:
293    //   - pure: not required
294    //   - readonly: implied by nomem
295    //   - noreturn: we do fall-through
296    //   - att_syntax: not on arm
297    //   - raw: not required
298    unsafe {
299        asm!(
300            "
301    dsb                 // Data Synchronization Barrier
302    isb                 // Instruction Synchronization Barrier
303            ",
304            options(nomem, nostack, preserves_flags)
305        );
306    }
307}
308
309// Mock implementation for tests on Travis-CI.
310#[cfg(not(all(target_arch = "arm", target_os = "none")))]
311pub unsafe fn set_sleepdeep() {
312    // Dummy operation to satisfy the `Writable` trait import on
313    // non-ARM platforms.
314    SCB.scr.modify(SystemControl::SLEEPDEEP::SET);
315
316    unimplemented!()
317}
318
319/// Do not allow the core to go into deep sleep on WFI.
320///
321/// The specific definition of "deep sleep" is chip specific.
322pub unsafe fn unset_sleepdeep() {
323    SCB.scr.modify(SystemControl::SLEEPDEEP::CLEAR);
324}
325
326/// Software reset using the ARM System Control Block
327pub unsafe fn reset() {
328    SCB.aircr.modify(
329        ApplicationInterruptAndReset::VECTKEY.val(0x05FA)
330            + ApplicationInterruptAndReset::PRIGROUP.val(0b111)
331            + ApplicationInterruptAndReset::SYSRESETREQ::SET,
332    );
333}
334
335/// relocate interrupt vector table
336pub unsafe fn set_vector_table_offset(offset: *const ()) {
337    SCB.vtor.set(offset as u32);
338}
339
340/// Disable the FPU
341#[cfg(all(target_arch = "arm", target_os = "none"))]
342pub unsafe fn disable_fpca() {
343    use core::arch::asm;
344    SCB.cpacr
345        .modify(CoprocessorAccessControl::CP10::CLEAR + CoprocessorAccessControl::CP11::CLEAR);
346
347    // # Safety
348    //
349    // - INPUTS: This does not use the existing value of any registers.
350    // - OUTPUTS: This does not write any registers.
351    // - Options set:
352    //   - nomem: We do not read or write memory.
353    //   - nostack: This does not use the stack.
354    //   - preserves_flags: This does not change flags.
355    // - Options not set:
356    //   - pure: not required
357    //   - readonly: implied by nomem
358    //   - noreturn: we do fall-through
359    //   - att_syntax: not on arm
360    //   - raw: not required
361    unsafe {
362        asm!(
363            "
364    dsb                 // Data Synchronization Barrier
365    isb                 // Instruction Synchronization Barrier
366            ",
367            options(nomem, nostack, preserves_flags)
368        );
369    }
370
371    if SCB.cpacr.read(CoprocessorAccessControl::CP10) != 0
372        || SCB.cpacr.read(CoprocessorAccessControl::CP11) != 0
373    {
374        panic!("Unable to disable FPU");
375    }
376}
377
378// Mock implementation for tests on Travis-CI.
379#[cfg(not(all(target_arch = "arm", target_os = "none")))]
380pub unsafe fn disable_fpca() {
381    // Dummy read register, to satisfy the `Readable` trait import on
382    // non-ARM platforms.
383    let _ = SCB.cpacr.read(CoprocessorAccessControl::CP10);
384
385    unimplemented!()
386}
387
388/// Disable the MemFault exception.
389///
390/// # Notes
391///
392/// This escalates the exception to a HardFault instead of triggering a
393/// MemFault exception, so it does not _disable_ MemFault completely.
394pub unsafe fn disable_memfault() {
395    SCB.shcsr
396        .modify(SystemHandlerControlAndState::MEMFAULTENA::CLEAR);
397}
398
399/// Disable the UsageFault exception.
400///
401/// # Notes
402///
403/// This escalates the exception to a HardFault instead of triggering a
404/// UsageFault exception, so it does not _disable_ UsageFault completely.
405pub unsafe fn disable_usagefault() {
406    SCB.shcsr
407        .modify(SystemHandlerControlAndState::USGFAULTENA::CLEAR);
408}
409
410/// Disable the BusFault exception.
411///
412/// # Notes
413///
414/// This escalates the exception to a HardFault instead of triggering a
415/// BusFault exception, so it does not _disable_ BusFault completely.
416pub unsafe fn disable_busfault() {
417    SCB.shcsr
418        .modify(SystemHandlerControlAndState::BUSFAULTENA::CLEAR);
419}