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}