1 /*
2  * Copyright (c) 2012-2015 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <lk/debug.h>
9 #include <arch.h>
10 #include <arch/ops.h>
11 #include <arch/arm.h>
12 #include <kernel/thread.h>
13 #include <kernel/debug.h>
14 #include <platform.h>
15 #include <arch/arm/cm.h>
16 #include <target.h>
17 
18 extern void *vectab;
19 
20 #if ARM_CM_DYNAMIC_PRIORITY_SIZE
21 unsigned int arm_cm_num_irq_pri_bits;
22 unsigned int arm_cm_irq_pri_mask;
23 #endif
24 
25 /* if otherwise not set externally, load the VTOR for all armv7m+ cpus.
26  * dynamic VTOR setting is optional on armv6m cores.
27  */
28 #ifndef ARM_CM_SET_VTOR
29 #if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300)
30 #define ARM_CM_SET_VTOR 1
31 #else
32 #define ARM_CM_SET_VTOR 0
33 #endif
34 #endif
35 
arch_early_init(void)36 void arch_early_init(void) {
37 
38     arch_disable_ints();
39 
40 #if ARM_CM_SET_VTOR
41     /* set the vector table base */
42     SCB->VTOR = (uint32_t)&vectab;
43 #endif
44 
45 #if (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300)
46     uint i;
47 #if ARM_CM_DYNAMIC_PRIORITY_SIZE
48     /* number of priorities */
49     for (i=0; i < 7; i++) {
50         __set_BASEPRI(1 << i);
51         if (__get_BASEPRI() != 0)
52             break;
53     }
54     arm_cm_num_irq_pri_bits = 8 - i;
55     arm_cm_irq_pri_mask = ~((1 << i) - 1) & 0xff;
56 #endif
57 
58     /* clear any pending interrupts and set all the vectors to medium priority */
59     uint groups = (SCnSCB->ICTR & 0xf) + 1;
60     for (i = 0; i < groups; i++) {
61         NVIC->ICER[i] = 0xffffffff;
62         NVIC->ICPR[i] = 0xffffffff;
63         for (uint j = 0; j < 32; j++) {
64             NVIC_SetPriority(i*32 + j, arm_cm_medium_priority());
65         }
66     }
67 
68     /* leave BASEPRI at 0 */
69     __set_BASEPRI(0);
70 
71     /* set priority grouping to 0 */
72     NVIC_SetPriorityGrouping(0);
73 
74     /* enable certain faults */
75     SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk);
76 #endif
77 
78     /* set the svc and pendsv priority level to pretty low */
79     NVIC_SetPriority(SVCall_IRQn, arm_cm_lowest_priority());
80     NVIC_SetPriority(PendSV_IRQn, arm_cm_lowest_priority());
81 
82     /* set systick and debugmonitor to medium priority */
83     NVIC_SetPriority(SysTick_IRQn, arm_cm_medium_priority());
84 
85 #if (__CORTEX_M >= 0x03)
86     NVIC_SetPriority(DebugMonitor_IRQn, arm_cm_medium_priority());
87 #endif
88 
89     /* FPU settings ------------------------------------------------------------*/
90 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
91     SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
92 #endif
93 
94 #if ARM_WITH_CACHE
95     arch_enable_cache(UCACHE);
96 #endif
97 }
98 
arch_init(void)99 void arch_init(void) {
100 #if ENABLE_CYCLE_COUNTER
101     CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
102     DWT->CYCCNT = 0;
103     DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // enable cycle counter
104 #endif
105     printf("CONTROL 0x%x\n", __get_CONTROL());
106 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
107     printf("FPSCR 0x%x\n", __get_FPSCR());
108     printf("FPCCR 0x%x\n", FPU->FPCCR);
109 #endif
110 }
111 
arch_quiesce(void)112 void arch_quiesce(void) {
113 #if ARM_WITH_CACHE
114     arch_disable_cache(UCACHE);
115 #endif
116 }
117 
arch_idle(void)118 void arch_idle(void) {
119     __asm__ volatile("wfi");
120 }
121 
122 #if     (__CORTEX_M >= 0x03) || (CORTEX_SC >= 300)
123 
_arm_cm_set_irqpri(uint32_t pri)124 void _arm_cm_set_irqpri(uint32_t pri) {
125     if (pri == 0) {
126         __disable_irq(); // cpsid i
127         __set_BASEPRI(0);
128     } else if (pri >= 256) {
129         __set_BASEPRI(0);
130         __enable_irq();
131     } else {
132         uint32_t _pri = pri & arm_cm_irq_pri_mask;
133 
134         if (_pri == 0)
135             __set_BASEPRI(1 << (8 - arm_cm_num_irq_pri_bits));
136         else
137             __set_BASEPRI(_pri);
138         __enable_irq(); // cpsie i
139     }
140 }
141 #endif
142 
143 
arm_cm_irq_entry(void)144 void arm_cm_irq_entry(void) {
145     // Set PRIMASK to 1
146     // This is so that later calls to arch_ints_disabled() returns true while we're inside the int handler
147     // Note: this will probably screw up future efforts to stack higher priority interrupts since we're setting
148     // the cpu to essentially max interrupt priority here. Will have to rethink it then.
149     __disable_irq();
150 
151     THREAD_STATS_INC(interrupts);
152     KEVLOG_IRQ_ENTER(__get_IPSR());
153 
154     target_set_debug_led(1, true);
155 }
156 
arm_cm_irq_exit(bool reschedule)157 void arm_cm_irq_exit(bool reschedule) {
158     target_set_debug_led(1, false);
159 
160     if (reschedule)
161         arm_cm_trigger_preempt();
162 
163     KEVLOG_IRQ_EXIT(__get_IPSR());
164 
165     __enable_irq(); // clear PRIMASK
166 }
167 
arch_chain_load(void * entry,ulong arg0,ulong arg1,ulong arg2,ulong arg3)168 void arch_chain_load(void *entry, ulong arg0, ulong arg1, ulong arg2, ulong arg3) {
169 #if (__CORTEX_M >= 0x03)
170 
171     uint32_t *entry_vector = (uint32_t *)entry;
172 
173     __asm__ volatile(
174         "mov r0,  %[arg0]; "
175         "mov r1,  %[arg1]; "
176         "mov r2,  %[arg2]; "
177         "mov r3,  %[arg3]; "
178         "mov sp,  %[SP]; "
179         "bx  %[entry]; "
180         :
181         : [arg0]"r"(arg0),
182         [arg1]"r"(arg1),
183         [arg2]"r"(arg2),
184         [arg3]"r"(arg3),
185         [SP]"r"(entry_vector[0]),
186         [entry]"r"(entry_vector[1])
187         : "r0", "r1", "r2", "r3"
188     );
189 
190     __UNREACHABLE;
191 #else
192     PANIC_UNIMPLEMENTED;
193 #endif
194 }
195