MCCI Trusted Bootloader
Simple trusted bootloader and tools for small embedded systems
mcci_arm_cm0plus.h
Go to the documentation of this file.
1/*
2
3Module: mcci_arm_cm0plus.h
4
5Function:
6 ARM cm0plus definitions without CMSIS overhead.
7
8Copyright and License:
9 This file copyright (C) 2021 by
10
11 MCCI Corporation
12 3520 Krums Corners Road
13 Ithaca, NY 14850
14
15 See accompanying LICENSE file for copyright and license information.
16
17Author:
18 Terry Moore, MCCI Corporation March 2021
19
20*/
21
22#ifndef _mcci_arm_cm0plus_h_
23#define _mcci_arm_cm0plus_h_ /* prevent multiple includes */
24
25#pragma once
26
27#ifndef _mcci_bootloader_bits_h_
28# include "mcci_bootloader_bits.h"
29#endif
30
31#include <stdint.h>
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37/****************************************************************************\
38|
39| Special function register values
40|
41\****************************************************************************/
42
43/// \name CPU Special function registers
44/// @{
45#define MCCI_CM0PLUS_SYSM_APSR UINT32_C(0x00) ///< Flags from previous instructions
46#define MCCI_CM0PLUS_SYSM_IAPSR UINT32_C(0x01) ///< Composite of IPSR and APSR
47#define MCCI_CM0PLUS_SYSM_EAPSR UINT32_C(0x02) ///< Composite of EPSR and APSR
48#define MCCI_CM0PLUS_SYSM_XPSR UINT32_C(0x03) ///< Composite of EPSR, IPSR and APSR
49#define MCCI_CM0PLUS_SYSM_IPSR UINT32_C(0x05) ///< Interrupt status register
50#define MCCI_CM0PLUS_SYSM_EPSR UINT32_C(0x06) ///< Exception status register
51#define MCCI_CM0PLUS_SYSM_IEPSR UINT32_C(0x07) ///< Composite of IPSR and EPSR
52#define MCCI_CM0PLUS_SYSM_MSP UINT32_C(0x08) ///< Main stack pointer
53#define MCCI_CM0PLUS_SYSM_PSP UINT32_C(0x09) ///< Process stack pointer
54#define MCCI_CM0PLUS_SYSM_PRIMASK UINT32_C(0x10) ///< priority mask register
55#define MCCI_CM0PLUS_SYSM_CONTROL UINT32_C(0x14) ///< control register
56
57/// \name PRIMASK special register fields
58/// @{
59#define MCCI_CM0PLUS_SR_PRIMASK_DISABLE (UINT32_C(1) << 0) ///< the bit to disable interrupts
60/// @}
61
62/* end of special-function registers */
63/// @}
64
65/****************************************************************************\
66|
67| Register addresses
68|
69\****************************************************************************/
70
71#define MCCI_CM0PLUS_SCS_BASE UINT32_C(0xE000E000)
72
73/// \name SYSTICK registers
74/// @{
75#define MCCI_CM0PLUS_SYSTICK UINT32_C(0xE000E010)
76#define MCCI_CM0PLUS_SYSTICK_CSR (MCCI_CM0PLUS_SYSTICK + 0x0)
77#define MCCI_CM0PLUS_SYSTICK_RVR (MCCI_CM0PLUS_SYSTICK + 0x4)
78#define MCCI_CM0PLUS_SYSTICK_CVR (MCCI_CM0PLUS_SYSTICK + 0x8)
79#define MCCI_CM0PLUS_SYSTICK_CALIB (MCCI_CM0PLUS_SYSTICK + 0xC)
80/// @}
81
82/// \name NVIC registers
83/// @{
84#define MCCI_CM0PLUS_NVIC UINT32_C(0xE000E100)
85#define MCCI_CM0PLUS_NVIC_ISER (MCCI_CM0PLUS_NVIC + 0x000)
86#define MCCI_CM0PLUS_NVIC_ICER (MCCI_CM0PLUS_NVIC + 0x080)
87#define MCCI_CM0PLUS_NVIC_ISPR (MCCI_CM0PLUS_NVIC + 0x100)
88#define MCCI_CM0PLUS_NVIC_ICPR (MCCI_CM0PLUS_NVIC + 0x180)
89#define MCCI_CM0PLUS_NVIC_IP0 (MCCI_CM0PLUS_NVIC + 0x300)
90#define MCCI_CM0PLUS_NVIC_IP1 (MCCI_CM0PLUS_NVIC + 0x304)
91#define MCCI_CM0PLUS_NVIC_IP2 (MCCI_CM0PLUS_NVIC + 0x308)
92#define MCCI_CM0PLUS_NVIC_IP3 (MCCI_CM0PLUS_NVIC + 0x30C)
93#define MCCI_CM0PLUS_NVIC_IP4 (MCCI_CM0PLUS_NVIC + 0x310)
94#define MCCI_CM0PLUS_NVIC_IP5 (MCCI_CM0PLUS_NVIC + 0x314)
95#define MCCI_CM0PLUS_NVIC_IP6 (MCCI_CM0PLUS_NVIC + 0x318)
96#define MCCI_CM0PLUS_NVIC_IP7 (MCCI_CM0PLUS_NVIC + 0x31C)
97/// @}
98
99/// \name SCB registers
100/// @{
101#define MCCI_CM0PLUS_SCB UINT32_C(0xE000ED00)
102#define MCCI_CM0PLUS_SCB_CPUID (MCCI_CM0PLUS_SCB + 0x00)
103#define MCCI_CM0PLUS_SCB_ICSR (MCCI_CM0PLUS_SCB + 0x04)
104#define MCCI_CM0PLUS_SCB_VTOR (MCCI_CM0PLUS_SCB + 0x08)
105#define MCCI_CM0PLUS_SCB_AIRCR (MCCI_CM0PLUS_SCB + 0x0C)
106#define MCCI_CM0PLUS_SCB_SCR (MCCI_CM0PLUS_SCB + 0x10)
107#define MCCI_CM0PLUS_SCB_CCR (MCCI_CM0PLUS_SCB + 0x14)
108#define MCCI_CM0PLUS_SCB_SHPR2 (MCCI_CM0PLUS_SCB + 0x1C)
109#define MCCI_CM0PLUS_SCB_SHPR3 (MCCI_CM0PLUS_SCB + 0x20)
110#define MCCI_CM0PLUS_SCB_SHCSR (MCCI_CM0PLUS_SCB + 0x24)
111#define MCCI_CM0PLUS_SCB_DFSR (MCCI_CM0PLUS_SCB + 0x30)
112/// @}
113
114/// \name MPU registers
115/// @{
116#define MCCI_CM0PLUS_MPU UINT32_C(0xE000ED90)
117#define MCCI_CM0PLUS_MPU_TYPE (MCCI_CM0PLUS_MPU + 0x00) //<
118#define MCCI_CM0PLUS_MPU_CTRL (MCCI_CM0PLUS_MPU + 0x04) //<
119#define MCCI_CM0PLUS_MPU_RNR (MCCI_CM0PLUS_MPU + 0x08) //<
120#define MCCI_CM0PLUS_MPU_RBAR (MCCI_CM0PLUS_MPU + 0x0C) //<
121#define MCCI_CM0PLUS_MPU_RASR (MCCI_CM0PLUS_MPU + 0x10) //<
122/// @}
123
124/****************************************************************************\
125|
126| Register bits
127|
128\****************************************************************************/
129
130/// \name SYSTICK CSR bits
131/// @{
132#define MCCI_CM0PLUS_SYSTICK_CSR_RSV17 UINT32_C(0xFFFE0000) ///< reserved
133#define MCCI_CM0PLUS_SYSTICK_CSR_COUNTFLAG (UINT32_C(1) << 16) ///< timer has counted to zero
134#define MCCI_CM0PLUS_SYSTICK_CSR_RSV3 UINT32_C(0x0000FFF8) ///< reserved
135#define MCCI_CM0PLUS_SYSTICK_CSR_CLKSOURCE (UINT32_C(1) << 2) ///< use processor (not external) clock
136#define MCCI_CM0PLUS_SYSTICK_CSR_TICKINT (UINT32_C(1) << 1) ///< enable tick exception
137#define MCCI_CM0PLUS_SYSTICK_CSR_ENABLE (UINT32_C(1) << 0) ///< enable counter
138/// @}
139
140/// \name SYSTICK RVR bits
141/// @{
142#define MCCI_CM0PLUS_SYSTICK_RVR_RSV24 UINT32_C(0xFF000000) ///< reserved, zero
143#define MCCI_CM0PLUS_SYSTICK_RVR_RELOAD UINT32_C(0x00FFFFFF) ///< reload value
144/// @}
145
146/// \name SYSTICK CVR bits
147/// @{
148#define MCCI_CM0PLUS_SYSTICK_CVR_RSV24 UINT32_C(0xFF000000) ///< reserved, read as zero
149#define MCCI_CM0PLUS_SYSTICK_CVR_CURRENT UINT32_C(0x00FFFFFF) ///< current value
150/// @}
151
152/// \name SYSTICK CALIB bits
153/// @{
154#define MCCI_CM0PLUS_SYSTICK_CALIB_NOREF (UINT32_C(1) << 31) ///< reference clock is not implemented
155#define MCCI_CM0PLUS_SYSTICK_CALIB_SKEW (UINT32_C(1) << 30) ///< 10ms cal value is inexact
156#define MCCI_CM0PLUS_SYSTICK_CALIB_RSV24 (UINT32_C(0x3F) << 24) ///< reserved, zero
157#define MCCI_CM0PLUS_SYSTICK_CALIB_TENMS UINT32_C(0x00FFFFFF) ///< if non-zero, use this as reload value for 10ms ticks
158/// @}
159
160/// \name NVIC IPR bits
161
162/// \name SCB CPUID fields
163/// @{
164#define MCCI_CM0PLUS_SCB_CPUID_IMPLEMENTER (UINT32_C(0xFF) << 24) ///< Implementer code
165#define MCCI_CM0PLUS_SCB_CPUID_VARIANT (UINT32_C(0xF) << 20) ///< Variant code
166#define MCCI_CM0PLUS_SCB_CPUID_ARCHITECTURE (UINT32_C(0xF) << 16) ///< Architecture code
167#define MCCI_CM0PLUS_SCB_CPUID_PARTNO (UINT32_C(0xFFF) << 4) ///< Part number
168#define MCCI_CM0PLUS_SCB_CPUID_REVISION (UINT32_C(0xF) << 0) ///< Revision
169/// @}
170
171/// \name SCB ICSR fields
172/// @{
173#define MCCI_CM0PLUS_SCB_ICSR_NMIPENDSET (UINT32_C(1) << 31) ///<
174#define MCCI_CM0PLUS_SCB_ICSR_RSV29 (UINT32_C(3) << 29) ///<
175#define MCCI_CM0PLUS_SCB_ICSR_PENDSVSET (UINT32_C(1) << 28) ///<
176#define MCCI_CM0PLUS_SCB_ICSR_PENDSVCLR (UINT32_C(1) << 27) ///<
177#define MCCI_CM0PLUS_SCB_ICSR_PENDSTSET (UINT32_C(1) << 26) ///<
178#define MCCI_CM0PLUS_SCB_ICSR_PENDSTCLR (UINT32_C(1) << 26) ///<
179#define MCCI_CM0PLUS_SCB_ICSR_RSV24 (UINT32_C(1) << 24) ///<
180#define MCCI_CM0PLUS_SCB_ICSR_ISRPREEMPT (UINT32_C(1) << 23) ///<
181#define MCCI_CM0PLUS_SCB_ICSR_ISRPENDING (UINT32_C(1) << 22) ///<
182#define MCCI_CM0PLUS_SCB_ICSR_VECTPENDING (UINT32_C(0x1FF) << 12) ///<
183#define MCCI_CM0PLUS_SCB_ICSR_VECTACTIVE (UINT32_C(0x1FF) << 0) ///<
184/// @}
185
186/// \name SCB VTOR fields
187/// @{
188#define MCCI_CM0PLUS_SCB_VTOR_TBLOFF UINT32_C(0xFFFFFF00) ///<
189/// @}
190
191/// \name SCB AIRCR fields (Appplication Interrupt and Reset Control)
192/// @{
193#define MCCI_CM0PLUS_SCB_AIRCR_VECTKEY (UINT32_C(0xFFFF) << 16) ///< Vector key
194#define MCCI_CM0PLUS_SCB_AIRCR_VECTKEY_VALUE (UINT32_C(0x05FA) << 16) ///< Value to write to unlock regster.
195#define MCCI_CM0PLUS_SCB_AIRCR_ENDIANNESS (UINT32_C(1) << 15) ///<
196#define MCCI_CM0PLUS_SCB_AIRCR_SYSRESETREQ (UINT32_C(1) << 2) ///<
197#define MCCI_CM0PLUS_SCB_AIRCR_VECTCLRACTIVE (UINT32_C(1) << 1) ///<
198/// @}
199
200/// \name SCB SCR fields
201/// @{
202#define MCCI_CM0PLUS_SCB_SCR_SEVONPEND (UINT32_C(1) << 4) ///<
203#define MCCI_CM0PLUS_SCB_SCR_SLEEPDEEP (UINT32_C(1) << 2) ///<
204#define MCCI_CM0PLUS_SCB_SCR_SLEEPONEXIT (UINT32_C(1) << 1) ///<
205/// @}
206
207/// \name SCB Configuration Control Register bits
208/// @{
209#define MCCI_CM0PLUS_SCB_CCR_STKALIGN (UINT32_C(1) << 9) ///<
210#define MCCI_CM0PLUS_SCB_CCR_UNALIGNED (UINT32_C(1) << 3) ///<
211/// @}
212
213/// \name SCB SHPR access
214/// @{
215#define MCCI_CM0PLUS_SCB_SHPR_PRI (UINT32_C(3) << 6) ///< priority bits within a byte
216
217#define MCCI_CM0PLUS_PRI_INDEX_SVC UINT32_C(11) ///< priority of systick
218#define MCCI_CM0PLUS_PRI_INDEX_PENDSV UINT32_C(14) ///< priority of systick
219#define MCCI_CM0PLUS_PRI_INDEX_SYSTICK UINT32_C(15) ///< priority of systick
220
221/// \brief return register for a given handler index
222static inline uint32_t
224 uint32_t handlerIndex
225 )
226 {
227 // map to either SPHR2 or SHPR3.
228 return MCCI_CM0PLUS_SCB_SHPR2 + (handlerIndex & 4);
229 }
230
231/// \brief return byte mask for a given handler index
232static inline uint32_t
234 uint32_t handlerIndex
235 )
236 {
237 // compute and return the mask for a given bit
238 return UINT32_C(0xE0) << (8 * (handlerIndex & 3));
239 }
240/// @}
241
242/// \name SCB System Handler Control and State Register bits
243/// @{
244#define MCCI_CM0PLUS_SCB_SHCSR_SVCALLPENDED (UINT32_C(1) << 15) ///<
245/// @}
246
247/****************************************************************************\
248|
249| Register access primitives
250|
251\****************************************************************************/
252
253/// \brief write a 32-bit value to a cm0plus register
254__attribute__((__always_inline__))
255static inline uint32_t
256McciArm_putReg(uint32_t reg, uint32_t val)
257 {
258 *(volatile uint32_t *)reg = val;
259 return val;
260 }
261
262/// \brief read a 32-bit value from a cm0plus register
263__attribute__((__always_inline__))
264static inline uint32_t
265McciArm_getReg(uint32_t reg)
266 {
267 return *(volatile uint32_t *)reg;
268 }
269
270/// \brief and/or 32-bit values to a cm0plus register
271__attribute__((__always_inline__))
272static inline uint32_t
273McciArm_putRegAndOr(uint32_t reg, uint32_t andVal, uint32_t orVal)
274 {
275 uint32_t const rValue = McciArm_getReg(reg);
276
277 return McciArm_putReg(
278 reg,
279 (rValue & andVal) | orVal
280 );
281 }
282
283/// \brief or 32-bit values to a cm0plus register
284__attribute__((__always_inline__))
285static inline uint32_t
286McciArm_putRegOr(uint32_t reg, uint32_t orVal)
287 {
288 uint32_t const rValue = McciArm_getReg(reg);
289
290 return McciArm_putReg(
291 reg,
292 rValue | orVal
293 );
294 }
295
296/// \brief clear out 32-bit values to a cm0plus register
297__attribute__((__always_inline__))
298static inline uint32_t
299McciArm_putRegClear(uint32_t reg, uint32_t clearVal)
300 {
301 uint32_t const rValue = McciArm_getReg(reg);
302
303 return McciArm_putReg(
304 reg,
305 rValue & ~clearVal
306 );
307 }
308
309///
310/// \brief clear and set 32-bit values to a cm0plus register
311///
312/// \param [in] reg register to be modified
313/// \param [in] clearVal mask of bits to be cleared (1 in mask clears bit in reg)
314/// \param [in] setVal mask of bits to be set
315///
316/// \note this is subtly different than \ref McciArm_putRegMasked,
317/// in that \p setVal is not modified by \p clearVal. Any bits
318/// set in \p setVal are unconditionally set in \p reg, whereas
319/// \ref McciArm_putRegMasked only changes bits that are set
320/// in its \c maskVal parameter.
321///
322/// \see McciArm_putRegMasked
323///
324__attribute__((__always_inline__))
325static inline uint32_t
326McciArm_putRegClearSet(uint32_t reg, uint32_t clearVal, uint32_t setVal)
327 {
328 uint32_t const rValue = McciArm_getReg(reg);
329
330 return McciArm_putReg(
331 reg,
332 (rValue & ~clearVal) | setVal
333 );
334 }
335
336///
337/// \brief store to cm0plus register under mask
338///
339/// \param [in] reg register to be modified
340/// \param [in] maskVal mask of bits to be modifed
341/// \param [in] modVal where \p maskVal is 1, provides values of bits
342///
343/// \note this is subtly different than \ref McciArm_putRegClearSet,
344/// in that any bits in \b ~maskVal are not changed, regardless of
345/// corresponding bits in \p modVal.
346///
347/// \see McciArm_putRegClearSet
348/// \see https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
349///
350__attribute__((__always_inline__))
351static inline uint32_t
352McciArm_putRegMasked(uint32_t reg, uint32_t maskVal, uint32_t modVal)
353 {
354 uint32_t const rValue = McciArm_getReg(reg);
355
356 return McciArm_putReg(
357 reg,
358 rValue ^ ((rValue ^ modVal) & maskVal)
359 /* same as (rValue & ~maskVal) | (modVal & maskVal) */
360 );
361 }
362
363/****************************************************************************\
364|
365| ARM intrinsics (some of then)
366|
367\****************************************************************************/
368
369#if defined(__GNUC__) // GCC or clang, likely
370
371///
372/// \brief set main stack pointer
373///
374/// \param[in] stack new stack pointer value.
375///
376/// \note This always must be inline because once stack pointer changes,
377/// maybe hard to return!
378///
379__attribute__((__always_inline__)) static inline
380void
381McciArm_setMSP(
382 uint32_t stack
383 )
384 {
385 __asm volatile ("MSR msp,%0\n" :: "r"(stack): );
386 }
387
388///
389/// \brief get priority mask
390///
391/// \return current value of PRIMASK register
392///
393/// \note only bit 0 is implemented on CM0 Plus CPUs. If cleared, it enables
394/// interrupts; if set it enables interrupts.
395///
396__attribute__((__always_inline__)) static inline
397uint32_t
398McciArm_getPRIMASK(
399 void
400 )
401 {
402 uint32_t primask;
403
404 __asm volatile ("MRS %0,primask" : "=r"(primask));
405 return primask;
406 }
407
408///
409/// \brief set priority mask
410///
411/// \param [in] primask new value of PRIMASK register
412///
413/// \note only bit 0 is implemented on CM0 Plus CPUs. If cleared, it enables
414/// interrupts; if set it enables interrupts.
415///
416__attribute__((__always_inline__)) static inline
417void
418McciArm_setPRIMASK(
419 uint32_t primask
420 )
421 {
422 __asm volatile ("MSR primask,%0" :: "r"(primask) : "memory");
423 }
424
425///
426/// \brief Disable interrupts and return previous state
427///
428/// \return previous value of PRIMASK register.
429///
430__attribute__((__always_inline__)) static inline
431uint32_t
432McciArm_disableInterrupts(
433 void
434 )
435 {
436 uint32_t const primask = McciArm_getPRIMASK();
437 __asm volatile ("cpsid i" ::: "memory");
438 return primask;
439 }
440
441///
442/// \brief insert a data synchronization barrier
443///
444/// \details
445/// Force all pending memory operations to complete before
446// continuing.
447///
448__attribute__((always_inline)) static inline
449void McciArm_DataSynchBarrier(
450 void
451 )
452 {
453 __asm volatile ("dsb 0xF" ::: "memory");
454 }
455
456#else
457# error "Compiler not supported"
458#endif
459
460/****************************************************************************\
461|
462| Vectors and so forth
463|
464\****************************************************************************/
465
466///
467/// \brief application entry contents
468///
469/// Every Cortex M0 application begins with two DWORDs. The first is
470/// the stack pointer; the second is the program counter.
471///
472/// We use MCCI Russian Doll structure nesting; this is the root
473/// of the hierarchy that forms the page zero vectors.
474///
475typedef struct Mcci_CortexAppEntryContents_s
476 {
477 uint32_t stack; //< Initial stack pointer must be multiple of 4
478 uint32_t entry; //< Initial entry point; must be odd.
480
481///
482/// \brief application entry object
483///
484/// This union wraps the app entry contents, so that we can always reference
485/// with a consistent name (`AppEntry.stack` etc.), regardless of how general
486/// or specific the pointer is.
487///
488typedef union Mcci_CortexAppEntry_u
489 {
490 Mcci_CortexAppEntryContents_t CortexAppEntry; //< reference name for application entry view.
492
493///
494/// \brief Cortex M0 interrupt vectors (low level view)
495///
496/// This structure represents the vectors page as an aray of 96 32-bit vectors.
497/// It's used mostly for initialization and for building up larger structures.
498///
499typedef struct Mcci_CortexVectorsContents_s
500 {
501 uint32_t vectors[192/4];
503
504///
505/// \brief Cortex M0 interrupt vector object
506///
507/// This union wraps the interrupt vector contents, both so we can always
508/// reference fields with consistent names (`AppEntry.stack` etc.), and to allow
509/// us to view the vectors as either an AppEntry description or a table of
510/// vectors.
511///
512typedef union Mcci_CortexVectors_u
513 {
514 Mcci_CortexAppEntryContents_t CortexAppEntry; //< View instance as a CortexM0 AppEntry.
515 Mcci_CortexAppEntry_t CortexAppEntryCast; //< Downcast to an AppEntry without explicit casting
516 Mcci_CortexVectorsContents_t CortexVectors; //< View instance as vectors.
518
519/****************************************************************************\
520|
521| End of file
522|
523\****************************************************************************/
524
525#ifdef __cplusplus
526}
527#endif
528
529#endif /* _mcci_arm_cm0plus_h_ */
static uint32_t McciArm_putRegOr(uint32_t reg, uint32_t orVal)
or 32-bit values to a cm0plus register
static uint32_t McciArm_getReg(uint32_t reg)
read a 32-bit value from a cm0plus register
static uint32_t McciArm_putReg(uint32_t reg, uint32_t val)
write a 32-bit value to a cm0plus register
#define MCCI_CM0PLUS_SCB_SHPR2
static uint32_t McciArm_putRegClear(uint32_t reg, uint32_t clearVal)
clear out 32-bit values to a cm0plus register
static uint32_t McciArm_putRegClearSet(uint32_t reg, uint32_t clearVal, uint32_t setVal)
clear and set 32-bit values to a cm0plus register
static uint32_t McciCm0Plus_SCB_SHPR_getRegister(uint32_t handlerIndex)
return register for a given handler index
static uint32_t McciArm_putRegMasked(uint32_t reg, uint32_t maskVal, uint32_t modVal)
store to cm0plus register under mask
static uint32_t McciArm_putRegAndOr(uint32_t reg, uint32_t andVal, uint32_t orVal)
and/or 32-bit values to a cm0plus register
static uint32_t McciCm0Plus_SCB_SHPR_getMask(uint32_t handlerIndex)
return byte mask for a given handler index
application entry contents
uint32_t entry
uint32_t stack
Cortex M0 interrupt vectors (low level view)
application entry object
Mcci_CortexAppEntryContents_t CortexAppEntry
Cortex M0 interrupt vector object.
Mcci_CortexAppEntry_t CortexAppEntryCast
Mcci_CortexVectorsContents_t CortexVectors
Mcci_CortexAppEntryContents_t CortexAppEntry