summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2012-01-25 21:47:20 +0000
committerVincent Palatin <vpalatin@chromium.org>2012-01-25 22:50:07 +0000
commitcf9fcef328900ae4460755cca01ec46e98b01732 (patch)
tree19e56762b6daa2b3abb2a2d2235d72dd417b3ed3 /core
parent645dad5d3f658d7c5e0d54453964e91afe7b43c0 (diff)
downloadchrome-ec-cf9fcef328900ae4460755cca01ec46e98b01732.tar.gz
Move OS files to a CPU specific directory
Preparatory work to introduce a second SoC : 3/5 We split the drivers files which contain SoC specific drivers from the OS files which only depend the actual CPU core. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BUG=None TEST=run EC firmware on BDS and test a few commands on the console. Change-Id: I598f8b23e074da9bd6b0e2ce6689c1075fe854f0
Diffstat (limited to 'core')
-rw-r--r--core/cortex-m/build.mk11
-rw-r--r--core/cortex-m/ec.lds.S63
-rw-r--r--core/cortex-m/init.S378
-rw-r--r--core/cortex-m/panic.S111
-rw-r--r--core/cortex-m/switch.S63
-rw-r--r--core/cortex-m/task.c394
-rw-r--r--core/cortex-m/timer.c206
7 files changed, 1226 insertions, 0 deletions
diff --git a/core/cortex-m/build.mk b/core/cortex-m/build.mk
new file mode 100644
index 0000000000..8da6792154
--- /dev/null
+++ b/core/cortex-m/build.mk
@@ -0,0 +1,11 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Cortex-M4 core OS files build
+#
+
+# CPU specific compilation flags
+CFLAGS_CPU=-mcpu=cortex-m4 -mthumb -Os -mno-sched-prolog
+
+core-y=init.o panic.o switch.o task.o timer.o
diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S
new file mode 100644
index 0000000000..35006ae77f
--- /dev/null
+++ b/core/cortex-m/ec.lds.S
@@ -0,0 +1,63 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "config.h"
+
+#define CONFIG_FW_SECT_OFF(section) CONFIG_FW_##section##_OFF
+#define CONFIG_FW_BASE(section) (CONFIG_FLASH_BASE + CONFIG_FW_SECT_OFF(section))
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(reset)
+MEMORY
+{
+ FLASH (rx) : ORIGIN = CONFIG_FW_BASE(SECTION), LENGTH = CONFIG_FW_IMAGE_SIZE
+ IRAM (rw) : ORIGIN = CONFIG_RAM_BASE, LENGTH = CONFIG_RAM_SIZE
+}
+SECTIONS
+{
+ .text : {
+ OUTDIR/core/CORE/init.o (.text)
+ *(.text*)
+#ifdef COMPILE_FOR_RAM
+ } > IRAM
+#else
+ } > FLASH
+#endif
+ . = ALIGN(4);
+ .rodata : {
+ __irqprio = .;
+ *(.rodata.irqprio)
+ __irqprio_end = .;
+ . = ALIGN(4);
+ __cmds = .;
+ *(.rodata.cmds)
+ __cmds_end = .;
+ *(.rodata*)
+ . = ALIGN(4);
+#ifdef COMPILE_FOR_RAM
+ } > IRAM
+ __ro_end = . ;
+ .data : {
+#else
+ } > FLASH
+ __ro_end = . ;
+ .data : AT(ADDR(.rodata) + SIZEOF(.rodata)) {
+#endif
+ . = ALIGN(4);
+ __data_start = .;
+ *(.data.tasks)
+ *(.data)
+ . = ALIGN(4);
+ __data_end = .;
+ } > IRAM
+ .bss : {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss)
+ . = ALIGN(4);
+ __bss_end = .;
+ } > IRAM
+ /DISCARD/ : { *(.ARM.*) }
+}
diff --git a/core/cortex-m/init.S b/core/cortex-m/init.S
new file mode 100644
index 0000000000..6e3f3489e6
--- /dev/null
+++ b/core/cortex-m/init.S
@@ -0,0 +1,378 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Cortex-M CPU initialization
+ */
+
+#include "config.h"
+
+.text
+
+.syntax unified
+.code 16
+
+.macro vector name
+.long \name\()_handler
+.weak \name\()_handler
+.set \name\()_handler, default_handler
+.endm
+
+.macro vector_irq number
+.if \number < CONFIG_IRQ_COUNT
+vector irq_\()\number
+.endif
+.endm
+
+/* Exceptions vector */
+vectors:
+.long stack_end @ initial stack pointer
+.long reset @ reset handler
+vector nmi @ NMI handler
+vector hard_fault @ HardFault handler
+vector mpu_fault @ MPU fault handler
+vector bus_fault @ Bus fault handler
+vector usage_fault @ Usage fault handler
+.long 0 @ reserved
+.long 0 @ reserved
+.long 0 @ reserved
+.long 0 @ reserved
+vector svc @ SWI
+vector debug @ Debug handler
+.long 0 @ reserved
+vector pendsv @ PendSV handler
+vector sys_tick @ SysTick handler
+vector_irq 0 @ IRQ 0 handler
+vector_irq 1 @ IRQ 1 handler
+vector_irq 2 @ IRQ 2 handler
+vector_irq 3 @ IRQ 3 handler
+vector_irq 4 @ IRQ 4 handler
+vector_irq 5 @ IRQ 5 handler
+vector_irq 6 @ IRQ 6 handler
+vector_irq 7 @ IRQ 7 handler
+vector_irq 8 @ IRQ 8 handler
+vector_irq 9 @ IRQ 9 handler
+vector_irq 10 @ IRQ 10 handler
+vector_irq 11 @ IRQ 11 handler
+vector_irq 12 @ IRQ 12 handler
+vector_irq 13 @ IRQ 13 handler
+vector_irq 14 @ IRQ 14 handler
+vector_irq 15 @ IRQ 15 handler
+vector_irq 16 @ IRQ 16 handler
+vector_irq 17 @ IRQ 17 handler
+vector_irq 18 @ IRQ 18 handler
+vector_irq 19 @ IRQ 19 handler
+vector_irq 20 @ IRQ 20 handler
+vector_irq 21 @ IRQ 21 handler
+vector_irq 22 @ IRQ 22 handler
+vector_irq 23 @ IRQ 23 handler
+vector_irq 24 @ IRQ 24 handler
+vector_irq 25 @ IRQ 25 handler
+vector_irq 26 @ IRQ 26 handler
+vector_irq 27 @ IRQ 27 handler
+vector_irq 28 @ IRQ 28 handler
+vector_irq 29 @ IRQ 29 handler
+vector_irq 30 @ IRQ 30 handler
+vector_irq 31 @ IRQ 31 handler
+vector_irq 32 @ IRQ 32 handler
+vector_irq 33 @ IRQ 33 handler
+vector_irq 34 @ IRQ 34 handler
+vector_irq 35 @ IRQ 35 handler
+vector_irq 36 @ IRQ 36 handler
+vector_irq 37 @ IRQ 37 handler
+vector_irq 38 @ IRQ 38 handler
+vector_irq 39 @ IRQ 39 handler
+vector_irq 40 @ IRQ 40 handler
+vector_irq 41 @ IRQ 41 handler
+vector_irq 42 @ IRQ 42 handler
+vector_irq 43 @ IRQ 43 handler
+vector_irq 44 @ IRQ 44 handler
+vector_irq 45 @ IRQ 45 handler
+vector_irq 46 @ IRQ 46 handler
+vector_irq 47 @ IRQ 47 handler
+vector_irq 48 @ IRQ 48 handler
+vector_irq 49 @ IRQ 49 handler
+vector_irq 50 @ IRQ 50 handler
+vector_irq 51 @ IRQ 51 handler
+vector_irq 52 @ IRQ 52 handler
+vector_irq 53 @ IRQ 53 handler
+vector_irq 54 @ IRQ 54 handler
+vector_irq 55 @ IRQ 55 handler
+vector_irq 56 @ IRQ 56 handler
+vector_irq 57 @ IRQ 57 handler
+vector_irq 58 @ IRQ 58 handler
+vector_irq 59 @ IRQ 59 handler
+vector_irq 60 @ IRQ 60 handler
+vector_irq 61 @ IRQ 61 handler
+vector_irq 62 @ IRQ 62 handler
+vector_irq 63 @ IRQ 63 handler
+vector_irq 64 @ IRQ 64 handler
+vector_irq 65 @ IRQ 65 handler
+vector_irq 66 @ IRQ 66 handler
+vector_irq 67 @ IRQ 67 handler
+vector_irq 68 @ IRQ 68 handler
+vector_irq 69 @ IRQ 69 handler
+vector_irq 70 @ IRQ 70 handler
+vector_irq 71 @ IRQ 71 handler
+vector_irq 72 @ IRQ 72 handler
+vector_irq 73 @ IRQ 73 handler
+vector_irq 74 @ IRQ 74 handler
+vector_irq 75 @ IRQ 75 handler
+vector_irq 76 @ IRQ 76 handler
+vector_irq 77 @ IRQ 77 handler
+vector_irq 78 @ IRQ 78 handler
+vector_irq 79 @ IRQ 79 handler
+vector_irq 80 @ IRQ 80 handler
+vector_irq 81 @ IRQ 81 handler
+vector_irq 82 @ IRQ 82 handler
+vector_irq 83 @ IRQ 83 handler
+vector_irq 84 @ IRQ 84 handler
+vector_irq 85 @ IRQ 85 handler
+vector_irq 86 @ IRQ 86 handler
+vector_irq 87 @ IRQ 87 handler
+vector_irq 88 @ IRQ 88 handler
+vector_irq 89 @ IRQ 89 handler
+vector_irq 90 @ IRQ 90 handler
+vector_irq 91 @ IRQ 91 handler
+vector_irq 92 @ IRQ 92 handler
+vector_irq 93 @ IRQ 93 handler
+vector_irq 94 @ IRQ 94 handler
+vector_irq 95 @ IRQ 95 handler
+vector_irq 96 @ IRQ 96 handler
+vector_irq 97 @ IRQ 97 handler
+vector_irq 98 @ IRQ 98 handler
+vector_irq 99 @ IRQ 99 handler
+vector_irq 100 @ IRQ 100 handler
+vector_irq 101 @ IRQ 101 handler
+vector_irq 102 @ IRQ 102 handler
+vector_irq 103 @ IRQ 103 handler
+vector_irq 104 @ IRQ 104 handler
+vector_irq 105 @ IRQ 105 handler
+vector_irq 106 @ IRQ 106 handler
+vector_irq 107 @ IRQ 107 handler
+vector_irq 108 @ IRQ 108 handler
+vector_irq 109 @ IRQ 109 handler
+vector_irq 110 @ IRQ 110 handler
+vector_irq 111 @ IRQ 111 handler
+vector_irq 112 @ IRQ 112 handler
+vector_irq 113 @ IRQ 113 handler
+vector_irq 114 @ IRQ 114 handler
+vector_irq 115 @ IRQ 115 handler
+vector_irq 116 @ IRQ 116 handler
+vector_irq 117 @ IRQ 117 handler
+vector_irq 118 @ IRQ 118 handler
+vector_irq 119 @ IRQ 119 handler
+vector_irq 120 @ IRQ 120 handler
+vector_irq 121 @ IRQ 121 handler
+vector_irq 122 @ IRQ 122 handler
+vector_irq 123 @ IRQ 123 handler
+vector_irq 124 @ IRQ 124 handler
+vector_irq 125 @ IRQ 125 handler
+vector_irq 126 @ IRQ 126 handler
+vector_irq 127 @ IRQ 127 handler
+vector_irq 128 @ IRQ 128 handler
+vector_irq 129 @ IRQ 129 handler
+vector_irq 130 @ IRQ 130 handler
+vector_irq 131 @ IRQ 131 handler
+vector_irq 132 @ IRQ 132 handler
+vector_irq 133 @ IRQ 133 handler
+vector_irq 134 @ IRQ 134 handler
+vector_irq 135 @ IRQ 135 handler
+vector_irq 136 @ IRQ 136 handler
+vector_irq 137 @ IRQ 137 handler
+vector_irq 138 @ IRQ 138 handler
+vector_irq 139 @ IRQ 139 handler
+vector_irq 140 @ IRQ 140 handler
+vector_irq 141 @ IRQ 141 handler
+vector_irq 142 @ IRQ 142 handler
+vector_irq 143 @ IRQ 143 handler
+vector_irq 144 @ IRQ 144 handler
+vector_irq 145 @ IRQ 145 handler
+vector_irq 146 @ IRQ 146 handler
+vector_irq 147 @ IRQ 147 handler
+vector_irq 148 @ IRQ 148 handler
+vector_irq 149 @ IRQ 149 handler
+vector_irq 150 @ IRQ 150 handler
+vector_irq 151 @ IRQ 151 handler
+vector_irq 152 @ IRQ 152 handler
+vector_irq 153 @ IRQ 153 handler
+vector_irq 154 @ IRQ 154 handler
+vector_irq 155 @ IRQ 155 handler
+vector_irq 156 @ IRQ 156 handler
+vector_irq 157 @ IRQ 157 handler
+vector_irq 158 @ IRQ 158 handler
+vector_irq 159 @ IRQ 159 handler
+vector_irq 160 @ IRQ 160 handler
+vector_irq 161 @ IRQ 161 handler
+vector_irq 162 @ IRQ 162 handler
+vector_irq 163 @ IRQ 163 handler
+vector_irq 164 @ IRQ 164 handler
+vector_irq 165 @ IRQ 165 handler
+vector_irq 166 @ IRQ 166 handler
+vector_irq 167 @ IRQ 167 handler
+vector_irq 168 @ IRQ 168 handler
+vector_irq 169 @ IRQ 169 handler
+vector_irq 170 @ IRQ 170 handler
+vector_irq 171 @ IRQ 171 handler
+vector_irq 172 @ IRQ 172 handler
+vector_irq 173 @ IRQ 173 handler
+vector_irq 174 @ IRQ 174 handler
+vector_irq 175 @ IRQ 175 handler
+vector_irq 176 @ IRQ 176 handler
+vector_irq 177 @ IRQ 177 handler
+vector_irq 178 @ IRQ 178 handler
+vector_irq 179 @ IRQ 179 handler
+vector_irq 180 @ IRQ 180 handler
+vector_irq 181 @ IRQ 181 handler
+vector_irq 182 @ IRQ 182 handler
+vector_irq 183 @ IRQ 183 handler
+vector_irq 184 @ IRQ 184 handler
+vector_irq 185 @ IRQ 185 handler
+vector_irq 186 @ IRQ 186 handler
+vector_irq 187 @ IRQ 187 handler
+vector_irq 188 @ IRQ 188 handler
+vector_irq 189 @ IRQ 189 handler
+vector_irq 190 @ IRQ 190 handler
+vector_irq 191 @ IRQ 191 handler
+vector_irq 192 @ IRQ 192 handler
+vector_irq 193 @ IRQ 193 handler
+vector_irq 194 @ IRQ 194 handler
+vector_irq 195 @ IRQ 195 handler
+vector_irq 196 @ IRQ 196 handler
+vector_irq 197 @ IRQ 197 handler
+vector_irq 198 @ IRQ 198 handler
+vector_irq 199 @ IRQ 199 handler
+vector_irq 200 @ IRQ 200 handler
+vector_irq 201 @ IRQ 201 handler
+vector_irq 202 @ IRQ 202 handler
+vector_irq 203 @ IRQ 203 handler
+vector_irq 204 @ IRQ 204 handler
+vector_irq 205 @ IRQ 205 handler
+vector_irq 206 @ IRQ 206 handler
+vector_irq 207 @ IRQ 207 handler
+vector_irq 208 @ IRQ 208 handler
+vector_irq 209 @ IRQ 209 handler
+vector_irq 210 @ IRQ 210 handler
+vector_irq 211 @ IRQ 211 handler
+vector_irq 212 @ IRQ 212 handler
+vector_irq 213 @ IRQ 213 handler
+vector_irq 214 @ IRQ 214 handler
+vector_irq 215 @ IRQ 215 handler
+vector_irq 216 @ IRQ 216 handler
+vector_irq 217 @ IRQ 217 handler
+vector_irq 218 @ IRQ 218 handler
+vector_irq 219 @ IRQ 219 handler
+vector_irq 220 @ IRQ 220 handler
+vector_irq 221 @ IRQ 221 handler
+vector_irq 222 @ IRQ 222 handler
+vector_irq 223 @ IRQ 223 handler
+vector_irq 224 @ IRQ 224 handler
+vector_irq 225 @ IRQ 225 handler
+vector_irq 226 @ IRQ 226 handler
+vector_irq 227 @ IRQ 227 handler
+vector_irq 228 @ IRQ 228 handler
+vector_irq 229 @ IRQ 229 handler
+vector_irq 230 @ IRQ 230 handler
+vector_irq 231 @ IRQ 231 handler
+vector_irq 232 @ IRQ 232 handler
+vector_irq 233 @ IRQ 233 handler
+vector_irq 234 @ IRQ 234 handler
+vector_irq 235 @ IRQ 235 handler
+vector_irq 236 @ IRQ 236 handler
+vector_irq 237 @ IRQ 237 handler
+vector_irq 238 @ IRQ 238 handler
+vector_irq 239 @ IRQ 239 handler
+vector_irq 240 @ IRQ 240 handler
+vector_irq 241 @ IRQ 241 handler
+vector_irq 242 @ IRQ 242 handler
+vector_irq 243 @ IRQ 243 handler
+vector_irq 244 @ IRQ 244 handler
+vector_irq 245 @ IRQ 245 handler
+vector_irq 246 @ IRQ 246 handler
+vector_irq 247 @ IRQ 247 handler
+vector_irq 248 @ IRQ 248 handler
+vector_irq 249 @ IRQ 249 handler
+vector_irq 250 @ IRQ 250 handler
+vector_irq 251 @ IRQ 251 handler
+vector_irq 252 @ IRQ 252 handler
+vector_irq 253 @ IRQ 253 handler
+vector_irq 254 @ IRQ 254 handler
+
+.global reset
+.thumb_func
+reset:
+ /* set the vector table on our current code */
+ adr r1, vectors
+ ldr r2, =0xE000ED08 /* VTABLE register in SCB*/
+ str r1, [r2]
+ /* Clear BSS */
+ mov r0, #0
+ ldr r1,_bss_start
+ ldr r2,_bss_end
+bss_loop:
+ cmp r1, r2
+ it lt
+ strlt r0, [r1], #4
+ blt bss_loop
+
+#ifndef COMPILE_FOR_RAM
+ /* Copy initialized data to Internal RAM */
+ ldr r0,_ro_end
+ ldr r1,_data_start
+ ldr r2,_data_end
+data_loop:
+ ldr r3, [r0], #4
+ cmp r1, r2
+ it lt
+ strlt r3, [r1], #4
+ blt data_loop
+#endif
+
+ /**
+ * Set stack pointer
+ * already done my Cortex-M hardware but this allows software to
+ * jump directly to reset function or to run on other ARM
+ */
+ ldr r0, =stack_end
+ mov sp, r0
+
+ /* jump to C code */
+ bl main
+ /* we should not return here */
+ /* TODO check error code ? */
+fini_loop:
+ b fini_loop
+
+/* default exception handler */
+.thumb_func
+default_handler:
+ b panic
+
+_bss_start:
+ .long __bss_start
+_bss_end:
+ .long __bss_end
+_data_start:
+ .long __data_start
+_data_end:
+ .long __data_end
+_ro_end:
+ .long __ro_end
+
+/* Dummy functions to avoid linker complaints */
+.global __aeabi_unwind_cpp_pr0
+.global __aeabi_unwind_cpp_pr1
+.global __aeabi_unwind_cpp_pr2
+__aeabi_unwind_cpp_pr0:
+__aeabi_unwind_cpp_pr1:
+__aeabi_unwind_cpp_pr2:
+ bx lr
+
+.section .bss
+
+/* Reserve space for system stack */
+stack_start:
+ .space CONFIG_STACK_SIZE, 0
+stack_end:
+ .globl stack_end
+
diff --git a/core/cortex-m/panic.S b/core/cortex-m/panic.S
new file mode 100644
index 0000000000..4c87cac511
--- /dev/null
+++ b/core/cortex-m/panic.S
@@ -0,0 +1,111 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Fatal exception handling and debug tracing
+ */
+
+#include "config.h"
+
+.text
+
+.syntax unified
+.code 16
+
+.macro hex_reg r, offset @ prepare to build
+ add r1, r3, #\offset @ .. hexadecimal string
+ mov r0, \r @ .. from the reg value
+ bl buildhex
+.endm
+
+/* fatal exception handler */
+.global panic
+.thumb_func
+panic:
+#ifndef CONFIG_DEBUG
+ b EcSystemReset @ Reboot the system
+#else /* CONFIG_DEBUG */
+ /* check that the exception stack pointer is valid */
+ ldr r0, =CONFIG_RAM_BASE @ start of RAM
+ ldr r1, =CONFIG_RAM_BASE+CONFIG_RAM_SIZE @ end of RAM
+ mrs r12, psp @ process stack pointer
+ cmp r12, r0 @ is sp >= RAM start ?
+ it ge
+ cmpge r1, r12 @ is sp < RAM end ?
+ blt panic_print @ no => no values to read
+ /* output registers value */
+ ldr r3, =msg_excep @ pointer to the text buffer
+ mrs r2, ipsr @ get exception num from IPSR
+ bfc r2, #9, #23 @ the exception is the 3 LSB
+ hex_reg r2, 18 @ prepare hexa for excep number
+ hex_reg r4, 119 @ prepare hexa for R4
+ hex_reg r5, 132 @ prepare hexa for R5
+ hex_reg r6, 145 @ prepare hexa for R6
+ hex_reg r7, 156 @ prepare hexa for R7
+ hex_reg r8, 171 @ prepare hexa for R8
+ hex_reg r9, 184 @ prepare hexa for R9
+ hex_reg r10, 197 @ prepare hexa for R10
+ hex_reg r11, 210 @ prepare hexa for R11
+ ldmia r12!, {r4-r11} @ load saved r0-r3,r12,lr,pc,psr
+ hex_reg r4, 66 @ prepare hexa for R0
+ hex_reg r5, 79 @ prepare hexa for R1
+ hex_reg r6, 92 @ prepare hexa for R2
+ hex_reg r7, 105 @ prepare hexa for R3
+ hex_reg r8, 225 @ prepare hexa for R12
+ hex_reg r12, 238 @ prepare hexa for SP
+ hex_reg r9, 251 @ prepare hexa for LR
+ hex_reg r10, 264 @ prepare hexa for PC
+ hex_reg r11, 40 @ prepare hexa for xPSR
+ /* print exception trace */
+panic_print:
+ ldr r0, =msg_excep @ pointer to the text buffer
+ bl emergency_puts @ print the banner
+ b system_reset @ Reboot the system
+
+/* Helpers for exception trace */
+/* print a string on the UART
+ * r0: asciiZ string pointer
+ */
+emergency_puts:
+ ldr r1, =0x4000c000 @ UART0 first register
+1:
+ ldrb r3, [r0], #1 @ read one character
+ cmp r3, #0 @ end of the string ?
+ beq 3f @ if yes, return
+2: /* putchar */
+ ldr r2, [r1, #0x18] @ read LM4_UART0_UARTFR
+ tst r2, #0x20 @ TX FIFO full ?
+ bne 2b @ if yes, wait
+ str r3, [r1] @ send character to UART DR
+ b 1b @ goto next character
+3: /* flush */
+ ldr r2, [r1, #0x18] @ read LM4_UART0_UARTFR
+ tst r2, #0x8 @ TX on-going ?
+ bne 3b @ if yes, wait
+ bx lr
+
+/* write a number in hexadecimal in a text buffer
+ * r0: number to print
+ * r1: pointer to *end* of the buffer (filled with '0')
+ */
+buildhex:
+ cmp r0, #0
+ it eq
+ bxeq lr
+ and r2, r0, #0xf
+ cmp r2, #10
+ ite lt
+ addlt r2, #'0'
+ addge r2, #'A'-10
+ strb r2, [r1],#-1
+ lsr r0, #4
+ b buildhex
+
+.data
+msg_excep: .ascii "\r\n=== EXCEPTION: 00 ====== xPSR: 00000000 ===========\r\n"
+msg_reg0: .ascii "R0 :00000000 R1 :00000000 R2 :00000000 R3 :00000000\r\n"
+msg_reg1: .ascii "R4 :00000000 R5 :00000000 R6 :00000000 R7 :00000000\r\n"
+msg_reg2: .ascii "R8 :00000000 R9 :00000000 R10:00000000 R11:00000000\r\n"
+msg_reg3: .ascii "R12:00000000 SP :00000000 LR :00000000 PC :00000000\r\n\0"
+.align 4
+#endif /* CONFIG_DEBUG */
diff --git a/core/cortex-m/switch.S b/core/cortex-m/switch.S
new file mode 100644
index 0000000000..4d974251cd
--- /dev/null
+++ b/core/cortex-m/switch.S
@@ -0,0 +1,63 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Context swtching
+ */
+
+#include "config.h"
+
+.text
+
+.syntax unified
+.code 16
+
+/**
+ * Task context switching
+ *
+ * Change the task scheduled after returning from the exception.
+ *
+ * Save the registers of the current task below the exception context on
+ * its task, then restore the live registers of the next task and set the
+ * process stack pointer to the new stack.
+ *
+ * r0: pointer to the task to switch from
+ * r1: pointer to the task to switch to
+ *
+ * must be called from interrupt context
+ *
+ * the structure of tje saved context on the stack is :
+ * r0, r1, r2, r3, r12, lr, pc, psr, r4, r5, r6, r7, r8, r9, r10, r11
+ * exception frame <|> additional registers
+ */
+.global __switchto
+.thumb_func
+__switchto:
+ mrs r3, psp @ get the task stack where the context has been saved
+ ldr r2, [r1] @ get the new scheduled task stack pointer
+ stmdb r3!, {r4-r11} @ save additional r4-r7 in the task stack
+ ldmia r2!, {r4-r11} @ restore r4-r7 for the next task context
+ str r3, [r0] @ save the task stack pointer in its context
+ msr psp, r2 @ set the process stack pointer to exception context
+ bx lr @ return from exception
+
+/**
+ * Start the task scheduling
+ */
+.global task_start
+.thumb_func
+task_start:
+ ldr r2,=scratchpad @ area used as dummy thread stack for the first switch
+ mov r3, #2
+ mov r0, #0 @ __Schedule parameter : de-schedule nothing
+ mov r1, #0 @ __Schedule parameter : re-schedule nothing
+ add r2, #17*4 @ put the pointer at the top of the stack
+ msr psp, r2 @ setup a thread stack up to the first context switch
+ isb @ ensure the write is done
+ msr control, r3 @ use : priv. mode / thread stack / no floating point
+ isb @ ensure the write is done
+ bl __schedule @ execute the task with the highest priority
+ /* we should never return here */
+ mov r0, #1 @ set to EC_ERROR_UNKNOWN
+ bx lr
+
diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c
new file mode 100644
index 0000000000..2e0821e80f
--- /dev/null
+++ b/core/cortex-m/task.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Task scheduling / events module for Chrome EC operating system */
+
+#include <stdint.h>
+
+#include "config.h"
+#include "atomic.h"
+#include "console.h"
+#include "task.h"
+#include "timer.h"
+#include "uart.h"
+#include "registers.h"
+#include "util.h"
+
+/**
+ * Global memory size for a task : 512 bytes
+ * including its contexts and its stack
+ */
+#define TASK_SIZE_LOG2 9
+#define TASK_SIZE (1<<TASK_SIZE_LOG2)
+
+typedef union {
+ struct {
+ uint32_t sp; /* saved stack pointer for context switch */
+ uint32_t events; /* bitmaps of received events */
+ uint8_t stack[0]; /* task stack */
+ };
+ uint32_t context[TASK_SIZE/4];
+} task_;
+
+/* declare task routine prototypes */
+#define TASK(n, r, d) int r(void *);
+#include TASK_LIST
+void __idle(void);
+CONFIG_TASK_LIST
+#undef TASK
+
+
+extern void __switchto(task_ *from, task_ *to);
+
+
+/* declare and fill the contexts for all the tasks */
+#define TASK(n, r, d) { \
+ .context[0] = (uint32_t)(tasks + TASK_ID_##n + 1) - 64, \
+ .context[TASK_SIZE/4 - 8/*r0*/] = (uint32_t)d, \
+ /* TODO set a LR to a trap */ \
+ .context[TASK_SIZE/4 - 2/*pc*/] = (uint32_t)r, \
+ .context[TASK_SIZE/4 - 1/*psr*/] = 0x01000000 },
+#include TASK_LIST
+static task_ tasks[] __attribute__((section(".data.tasks")))
+ __attribute__((aligned(TASK_SIZE))) = {
+ TASK(IDLE, __idle, 0)
+ CONFIG_TASK_LIST
+};
+#undef TASK
+/* reserve space to discard context on first context switch */
+uint32_t scratchpad[17] __attribute__((section(".data.tasks")));
+
+/* context switch at the next exception exit if needed */
+/* TODO: who sets this back to 0 after it's set to 1? */
+static int need_resched = 0;
+
+/**
+ * bitmap of all tasks ready to be run
+ *
+ * Currently all tasks are enabled at startup.
+ */
+static unsigned tasks_ready = (1<<TASK_ID_COUNT) - 1;
+
+
+static task_ *__get_current(void)
+{
+ unsigned sp;
+
+ asm("mov %0, sp":"=r"(sp));
+ return (task_ *)((sp - 4) & ~(TASK_SIZE-1));
+}
+
+
+/**
+ * Return a pointer to the task preempted by the current exception
+ *
+ * designed to be called from interrupt context.
+ */
+static task_ *__get_task_scheduled(void)
+{
+ unsigned sp;
+
+ asm("mrs %0, psp":"=r"(sp));
+ return (task_ *)((sp - 16) & ~(TASK_SIZE-1));
+}
+
+
+static inline task_ *__task_id_to_ptr(task_id_t id)
+{
+ return tasks + id;
+}
+
+
+inline int in_interrupt_context(void)
+{
+ int ret;
+ asm("mrs %0, ipsr \n" /* read exception number */
+ "lsl %0, #23 \n":"=r"(ret)); /* exception bits are the 9 LSB */
+ return ret;
+}
+
+
+task_id_t task_get_current(void)
+{
+ task_id_t id = __get_current() - tasks;
+ if (id >= TASK_ID_COUNT)
+ id = TASK_ID_INVALID;
+
+ return id;
+}
+
+
+uint32_t *task_get_event_bitmap(task_id_t tskid)
+{
+ task_ *tsk = __task_id_to_ptr(tskid);
+ return &tsk->events;
+}
+
+
+/**
+ * scheduling system call
+ */
+void svc_handler(int desched, task_id_t resched)
+{
+ task_ *current, *next;
+ uint32_t reg;
+
+ /* push the priority to -1 until the return, to avoid being
+ * interrupted */
+ asm volatile("mov %0, #1\n"
+ "msr faultmask, %0" :"=r"(reg));
+ current = __get_task_scheduled();
+ if (desched && !current->events) {
+ /* Remove our own ready bit */
+ tasks_ready &= ~(1 << (current-tasks));
+ }
+ tasks_ready |= 1 << resched;
+
+ ASSERT(tasks_ready);
+ next = __task_id_to_ptr(31 - __builtin_clz(tasks_ready));
+
+ /* Nothing to do */
+ if (next == current)
+ return;
+
+ __switchto(current, next);
+}
+
+
+void __schedule(int desched, int resched)
+{
+ register int p0 asm("r0") = desched;
+ register int p1 asm("r1") = resched;
+ /* TODO remove hardcoded opcode
+ * SWI not compiled properly for ARMv7-M on our current chroot toolchain
+ */
+ asm(".hword 0xdf00 @swi 0"::"r"(p0),"r"(p1));
+}
+
+
+/**
+ * Change the task scheduled after returning from the exception.
+ *
+ * If task_send_msg has been called and has set need_resched flag,
+ * we re-compute which task is running and eventually swap the context
+ * saved on the process stack to restore the new one at exception exit.
+ *
+ * it must be called from interrupt context !
+ */
+void task_resched_if_needed(void *excep_return)
+{
+ /**
+ * continue iff a rescheduling event happened and
+ * we are not called from another exception
+ */
+ if (!need_resched || (((uint32_t)excep_return & 0xf) == 1))
+ return;
+
+ svc_handler(0, 0);
+}
+
+
+static uint32_t __wait_msg(int timeout_us, task_id_t resched)
+{
+ task_ *tsk = __get_current();
+ task_id_t me = tsk - tasks;
+ uint32_t evt;
+ int ret;
+
+ ASSERT(!in_interrupt_context());
+
+ if (timeout_us > 0) {
+ timestamp_t deadline = get_time();
+ deadline.val += timeout_us;
+ ret = timer_arm(deadline, me);
+ ASSERT(ret == EC_SUCCESS);
+ }
+ while (!(evt = atomic_read_clear(&tsk->events)))
+ {
+ /* Remove ourself and get the next task in the scheduler */
+ __schedule(1, resched);
+ resched = TASK_ID_IDLE;
+ }
+ if (timeout_us > 0)
+ timer_cancel(me);
+ return evt;
+}
+
+
+uint32_t task_send_msg(task_id_t tskid, task_id_t from, int wait)
+{
+ task_ *receiver = __task_id_to_ptr(tskid);
+ ASSERT(receiver);
+
+ if (from == TASK_ID_CURRENT) {
+ from = task_get_current();
+ }
+
+ /* set the event bit in the receiver message bitmap */
+ atomic_or(&receiver->events, 1 << from);
+
+ /* Re-schedule if priorities have changed */
+ if (in_interrupt_context()) {
+ /* the receiver might run again */
+ tasks_ready |= 1 << tskid;
+ need_resched = 1;
+ } else {
+ if (wait)
+ return __wait_msg(-1, tskid);
+ else
+ __schedule(0, tskid);
+ }
+
+ return 0;
+}
+
+
+uint32_t task_wait_msg(int timeout_us)
+{
+ return __wait_msg(timeout_us, TASK_ID_IDLE);
+}
+
+
+void task_enable_irq(int irq)
+{
+ LM4_NVIC_EN(irq / 32) = 1 << (irq % 32);
+}
+
+
+void task_disable_irq(int irq)
+{
+ LM4_NVIC_DIS(irq / 32) = 1 << (irq % 32);
+}
+
+
+void task_trigger_irq(int irq)
+{
+ LM4_NVIC_SWTRIG = irq;
+}
+
+
+/**
+ * Enable all used IRQ in the NVIC and set their priorities
+ * as defined by the DECLARE_IRQ statements
+ */
+static void __nvic_init_irqs(void)
+{
+ /* get the IRQ priorities section from the linker */
+ extern struct irq_priority __irqprio[];
+ extern struct irq_priority __irqprio_end[];
+ int irq_count = __irqprio_end - __irqprio;
+ int i;
+
+ for (i = 0; i < irq_count; i++) {
+ uint8_t irq = __irqprio[i].irq;
+ uint8_t prio = __irqprio[i].priority;
+ uint32_t prio_shift = irq % 4 * 8 + 5;
+ LM4_NVIC_PRI(irq / 4) =
+ (LM4_NVIC_PRI(irq / 4) &
+ ~(0x7 << prio_shift)) |
+ (prio << prio_shift);
+ }
+}
+
+
+void mutex_lock(struct mutex *mtx)
+{
+ uint32_t value;
+ uint32_t id = 1 << task_get_current();
+
+ ASSERT(id != TASK_ID_INVALID);
+ atomic_or(&mtx->waiters, id);
+
+ do {
+ /* try to get the lock (set 1 into the lock field) */
+ __asm__ __volatile__(" ldrex %0, [%1]\n"
+ " teq %0, #0\n"
+ " it eq\n"
+ " strexeq %0, %2, [%1]\n"
+ : "=&r" (value)
+ : "r" (&mtx->lock), "r" (1) : "cc");
+ if (value) {
+ /* contention on the mutex */
+ task_wait_msg(0);
+ }
+ } while (value);
+
+ atomic_clear(&mtx->waiters, id);
+}
+
+void mutex_unlock(struct mutex *mtx)
+{
+ uint32_t waiters;
+ task_ *tsk = __get_current();
+
+ __asm__ __volatile__(" ldr %0, [%2]\n"
+ " str %3, [%1]\n"
+ : "=&r" (waiters)
+ : "r" (&mtx->lock), "r" (&mtx->waiters), "r" (0)
+ : "cc");
+ while (waiters) {
+ task_id_t id = 31 - __builtin_clz(waiters);
+ /* somebody is waiting on the mutex */
+ task_send_msg(id, TASK_ID_MUTEX, 0);
+ waiters &= ~(1 << id);
+ }
+ /* Ensure no event is remaining from mutex wake-up */
+ atomic_clear(&tsk->events, 1 << TASK_ID_MUTEX);
+}
+
+
+#ifdef CONFIG_DEBUG
+
+/* store the task names for easier debugging */
+#define TASK(n, r, d) #n,
+#include TASK_LIST
+static const char * const task_names[] = {
+ "<< idle >>",
+ CONFIG_TASK_LIST
+};
+#undef TASK
+
+
+int command_task_info(int argc, char **argv)
+{
+ int i;
+
+ for (i = 0; i < TASK_ID_COUNT; i++) {
+ char is_ready = (tasks_ready & (1<<i)) ? 'R' : ' ';
+ uart_printf("%2d %c %-16s events %08x\n", i, is_ready,
+ task_names[i], tasks[i].events);
+ }
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(taskinfo, command_task_info);
+
+
+static int command_task_ready(int argc, char **argv)
+{
+ if (argc < 2) {
+ uart_printf("tasks_ready: 0x%08x\n", tasks_ready);
+ } else {
+ tasks_ready = strtoi(argv[1], NULL, 16);
+ uart_printf("Setting tasks_ready to 0x%08x\n", tasks_ready);
+ __schedule(0, 0);
+ }
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(taskready, command_task_ready);
+#endif
+
+
+int task_init(void)
+{
+ /* sanity checks about static task invariants */
+ BUILD_ASSERT(TASK_ID_COUNT <= sizeof(unsigned) * 8);
+ BUILD_ASSERT(TASK_ID_COUNT < (1 << (sizeof(task_id_t) * 8)));
+
+ /* Initialize IRQs */
+ __nvic_init_irqs();
+
+ return EC_SUCCESS;
+}
diff --git a/core/cortex-m/timer.c b/core/cortex-m/timer.c
new file mode 100644
index 0000000000..56b67a9d2f
--- /dev/null
+++ b/core/cortex-m/timer.c
@@ -0,0 +1,206 @@
+/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Timer module for Chrome EC operating system */
+
+#include <stdint.h>
+
+#include "task.h"
+#include "timer.h"
+#include "hwtimer.h"
+#include "atomic.h"
+#include "board.h"
+#include "console.h"
+#include "uart.h"
+#include "util.h"
+
+/* high word of the 64-bit timestamp counter */
+static volatile uint32_t clksrc_high;
+
+/* bitmap of currently running timers */
+static uint32_t timer_running = 0;
+
+/* deadlines of all timers */
+static timestamp_t timer_deadline[TASK_ID_COUNT];
+
+static uint32_t next_deadline = 0xffffffff;
+
+/* Hardware timer routine IRQ number */
+static int timer_irq;
+
+static void expire_timer(task_id_t tskid)
+{
+ /* we are done with this timer */
+ atomic_clear(&timer_running, 1<<tskid);
+ /* wake up the taks waiting for this timer */
+ task_send_msg(tskid, TASK_ID_TIMER, 0);
+}
+
+/**
+ * Search the next deadline and program it in the timer hardware
+ *
+ * overflow: if true, the 32-bit counter as overflowed since the last call.
+ */
+void process_timers(int overflow)
+{
+ uint32_t check_timer, running_t0;
+ timestamp_t next;
+ timestamp_t now;
+
+ if (overflow)
+ clksrc_high++;
+
+reprocess_timers:
+ next.val = 0xffffffffffffffff;
+ now = get_time();
+ do {
+ /* read atomically the current state of timer running */
+ check_timer = running_t0 = timer_running;
+ while (check_timer) {
+ int tskid = 31 - __builtin_clz(check_timer);
+
+ /* timer has expired ? */
+ if (timer_deadline[tskid].val < now.val)
+ expire_timer(tskid);
+ else if ((timer_deadline[tskid].le.hi == now.le.hi) &&
+ (timer_deadline[tskid].le.lo < next.le.lo))
+ next.val = timer_deadline[tskid].val;
+
+ check_timer &= ~(1 << tskid);
+ }
+ /* if there is a new timer, let's retry */
+ } while (timer_running & ~running_t0);
+
+ if (next.le.hi == 0xffffffff) {
+ /* no deadline to set */
+ __hw_clock_event_clear();
+ next_deadline = 0xffffffff;
+ return;
+ }
+
+ if (next.val <= get_time().val)
+ goto reprocess_timers;
+ __hw_clock_event_set(next.le.lo);
+ next_deadline = next.le.lo;
+ //TODO narrow race: deadline might have been reached before
+}
+
+void udelay(unsigned us)
+{
+ timestamp_t deadline = get_time();
+
+ deadline.val += us;
+ while (get_time().val < deadline.val) {}
+}
+
+int timer_arm(timestamp_t tstamp, task_id_t tskid)
+{
+ ASSERT(tskid < TASK_ID_COUNT);
+
+ if (timer_running & (1<<tskid))
+ return EC_ERROR_BUSY;
+
+ timer_deadline[tskid] = tstamp;
+ atomic_or(&timer_running, 1<<tskid);
+
+ /* modify the next event if needed */
+ if ((tstamp.le.hi < clksrc_high) ||
+ ((tstamp.le.hi == clksrc_high) && (tstamp.le.lo <= next_deadline)))
+ task_trigger_irq(timer_irq);
+
+ return EC_SUCCESS;
+}
+
+int timer_cancel(task_id_t tskid)
+{
+ ASSERT(tskid < TASK_ID_COUNT);
+
+ atomic_clear(&timer_running, 1<<tskid);
+ /* don't bother about canceling the interrupt:
+ * it would be slow, just do it on the next IT
+ */
+
+ return EC_SUCCESS;
+}
+
+
+void usleep(unsigned us)
+{
+ uint32_t evt = 0;
+ ASSERT(us);
+ do {
+ evt |= task_wait_msg(us);
+ } while (!(evt & (1 << TASK_ID_TIMER)));
+ /* re-queue other events which happened in the meanwhile */
+ if (evt)
+ atomic_or(task_get_event_bitmap(task_get_current()),
+ evt & ~(1 << TASK_ID_TIMER));
+}
+
+
+timestamp_t get_time(void)
+{
+ timestamp_t ts;
+ ts.le.hi = clksrc_high;
+ ts.le.lo = __hw_clock_source_read();
+ if (ts.le.hi != clksrc_high) {
+ ts.le.hi = clksrc_high;
+ ts.le.lo = __hw_clock_source_read();
+ }
+ return ts;
+}
+
+
+static int command_wait(int argc, char **argv)
+{
+ if (argc < 2)
+ return EC_ERROR_INVAL;
+
+ udelay(atoi(argv[1]) * 1000);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(waitms, command_wait);
+
+
+static int command_get_time(int argc, char **argv)
+{
+ timestamp_t ts = get_time();
+ uart_printf("Time: 0x%08x%08x us\n", ts.le.hi, ts.le.lo);
+ return EC_SUCCESS;
+
+}
+DECLARE_CONSOLE_COMMAND(gettime, command_get_time);
+
+
+int command_timer_info(int argc, char **argv)
+{
+ timestamp_t ts = get_time();
+ int tskid;
+
+ uart_printf("Time: 0x%08x%08x us\n"
+ "Deadline: 0x%08x%08x us\n"
+ "Active timers:\n",
+ ts.le.hi, ts.le.lo, clksrc_high,
+ __hw_clock_event_get());
+ for (tskid = 0; tskid < TASK_ID_COUNT; tskid++) {
+ if (timer_running & (1<<tskid))
+ uart_printf("Tsk %d tmr 0x%08x%08x\n", tskid,
+ timer_deadline[tskid].le.hi,
+ timer_deadline[tskid].le.lo);
+ }
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(timerinfo, command_timer_info);
+
+
+int timer_init(void)
+{
+ BUILD_ASSERT(TASK_ID_COUNT < sizeof(timer_running) * 8);
+
+ timer_irq = __hw_clock_source_init();
+
+ return EC_SUCCESS;
+}