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