diff options
Diffstat (limited to 'core/cortex-m')
l--------- | core/cortex-m/aes.S | 1 | ||||
-rw-r--r-- | core/cortex-m/atomic.h | 41 | ||||
-rw-r--r-- | core/cortex-m/build.mk | 34 | ||||
-rw-r--r-- | core/cortex-m/cache.S | 76 | ||||
-rw-r--r-- | core/cortex-m/config_core.h | 15 | ||||
-rw-r--r-- | core/cortex-m/cpu.c | 65 | ||||
-rw-r--r-- | core/cortex-m/cpu.h | 103 | ||||
-rw-r--r-- | core/cortex-m/debug.c | 12 | ||||
-rw-r--r-- | core/cortex-m/debug.h | 37 | ||||
-rw-r--r-- | core/cortex-m/ec.lds.S | 721 | ||||
l--------- | core/cortex-m/ghash.S | 1 | ||||
-rw-r--r-- | core/cortex-m/include/fpu.h | 35 | ||||
-rw-r--r-- | core/cortex-m/include/mpu.h | 144 | ||||
-rw-r--r-- | core/cortex-m/include/mpu_private.h | 25 | ||||
-rw-r--r-- | core/cortex-m/init.S | 135 | ||||
-rw-r--r-- | core/cortex-m/irq_handler.h | 44 | ||||
l--------- | core/cortex-m/ldivmod.S | 1 | ||||
-rw-r--r-- | core/cortex-m/llsr.c | 65 | ||||
-rw-r--r-- | core/cortex-m/mpu.c | 457 | ||||
-rw-r--r-- | core/cortex-m/panic-internal.h | 11 | ||||
-rw-r--r-- | core/cortex-m/panic.c | 475 | ||||
-rw-r--r-- | core/cortex-m/switch.S | 101 | ||||
-rw-r--r-- | core/cortex-m/task.c | 1088 | ||||
l--------- | core/cortex-m/uldivmod.S | 1 | ||||
-rw-r--r-- | core/cortex-m/vecttable.c | 400 | ||||
-rw-r--r-- | core/cortex-m/watchdog.c | 58 |
26 files changed, 0 insertions, 4146 deletions
diff --git a/core/cortex-m/aes.S b/core/cortex-m/aes.S deleted file mode 120000 index 39d1286943..0000000000 --- a/core/cortex-m/aes.S +++ /dev/null @@ -1 +0,0 @@ -../../third_party/boringssl/core/cortex-m/aes.S
\ No newline at end of file diff --git a/core/cortex-m/atomic.h b/core/cortex-m/atomic.h deleted file mode 100644 index e9b96f6fd5..0000000000 --- a/core/cortex-m/atomic.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright 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. - */ - -/* Atomic operations for ARMv7 */ - -#ifndef __CROS_EC_ATOMIC_H -#define __CROS_EC_ATOMIC_H - -#include "common.h" - -typedef int atomic_t; -typedef atomic_t atomic_val_t; - -static inline atomic_val_t atomic_clear_bits(atomic_t *addr, atomic_val_t bits) -{ - return __atomic_fetch_and(addr, ~bits, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_or(atomic_t *addr, atomic_val_t bits) -{ - return __atomic_fetch_or(addr, bits, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_add(atomic_t *addr, atomic_val_t value) -{ - return __atomic_fetch_add(addr, value, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_sub(atomic_t *addr, atomic_val_t value) -{ - return __atomic_fetch_sub(addr, value, __ATOMIC_SEQ_CST); -} - -static inline atomic_val_t atomic_clear(atomic_t *addr) -{ - return __atomic_exchange_n(addr, 0, __ATOMIC_SEQ_CST); -} - -#endif /* __CROS_EC_ATOMIC_H */ diff --git a/core/cortex-m/build.mk b/core/cortex-m/build.mk deleted file mode 100644 index ad7ab6eacc..0000000000 --- a/core/cortex-m/build.mk +++ /dev/null @@ -1,34 +0,0 @@ -# -*- makefile -*- -# Copyright 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 -# - -# Use coreboot-sdk -$(call set-option,CROSS_COMPILE,\ - $(CROSS_COMPILE_arm),\ - /opt/coreboot-sdk/bin/arm-eabi-) - -# FPU compilation flags -CFLAGS_FPU-$(CONFIG_FPU)=-mfpu=fpv4-sp-d16 -mfloat-abi=hard - -# CPU specific compilation flags -CFLAGS_CPU+=-mthumb -Os -mno-sched-prolog -CFLAGS_CPU+=-mno-unaligned-access -CFLAGS_CPU+=$(CFLAGS_FPU-y) - -ifneq ($(CONFIG_LTO),) -CFLAGS_CPU+=-flto -LDFLAGS_EXTRA+=-flto -endif - -core-y=cpu.o debug.o init.o ldivmod.o llsr.o uldivmod.o vecttable.o -core-$(CONFIG_AES)+=aes.o -core-$(CONFIG_AES_GCM)+=ghash.o -core-$(CONFIG_ARMV7M_CACHE)+=cache.o -core-$(CONFIG_COMMON_PANIC_OUTPUT)+=panic.o -core-$(CONFIG_COMMON_RUNTIME)+=switch.o task.o -core-$(CONFIG_WATCHDOG)+=watchdog.o -core-$(CONFIG_MPU)+=mpu.o diff --git a/core/cortex-m/cache.S b/core/cortex-m/cache.S deleted file mode 100644 index 0a3d3bb67d..0000000000 --- a/core/cortex-m/cache.S +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright 2018 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. - * - * ARMv7-M architectural caches maintenance operations. - */ - -.syntax unified -.text -.thumb - -/* System Control Block: cache registers */ -#define SCB_CCSIDR 0xe000ed80 -#define SCB_CCSELR 0xe000ed84 -#define SCB_DCISW 0xe000ef60 -#define SCB_DCCISW 0xe000ef74 - -.macro dcache_set_way_op name register -@ -@ Perform an operation on all D-cache sets/ways. -@ -@ Note: implemented in assembly to guarantee that we are not touching the -@ D-cache in the middle of the loop. -@ -.thumb_func -.section .text.\name -.global \name -\name: - /* Select Level-1 Data cache (for operations on CCSIDR). */ - ldr r1, =SCB_CCSELR - movs r0, #0 - ldr r2, =SCB_CCSIDR - str r0, [r1] /* set CCSELR = 0 */ - - /* Ensure the CCSELR write is effective before reading CCSIDR. */ - dsb - /* CCSIDR contains the cache geometry. */ - ldr r3, [r2] /* [27:13] Number of sets -1 [12:3] Number of ways -1 */ - - /* register used to do the set/way cache operation. */ - ldr r0, =\register - /* r2 is the number of cache 'sets' - 1 */ - ubfx r2, r3, #13, #15 - /* r12 is the number of cache 'ways' - 1 */ - ubfx r12, r3, #3, #10 - -1: - mov r1, r12 /* reset way index */ -2: - /* - * Build address Set/Way operation e.g DC(C)ISW - * [31:30] way index [13:5] set index - */ - lsls r3, r2, #5 /* set index */ - /* TODO(crbug.com/848704) remove cache geometry assumptions */ - orr r3, r3, r1, lsl #30 /* way index */ - /* Perform operation (e.g invalidate) on a D-cache line */ - str r3, [r0] - /* go to previous way */ - subs r1, #1 - bcs 2b - /* go to previous set */ - subs r2, #1 - bcs 1b - - /* Ensure everything has propagated and return. */ - dsb - isb - bx lr -.endm - -/* D-cache Invalidate by set-way */ -dcache_set_way_op cpu_invalidate_dcache SCB_DCISW - -/* D-cache Clean and Invalidate by set-way, to Point of Coherency */ -dcache_set_way_op cpu_clean_invalidate_dcache SCB_DCCISW diff --git a/core/cortex-m/config_core.h b/core/cortex-m/config_core.h deleted file mode 100644 index 0665b28852..0000000000 --- a/core/cortex-m/config_core.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright 2013 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. - */ - -#ifndef __CROS_EC_CONFIG_CORE_H -#define __CROS_EC_CONFIG_CORE_H - -/* Linker binary architecture and format */ -#define BFD_ARCH arm -#define BFD_FORMAT "elf32-littlearm" - -#define CONFIG_SOFTWARE_PANIC - -#endif /* __CROS_EC_CONFIG_CORE_H */ diff --git a/core/cortex-m/cpu.c b/core/cortex-m/cpu.c deleted file mode 100644 index 7c31892c18..0000000000 --- a/core/cortex-m/cpu.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright 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. - * - * Set up the Cortex-M core - */ - -#include "common.h" -#include "cpu.h" -#include "hooks.h" - -void cpu_init(void) -{ - /* Catch divide by 0 and unaligned access */ - CPU_NVIC_CCR |= CPU_NVIC_CCR_DIV_0_TRAP | CPU_NVIC_CCR_UNALIGN_TRAP; - - /* Enable reporting of memory faults, bus faults and usage faults */ - CPU_NVIC_SHCSR |= CPU_NVIC_SHCSR_MEMFAULTENA | - CPU_NVIC_SHCSR_BUSFAULTENA | CPU_NVIC_SHCSR_USGFAULTENA; -} - -#ifdef CONFIG_ARMV7M_CACHE -static void cpu_invalidate_icache(void) -{ - /* - * Invalidates the entire instruction cache to the point of - * unification. - */ - CPU_SCB_ICIALLU = 0; - asm volatile("dsb; isb"); -} - -void cpu_enable_caches(void) -{ - /* Check whether the I-cache is already enabled */ - if (!(CPU_NVIC_CCR & CPU_NVIC_CCR_ICACHE)) { - /* Invalidate the I-cache first */ - cpu_invalidate_icache(); - /* Turn on the caching */ - CPU_NVIC_CCR |= CPU_NVIC_CCR_ICACHE; - asm volatile("dsb; isb"); - } - /* Check whether the D-cache is already enabled */ - if (!(CPU_NVIC_CCR & CPU_NVIC_CCR_DCACHE)) { - /* Invalidate the D-cache first */ - cpu_invalidate_dcache(); - /* Turn on the caching */ - CPU_NVIC_CCR |= CPU_NVIC_CCR_DCACHE; - asm volatile("dsb; isb"); - } -} - -void cpu_disable_caches(void) -{ - /* - * Disable the I-cache and the D-cache - * The I-cache will be invalidated after the reboot/sysjump if needed - * (e.g after a flash update). - */ - cpu_clean_invalidate_dcache(); - CPU_NVIC_CCR &= ~(CPU_NVIC_CCR_ICACHE | CPU_NVIC_CCR_DCACHE); - asm volatile("dsb; isb"); -} -DECLARE_HOOK(HOOK_SYSJUMP, cpu_disable_caches, HOOK_PRIO_LAST); -#endif /* CONFIG_ARMV7M_CACHE */ diff --git a/core/cortex-m/cpu.h b/core/cortex-m/cpu.h deleted file mode 100644 index 0b03302bfc..0000000000 --- a/core/cortex-m/cpu.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright 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. - * - * Registers map and definitions for Cortex-MLM4x processor - */ - -#ifndef __CROS_EC_CPU_H -#define __CROS_EC_CPU_H - -#include <stdint.h> -#include "compile_time_macros.h" - -/* Macro to access 32-bit registers */ -#define CPUREG(addr) (*(volatile uint32_t*)(addr)) - -#define CPU_NVIC_ST_CTRL CPUREG(0xE000E010) -#define ST_ENABLE BIT(0) -#define ST_TICKINT BIT(1) -#define ST_CLKSOURCE BIT(2) -#define ST_COUNTFLAG BIT(16) - -/* Nested Vectored Interrupt Controller */ -#define CPU_NVIC_EN(x) CPUREG(0xe000e100 + 4 * (x)) -#define CPU_NVIC_DIS(x) CPUREG(0xe000e180 + 4 * (x)) -#define CPU_NVIC_UNPEND(x) CPUREG(0xe000e280 + 4 * (x)) -#define CPU_NVIC_PRI(x) CPUREG(0xe000e400 + 4 * (x)) -/* SCB AIRCR : Application interrupt and reset control register */ -#define CPU_NVIC_APINT CPUREG(0xe000ed0c) -#define CPU_NVIC_APINT_SYSRST BIT(2) /* System reset request */ -#define CPU_NVIC_APINT_PRIOGRP (BIT(8)|BIT(9)|BIT(10)) -#define CPU_NVIC_APINT_ENDIAN BIT(15) /* Endianness */ -#define CPU_NVIC_APINT_KEY_RD (0xFA05U << 16) -#define CPU_NVIC_APINT_KEY_WR (0x05FAU << 16) -/* NVIC STIR : Software Trigger Interrupt Register */ -#define CPU_NVIC_SWTRIG CPUREG(0xe000ef00) -/* SCB SCR : System Control Register */ -#define CPU_SCB_SYSCTRL CPUREG(0xe000ed10) - -#define CPU_NVIC_CCR CPUREG(0xe000ed14) -#define CPU_NVIC_SHCSR CPUREG(0xe000ed24) -#define CPU_NVIC_CFSR CPUREG(0xe000ed28) -#define CPU_NVIC_HFSR CPUREG(0xe000ed2c) -#define CPU_NVIC_DFSR CPUREG(0xe000ed30) -#define CPU_NVIC_MFAR CPUREG(0xe000ed34) -#define CPU_NVIC_BFAR CPUREG(0xe000ed38) - -enum { - CPU_NVIC_CFSR_BFARVALID = BIT(15), - CPU_NVIC_CFSR_MFARVALID = BIT(7), - - CPU_NVIC_CCR_ICACHE = BIT(17), - CPU_NVIC_CCR_DCACHE = BIT(16), - CPU_NVIC_CCR_DIV_0_TRAP = BIT(4), - CPU_NVIC_CCR_UNALIGN_TRAP = BIT(3), - - CPU_NVIC_HFSR_DEBUGEVT = 1UL << 31, - CPU_NVIC_HFSR_FORCED = BIT(30), - CPU_NVIC_HFSR_VECTTBL = BIT(1), - - CPU_NVIC_SHCSR_MEMFAULTENA = BIT(16), - CPU_NVIC_SHCSR_BUSFAULTENA = BIT(17), - CPU_NVIC_SHCSR_USGFAULTENA = BIT(18), -}; - -/* System Control Block: cache registers */ -#define CPU_SCB_CCSIDR CPUREG(0xe000ed80) -#define CPU_SCB_CCSELR CPUREG(0xe000ed84) -#define CPU_SCB_ICIALLU CPUREG(0xe000ef50) -#define CPU_SCB_DCISW CPUREG(0xe000ef60) -#define CPU_SCB_DCCISW CPUREG(0xe000ef74) - -/* Set up the cpu to detect faults */ -void cpu_init(void); -/* Enable the CPU I-cache and D-cache if they are not already enabled */ -void cpu_enable_caches(void); -/* Disable the CPU I-cache and D-cache */ -void cpu_disable_caches(void); -/* Invalidate the D-cache */ -void cpu_invalidate_dcache(void); -/* Clean and Invalidate the D-cache to the Point of Coherency */ -void cpu_clean_invalidate_dcache(void); - -/* Invalidate a single range of the D-cache */ -void cpu_invalidate_dcache_range(uintptr_t base, unsigned int length); -/* Clean and Invalidate a single range of the D-cache */ -void cpu_clean_invalidate_dcache_range(uintptr_t base, unsigned int length); - -/* Set the priority of the given IRQ in the NVIC (0 is highest). */ -static inline void cpu_set_interrupt_priority(uint8_t irq, uint8_t priority) -{ - const uint32_t prio_shift = irq % 4 * 8 + 5; - - if (priority > 7) - priority = 7; - - CPU_NVIC_PRI(irq / 4) = - (CPU_NVIC_PRI(irq / 4) & - ~(7 << prio_shift)) | - (priority << prio_shift); -} - -#endif /* __CROS_EC_CPU_H */ diff --git a/core/cortex-m/debug.c b/core/cortex-m/debug.c deleted file mode 100644 index db8891b5d8..0000000000 --- a/core/cortex-m/debug.c +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright 2021 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 "debug.h" -#include "stdbool.h" - -bool debugger_is_connected(void) -{ - return CPU_DHCSR & DHCSR_C_DEBUGEN; -} diff --git a/core/cortex-m/debug.h b/core/cortex-m/debug.h deleted file mode 100644 index ae5ef08d06..0000000000 --- a/core/cortex-m/debug.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2021 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. - */ - -#ifndef __CROS_EC_DEBUG_H -#define __CROS_EC_DEBUG_H - -#include "common.h" -#include "stdbool.h" - -/* For Cortex-M0, see "C1.6.3 Debug Halting Control and Status Register, DHCSR" - * in the ARMv6-M Architecture Reference Manual. - * - * For other Cortex-M, see - * "C1.6.2 Debug Halting Control and Status Register, DHCSR" in the ARMv7-M - * Architecture Reference Manual or - * https://developer.arm.com/documentation/ddi0337/e/core-debug/core-debug-registers/debug-halting-control-and-status-register. - */ -#define CPU_DHCSR REG32(0xE000EDF0) -#define DHCSR_C_DEBUGEN BIT(0) -#define DHCSR_C_HALT BIT(1) -#define DHCSR_C_STEP BIT(2) -#define DHCSR_C_MASKINTS BIT(3) -#ifndef CHIP_CORE_CORTEX_M0 -#define DHCSR_C_SNAPSTALL BIT(5) /* Not available on Cortex-M0 */ -#endif -#define DHCSR_S_REGRDY BIT(16) -#define DHCSR_S_HALT BIT(17) -#define DHCSR_S_SLEEP BIT(18) -#define DHCSR_S_LOCKUP BIT(19) -#define DHCSR_S_RETIRE_ST BIT(24) -#define DHCSR_S_RESET_ST BIT(25) - -bool debugger_is_connected(void); - -#endif /* __CROS_EC_DEBUG_H */ diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S deleted file mode 100644 index 7b08be81a6..0000000000 --- a/core/cortex-m/ec.lds.S +++ /dev/null @@ -1,721 +0,0 @@ -/* Copyright 2013 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" -#include "rwsig.h" - -#define CONCAT_STAGE_1(w, x, y, z) w ## x ## y ## z -#define CONCAT2(w, x) CONCAT_STAGE_1(w, x, , ) -#define CONCAT3(w, x, y) CONCAT_STAGE_1(w, x, y, ) -#define CONCAT4(w, x, y, z) CONCAT_STAGE_1(w, x, y, z) - -#define STRINGIFY0(name) #name -#define STRINGIFY(name) STRINGIFY0(name) - -#ifdef RW_B_LDS -#define FW_MEM_OFF_(section) CONFIG_##section##_B_MEM_OFF -#else -#define FW_MEM_OFF_(section) CONFIG_##section##_MEM_OFF -#endif -#define FW_MEM_OFF(section) (FW_MEM_OFF_(section)) -#define FW_OFF(section) (CONFIG_PROGRAM_MEMORY_BASE + FW_MEM_OFF(section)) - -#define FW_SIZE_(section) CONFIG_##section##_SIZE -#define FW_SIZE(section) FW_SIZE_(section) - -/* - * Define the VMA (virtual memory address) of the ROM_RESIDENT region within - * the EC image. This is full 32-bit address starting from - * CONFIG_PROGRAM_MEMORY_BASE. - */ -#define ROM_RES_OFF(section) FW_OFF(CONCAT2(section, _ROM_RESIDENT)) -#define ROM_RES_SIZE(section) FW_SIZE(CONCAT2(section, _ROM_RESIDENT)) - -/* - * Define the VMA (virtual memory address) of the ROM_RESIDENT region. Instead - * of a full 32-bit address, set the VMA to be an offset within the flash memory - * section. Objects linked into this section can pass the address of the - * object unmodified to the public APIs of the flash and init_rom modules. - */ -#ifdef SECTION_IS_RO -#define ROM_RES_FLASH_OFF(section) \ - FW_MEM_OFF(CONCAT2(section, _ROM_RESIDENT)) + \ - CONFIG_EC_PROTECTED_STORAGE_OFF -#else -#define ROM_RES_FLASH_OFF(section) \ - FW_MEM_OFF(CONCAT2(section, _ROM_RESIDENT)) + \ - CONFIG_EC_WRITABLE_STORAGE_OFF -#endif - -/* Indicates where .data LMA should reside. */ -#undef DATA_LMA_MEM_REGION - -OUTPUT_FORMAT(BFD_FORMAT, BFD_FORMAT, BFD_FORMAT) -OUTPUT_ARCH(BFD_ARCH) -ENTRY(reset) - -MEMORY -{ -#if !defined(CONFIG_FLASH_PHYSICAL) - IROM (rx) : ORIGIN = CONFIG_ROM_BASE, LENGTH = CONFIG_ROM_SIZE -#else -#if defined(SECTION_IS_RO) && defined(NPCX_RO_HEADER) - /* - * Header structure used by npcx booter in RO region. - * Please notice the location of header must be in front of FW - * which needs copy. But header itself won't be copied to code ram - * by booter. - */ - FLASH_HDR (rx) : ORIGIN = FW_OFF(RO_HDR), LENGTH = FW_SIZE(RO_HDR) - FLASH (rx) : ORIGIN = FW_OFF(SECTION) + FW_SIZE(RO_HDR), \ - LENGTH = FW_SIZE(SECTION) - FW_SIZE(RO_HDR) -#else - FLASH (rx) : ORIGIN = FW_OFF(SECTION), LENGTH = FW_SIZE(SECTION) -#endif -#ifdef CONFIG_CHIP_INIT_ROM_REGION - ROM_RESIDENT (r) : \ - ORIGIN = ROM_RES_OFF(SECTION), \ - LENGTH = ROM_RES_SIZE(SECTION) - - ROM_RESIDENT_VMA (r) : \ - ORIGIN = ROM_RES_FLASH_OFF(SECTION), \ - LENGTH = ROM_RES_SIZE(SECTION) -#endif /* CONFIG_CHIP_INIT_ROM_REGION */ -#ifdef CONFIG_SHAREDLIB - SHARED_LIB (rx) : ORIGIN = FW_OFF(SHAREDLIB), \ - LENGTH = FW_SIZE(SHAREDLIB) -#endif -#endif /* !CONFIG_FLASH_PHYSICAL */ - IRAM (rw) : ORIGIN = CONFIG_RAM_BASE, LENGTH = CONFIG_RAM_SIZE - -#ifdef CONFIG_EXTERNAL_STORAGE - CDRAM (rx) : \ - ORIGIN = CONFIG_PROGRAM_MEMORY_BASE + FW_MEM_OFF(SECTION), \ - LENGTH = FW_SIZE(SECTION) -#endif /* CONFIG_EXTERNAL_STORAGE */ - -#ifdef CONFIG_CHIP_MEMORY_REGIONS -#define REGION(name, attr, start, size) \ - name(attr) : ORIGIN = (start), LENGTH = (size) -#define REGION_LOAD REGION -#include "memory_regions.inc" -#undef REGION -#undef REGION_LOAD -#endif /* CONFIG_MEMORY_REGIONS */ - -#ifdef CONFIG_DRAM_BASE - DRAM (rwx) : ORIGIN = CONFIG_DRAM_BASE, LENGTH = CONFIG_DRAM_SIZE -#endif -} - -/* - * Convenience macros for determining the correct output memory section. - */ -#if !defined(CONFIG_FLASH_PHYSICAL) - #define EC_IMAGE_LMA_MEM_REGION IROM - #define EC_IMAGE_VMA_MEM_REGION IROM - #define DATA_LMA_MEM_REGION IROM -#else - #define EC_IMAGE_LMA_MEM_REGION FLASH - #ifdef CONFIG_EXTERNAL_STORAGE - #define EC_IMAGE_VMA_MEM_REGION CDRAM - #else - #define EC_IMAGE_VMA_MEM_REGION FLASH - #endif - - #ifdef CONFIG_CHIP_DATA_IN_INIT_ROM - #define DATA_LMA_MEM_REGION ROM_RESIDENT - #else - #define DATA_LMA_MEM_REGION FLASH - #endif -#endif - -SECTIONS -{ -#if defined(SECTION_IS_RO) && defined(NPCX_RO_HEADER) - .header : { - KEEP(*(.header)) - } > FLASH_HDR -#endif -#ifdef CONFIG_SHAREDLIB - .roshared : { - KEEP(*(.roshared*)) - } > SHARED_LIB -#endif - .text : { -#ifdef SECTION_IS_RO - . = . + CONFIG_RO_HEAD_ROOM; -#endif -#ifdef SECTION_IS_RW - . = . + CONFIG_RW_HEAD_ROOM; -#endif - *(.text.vecttable) - . = ALIGN(4); - __image_data_offset = .; - KEEP(*(.rodata.ver)) - - . = ALIGN(4); - KEEP(*(.rodata.pstate)) - - . = ALIGN(4); - STRINGIFY(OUTDIR/core/CORE/init.o) (.text) -#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7 && !defined(CONFIG_HIBERNATE_PSL) - /* Keep hibernate utility in last code ram block */ - . = ALIGN(4); - KEEP(*(.after_init)) - __after_init_end = .; -#endif - *(.text*) -#ifdef CONFIG_EXTERNAL_STORAGE - . = ALIGN(4); - __flash_lpfw_start = .; - /* Entering deep idle FW for better power consumption */ - KEEP(*(.lowpower_ram)) - . = ALIGN(4); - __flash_lpfw_end = .; - __flash_lplfw_start = .; - /* GDMA utilities for better FW download speed */ - KEEP(*(.lowpower_ram2)) - . = ALIGN(4); - __flash_lplfw_end = .; -#endif /* CONFIG_EXTERNAL_STORAGE */ - } > EC_IMAGE_VMA_MEM_REGION AT > EC_IMAGE_LMA_MEM_REGION - - . = ALIGN(4); - .rodata : { - /* Symbols defined here are declared in link_defs.h */ - __irqprio = .; - KEEP(*(.rodata.irqprio)) - __irqprio_end = .; - - . = ALIGN(4); - __cmds = .; - KEEP(*(SORT(.rodata.cmds*))) - __cmds_end = .; - - . = ALIGN(4); - __extension_cmds = .; - KEEP(*(.rodata.extensioncmds)) - __extension_cmds_end = .; - - . = ALIGN(4); - __hcmds = .; - KEEP(*(SORT(.rodata.hcmds*))) - __hcmds_end = .; - - . = ALIGN(4); - __mkbp_evt_srcs = .; - KEEP(*(.rodata.evtsrcs)) - __mkbp_evt_srcs_end = .; - - . = ALIGN(4); - __hooks_init = .; - KEEP(*(.rodata.HOOK_INIT)) - __hooks_init_end = .; - - __hooks_pre_freq_change = .; - KEEP(*(.rodata.HOOK_PRE_FREQ_CHANGE)) - __hooks_pre_freq_change_end = .; - - __hooks_freq_change = .; - KEEP(*(.rodata.HOOK_FREQ_CHANGE)) - __hooks_freq_change_end = .; - - __hooks_sysjump = .; - KEEP(*(.rodata.HOOK_SYSJUMP)) - __hooks_sysjump_end = .; - - __hooks_chipset_pre_init = .; - KEEP(*(.rodata.HOOK_CHIPSET_PRE_INIT)) - __hooks_chipset_pre_init_end = .; - - __hooks_chipset_startup = .; - KEEP(*(.rodata.HOOK_CHIPSET_STARTUP)) - __hooks_chipset_startup_end = .; - - __hooks_chipset_resume = .; - KEEP(*(.rodata.HOOK_CHIPSET_RESUME)) - __hooks_chipset_resume_end = .; - - __hooks_chipset_suspend = .; - KEEP(*(.rodata.HOOK_CHIPSET_SUSPEND)) - __hooks_chipset_suspend_end = .; - -#ifdef CONFIG_CHIPSET_RESUME_INIT_HOOK - __hooks_chipset_resume_init = .; - KEEP(*(.rodata.HOOK_CHIPSET_RESUME_INIT)) - __hooks_chipset_resume_init_end = .; - - __hooks_chipset_suspend_complete = .; - KEEP(*(.rodata.HOOK_CHIPSET_SUSPEND_COMPLETE)) - __hooks_chipset_suspend_complete_end = .; -#endif - - __hooks_chipset_shutdown = .; - KEEP(*(.rodata.HOOK_CHIPSET_SHUTDOWN)) - __hooks_chipset_shutdown_end = .; - - __hooks_chipset_shutdown_complete = .; - KEEP(*(.rodata.HOOK_CHIPSET_SHUTDOWN_COMPLETE)) - __hooks_chipset_shutdown_complete_end = .; - - __hooks_chipset_hard_off = .; - KEEP(*(.rodata.HOOK_CHIPSET_HARD_OFF)) - __hooks_chipset_hard_off_end = .; - - __hooks_chipset_reset = .; - KEEP(*(.rodata.HOOK_CHIPSET_RESET)) - __hooks_chipset_reset_end = .; - - __hooks_ac_change = .; - KEEP(*(.rodata.HOOK_AC_CHANGE)) - __hooks_ac_change_end = .; - - __hooks_lid_change = .; - KEEP(*(.rodata.HOOK_LID_CHANGE)) - __hooks_lid_change_end = .; - - __hooks_tablet_mode_change = .; - KEEP(*(.rodata.HOOK_TABLET_MODE_CHANGE)) - __hooks_tablet_mode_change_end = .; - - __hooks_base_attached_change = .; - KEEP(*(.rodata.HOOK_BASE_ATTACHED_CHANGE)) - __hooks_base_attached_change_end = .; - - __hooks_pwrbtn_change = .; - KEEP(*(.rodata.HOOK_POWER_BUTTON_CHANGE)) - __hooks_pwrbtn_change_end = .; - - __hooks_battery_soc_change = .; - KEEP(*(.rodata.HOOK_BATTERY_SOC_CHANGE)) - __hooks_battery_soc_change_end = .; - -#ifdef CONFIG_USB_SUSPEND - __hooks_usb_change = .; - KEEP(*(.rodata.HOOK_USB_PM_CHANGE)) - __hooks_usb_change_end = .; -#endif - - __hooks_tick = .; - KEEP(*(.rodata.HOOK_TICK)) - __hooks_tick_end = .; - - __hooks_second = .; - KEEP(*(.rodata.HOOK_SECOND)) - __hooks_second_end = .; - - __hooks_usb_pd_disconnect = .; - KEEP(*(.rodata.HOOK_USB_PD_DISCONNECT)) - __hooks_usb_pd_disconnect_end = .; - - __hooks_usb_pd_connect = .; - KEEP(*(.rodata.HOOK_USB_PD_CONNECT)) - __hooks_usb_pd_connect_end = .; - - __deferred_funcs = .; - KEEP(*(.rodata.deferred)) - __deferred_funcs_end = .; - - __usb_desc = .; - KEEP(*(.rodata.usb_desc_conf)) - KEEP(*(SORT(.rodata.usb_desc*))) - __usb_desc_end = .; - . = ALIGN(4); - KEEP(*(.rodata.usb_ep)) - KEEP(*(.rodata.usb_ep.usb_ep_tx)) - KEEP(*(.rodata.usb_ep.usb_ep_rx)) - KEEP(*(.rodata.usb_ep.usb_ep_reset)) - KEEP(*(.rodata.usb_ep.usb_iface_request)) - - . = ALIGN(4); - *(.rodata*) - -#ifndef CONFIG_CHIP_INIT_ROM_REGION - /* - * When a separate ROM resident section isn't enabled, ensure - * the corresponding data objects are linked into the .rodata - * section. - */ - . = ALIGN(4); - __init_rom_start = .; - *(.init.rom) - __init_rom_end = .; -#endif /* CONFIG_CHIP_INIT_ROM_REGION */ - -#if defined(SECTION_IS_RO) && defined(CONFIG_FLASH_CROS) - . = ALIGN(64); - KEEP(*(.google)) -#endif - - . = ALIGN(4); - } > EC_IMAGE_VMA_MEM_REGION AT > EC_IMAGE_LMA_MEM_REGION - -#ifdef CONFIG_CHIP_DATA_IN_INIT_ROM - __data_lma_start = ORIGIN(ROM_RESIDENT_VMA); - #define INIT_ROM_LMA (ORIGIN(ROM_RESIDENT_VMA) + SIZEOF(.data)) -#else - __data_lma_start = .; - #define INIT_ROM_LMA ORIGIN(ROM_RESIDENT_VMA) -#endif - -#ifdef CONFIG_PRESERVE_LOGS - .preserve_logs(NOLOAD) : { - . = ALIGN(8); - *(SORT(.preserved_logs.*)) - . = ALIGN(8); - __preserved_logs_end = .; - } > IRAM - - ASSERT((SIZEOF(.preserve_logs) + CONFIG_RAM_BASE) == - __preserved_logs_end, - "preserve_logs must be at CONFIG_RAM_BASE.") -#endif - - .bss : { - /* - * Align to 512 bytes. This is convenient when some memory block - * needs big alignment. This is the beginning of the RAM, - * so there is usually no penalty on aligning this. - */ - . = ALIGN(512); - __bss_start = .; - *(.bss.big_align) - /* Stacks must be 64-bit aligned */ - . = ALIGN(8); - *(.bss.system_stack) - /* Rest of .bss takes care of its own alignment */ - - /* Group libtpm2 data so it can be cleared on system reset */ - __bss_libtpm2_start = .; - /* TPM registers should be cleared at the same time */ - STRINGIFY(OUTDIR/common/tpm_registers.o*)(.bss) - *(.bss.Tpm2_common) - __bss_libtpm2_end = .; - - *(.bss) - - /* - * Reserve space for deferred function firing times. - * Each time is a uint64_t, each func is a 32-bit pointer, - * thus the scaling factor of two. The 8 byte alignment of - * uint64_t is required by the ARM ABI. - */ - . = ALIGN(8); - __deferred_until = .; - . += (__deferred_funcs_end - __deferred_funcs) * (8 / 4); - __deferred_until_end = .; - } > IRAM - - .bss.slow : { - /* Region of RAM reclaimed from the little firmware(LFW). */ - *(.bss.slow) - /* - * Not replacing the loader, so .bss.slow is part of .bss. - * It needs to be followed by __bss_end so that .bss.slow - * will be zeroed by init. - */ - . = ALIGN(4); - __bss_end = .; - } > IRAM - - .data : { - . = ALIGN(4); - __data_start = .; - *(.data.tasks) - - /* - * Group libtpm2 data so it can be reinitialized on - * system reset - */ - __data_libtpm2_start = .; - Tpm2_*(.data) - /* TPM registers should be reinitialized at the same time */ - STRINGIFY(OUTDIR/common/tpm_registers.o*)(.data) - __data_libtpm2_end = .; - - /* - * TPM reset currently only clears BSS for the TPM library. - * It does not reset any initialized variables in data. - * So, make sure there aren't any. - */ - ASSERT(__data_libtpm2_start == __data_libtpm2_end, - "libtpm2 .data section is nonzero"); - - *(.data*) -#ifdef CONFIG_MPU - /* - * It has to be aligned by 32 bytes to be a valid - * MPU region. - */ - . = ALIGN(32); - __iram_text_start = .; -#else - . = ALIGN(4); -#endif - *(.iram.text) -#ifdef CONFIG_MPU - . = ALIGN(32); - __iram_text_end = .; -#else - . = ALIGN(4); -#endif - __data_end = .; - - /* - * Shared memory buffer must be at the end of preallocated - * RAM, so it can expand to use all the remaining RAM. - */ - __shared_mem_buf = .; - - /* NOTHING MAY GO AFTER THIS! */ - } > IRAM AT > DATA_LMA_MEM_REGION - - ASSERT((__shared_mem_buf + CONFIG_SHAREDMEM_MINIMUM_SIZE) <= - (CONFIG_RAM_BASE + CONFIG_RAM_SIZE), - "Not enough space for shared memory.") - - __ram_free = (CONFIG_RAM_BASE + CONFIG_RAM_SIZE) - - (__shared_mem_buf + CONFIG_SHAREDMEM_MINIMUM_SIZE); - -#ifdef CONFIG_CHIP_DATA_IN_INIT_ROM - /* - * .data is ROM resident, last section in the EC image is the .rodata - * section. - */ - #define FLASH_USED_END (LOADADDR(.rodata) + SIZEOF(.rodata)) -#else - /* - * .data is included in the EC image and copied to RAM by the loader. - */ - #define FLASH_USED_END (LOADADDR(.data) + SIZEOF(.data)) -#endif - - /* - * __flash_used is used in flash free calculations by the makefile. - * __image_size is stored in the struct image_data header and used - * in hash calcuations. - */ - __flash_used = FLASH_USED_END - ORIGIN(EC_IMAGE_LMA_MEM_REGION); -#ifndef CONFIG_CHIP_INIT_ROM_REGION -#if !(defined(SECTION_IS_RW) && (CONFIG_FLASH_WRITE_SIZE > 4)) - __image_size = __flash_used; -#else - .rw_image_size_alignment : - { - . = ORIGIN(FLASH) + __flash_used; - BYTE(0xFF); - . = ALIGN (CONFIG_FLASH_WRITE_SIZE); - } > FLASH = 0xFF - - __image_size = __flash_used + SIZEOF(.rw_image_size_alignment); -#endif -#endif /* CONFIG_CHIP_INIT_ROM_REGION */ - -#ifdef CONFIG_FLASH_CROS - /* - * These linker labels are just for analysis and not used in the code. - */ - __config_flash_size = CONFIG_FLASH_SIZE_BYTES; - __config_ro_size = CONFIG_RO_SIZE; - __config_ec_protected_storage_size = CONFIG_EC_PROTECTED_STORAGE_SIZE; - __config_rw_size = CONFIG_RW_SIZE; - __config_ec_writable_storage_size = CONFIG_EC_WRITABLE_STORAGE_SIZE; -#endif - - /* - * The linker won't notice if the .data section is too big to fit, - * apparently because we're sending it into IRAM, not FLASH. - * Verify that all sections linked into the FLASH region will fit. - */ - ASSERT((LENGTH(EC_IMAGE_LMA_MEM_REGION) -#if defined(CONFIG_RWSIG) && defined(SECTION_IS_RO) - - CONFIG_RO_PUBKEY_SIZE -#endif -#if defined(CONFIG_RWSIG) && defined(SECTION_IS_RW) - - CONFIG_RW_SIG_SIZE -#endif - ) >= __flash_used, - "No room left in the flash") - -#ifdef CONFIG_CHIP_INIT_ROM_REGION - /* - * Image layout when ROM_RESIDENT region is used (lower addresses - * at the top). This layout is setup by the LMA assignment. - * - * EC image layout (LMA) VMA - * .header (if RO image) none - * .text code RAM - * .rodata code RAM + .text size - * .data data RAM - * .fill none - * .init_rom flash offset - * - * The loader code copies the .text, .rodata, and .data sections into - * the code RAM of the EC. The .header and .init_rom sections are not - * copied by the loader. - * - * Image layout when ROM_RESIDENT region is used, and - * CONFIG_CHIP_DATA_IN_INIT_ROM is enabled. - * - * EC image layout (LMA) VMA - * .header (if RO image) none - * .text code RAM - * .rodata code RAM + .text size - * .fill none - * .data data RAM - * .init_rom flash offset - * - * The loader code copies the .text and .rodata sections into the code - * RAM of the EC. The .header, .data, and .init_rom sections are not - * copied by the loader. - * - * EC initialization code copies the .data directly from flash to - * data RAM at runtime. - */ - - /* - * The layout assumes the ROM_RESIDENT region follows the FLASH - * region. - */ - ASSERT((ORIGIN(FLASH) + LENGTH(FLASH)) == ORIGIN(ROM_RESIDENT), - ".init_rom section must follow the flash section") - - .init_rom INIT_ROM_LMA : { - . = ALIGN(4); - __init_rom_start = .; - *(.init.rom) - __init_rom_end = .; - } > ROM_RESIDENT_VMA AT > ROM_RESIDENT - - /* - * The ROM_RESIDENT section is assumed to be in the same physical - * flash as the FLASH section. Fill the space between. - */ - .fill : { - . = FLASH_USED_END; - . = ALIGN(4); - __fill_start = .; - FILL(0xFF); - . = ORIGIN(FLASH) + LENGTH(FLASH) - 1; - /* Need at least one byte so section is not omitted */ - BYTE(0xFF); - __fill_end = .; - } > FLASH - - /* - * The end of the .fill region should also be the start of the ROM - * resident region. - */ - ASSERT(__fill_end == ORIGIN(ROM_RESIDENT), - ".fill region end not aligned to start of ROM_RESIDENT region") - - /* - * __image_size is used for hash calculation. When - * CONFIG_CHIP_INIT_ROM_REGION is enabled, this includes the entire - * FLASH region and the bytes used in the .init_rom section. - */ -#ifdef CONFIG_CHIP_DATA_IN_INIT_ROM - __image_size = LENGTH(FLASH) + SIZEOF(.init_rom) + SIZEOF(.data); -#else - __image_size = LENGTH(FLASH) + SIZEOF(.init_rom); -#endif /* CONFIG_CHIP_DATA_IN_INIT_ROM */ -#endif /* CONFIG_CHIP_INIT_ROM_REGION */ - -#ifdef CONFIG_CHIP_MEMORY_REGIONS -#define REGION(name, attr, start, size) \ - .name(NOLOAD) : { \ - __##name##_start = .; \ - KEEP(*(SORT(.name.keep.*))) \ - *(SORT(.name.*)) \ - } > name -#define REGION_LOAD(name, attr, start, size) \ - .name : { \ - __##name##_start = .; \ - KEEP(*(SORT(.name.keep.*))) \ - *(SORT(.name.*)) \ - } > name -#include "memory_regions.inc" -#undef REGION -#undef REGION_LOAD -#endif /* CONFIG_CHIP_MEMORY_REGIONS */ - -#ifdef CONFIG_DRAM_BASE - - /* - * Sections in DRAM region are constructed as like in non-DRAM regions: - * .dram.data LMA is for preserving initialized data across resets. - * The only difference is that they are all in the DRAM region: - * .dram.text | LOAD - * .dram.rodata | LOAD - * .dram.data LMA | LOAD - * .dram.data VMA | - * .dram.bss | NOLOAD - * TODO(b:123269246): Enable MPU protectable DRAM section. This might - * introduce a RO-DRAM section for .dram.text, .dram.rodata and - * .dram.data LMA. - */ - - .dram.text : { - . = ALIGN(4); - KEEP(*(SORT(.dram.text.keep.*))) - *(SORT(.dram.text.*)) - . = ALIGN(4); - } > DRAM - - .dram.rodata : { - . = ALIGN(4); - KEEP(*(SORT(.dram.rodata.keep.*))) - *(SORT(.dram.rodata.*)) - . = ALIGN(4); - } > DRAM - - __dram_data_lma_start = ADDR(.dram.rodata) + SIZEOF(.dram.rodata); - - /* Place .dram.data LMA in between .dram.rodata and .dram.data VMA. */ -#ifdef __clang__ - /* - * The evaluation timing for SIZEOF() and symbols are different in - * ld and lld. - */ - .dram.data __dram_data_lma_start + SIZEOF(.dram.data) : { -#else - .dram.data __dram_data_lma_start + - (__dram_data_end - __dram_data_start) : { -#endif /* __clang__ */ - . = ALIGN(4); - __dram_data_start = .; - *(.dram.data*) - . = ALIGN(4); - __dram_data_end = .; - - /* - * Normally, '> DRAM AT > DRAM' should be the same as '> DRAM', - * and they will be at the same address. However, if the address - * of VMA specified, LMA and VMA might have different addresses: - * '> DRAM' places VMA at the address where section declaration - * specified. - * 'AT > DRAM' places LMA at the location counter's address. - */ - } > DRAM AT > DRAM - - /* - * ld assigns correct attribute for .bss, but not for other .*.bss, - * we need an explicltly NOLOAD. - */ - .dram.bss(NOLOAD) : { - . = ALIGN(4); - __dram_bss_start = .; - *(SORT(.dram.bss*)) - . = ALIGN(4); - __dram_bss_end = .; - } > DRAM -#endif - -#if !(defined(SECTION_IS_RO) && defined(CONFIG_FLASH_CROS)) - /DISCARD/ : { *(.google) } -#endif - /DISCARD/ : { *(.ARM.*) } -} diff --git a/core/cortex-m/ghash.S b/core/cortex-m/ghash.S deleted file mode 120000 index e9acbf4b25..0000000000 --- a/core/cortex-m/ghash.S +++ /dev/null @@ -1 +0,0 @@ -../../third_party/boringssl/core/cortex-m/ghash.S
\ No newline at end of file diff --git a/core/cortex-m/include/fpu.h b/core/cortex-m/include/fpu.h deleted file mode 100644 index 0949d336e2..0000000000 --- a/core/cortex-m/include/fpu.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 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. - */ - -/* Math utility functions for ARMv7 */ - -#ifndef __CROS_EC_FPU_H -#define __CROS_EC_FPU_H - -#ifdef CONFIG_FPU -static inline float sqrtf(float v) -{ - float root; - asm volatile( - "fsqrts %0, %1" - : "=w" (root) - : "w" (v) - ); - return root; -} - -static inline float fabsf(float v) -{ - float root; - asm volatile( - "fabss %0, %1" - : "=w" (root) - : "w" (v) - ); - return root; -} -#endif /* CONFIG_FPU */ - -#endif /* __CROS_EC_FPU_H */ diff --git a/core/cortex-m/include/mpu.h b/core/cortex-m/include/mpu.h deleted file mode 100644 index 610728b501..0000000000 --- a/core/cortex-m/include/mpu.h +++ /dev/null @@ -1,144 +0,0 @@ -/* Copyright 2013 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. - */ - -/* MPU module for Cortex-M3 */ - -#ifndef __CROS_EC_MPU_H -#define __CROS_EC_MPU_H - -#include "common.h" -#include "config.h" /* chips might override MPU attribute settings */ - -/* - * ARMv7-M SRAM region - */ -#define CORTEX_M_SRAM_BASE 0x20000000 - -/* - * Region assignment. 7 as the highest, a higher index has a higher priority. - * For example, using 7 for .iram.text allows us to mark entire RAM XN except - * .iram.text, which is used for hibernation. - * Region assignment is currently wasteful and can be changed if more - * regions are needed in the future. For example, a second region may not - * be necessary for all types, and REGION_CODE_RAM / REGION_STORAGE can be - * made mutually exclusive. - */ -enum mpu_region { - REGION_DATA_RAM = 0, /* For internal data RAM */ - REGION_DATA_RAM2 = 1, /* Second region for unaligned size */ - REGION_CODE_RAM = 2, /* For internal code RAM */ - REGION_CODE_RAM2 = 3, /* Second region for unaligned size */ - REGION_STORAGE = 4, /* For mapped internal storage */ - REGION_STORAGE2 = 5, /* Second region for unaligned size */ - REGION_DATA_RAM_TEXT = 6, /* Exempt region of data RAM */ - REGION_CHIP_RESERVED = 7, /* Reserved for use in chip/ */ - /* only for chips with MPU supporting 16 regions */ - REGION_UNCACHED_RAM = 8, /* For uncached data RAM */ - REGION_UNCACHED_RAM2 = 9, /* Second region for unaligned size */ - REGION_ROLLBACK = 10, /* For rollback */ -}; - -#define MPU_TYPE REG32(0xe000ed90) -#define MPU_CTRL REG32(0xe000ed94) -#define MPU_NUMBER REG32(0xe000ed98) -#define MPU_BASE REG32(0xe000ed9c) -#define MPU_SIZE REG16(0xe000eda0) -#define MPU_ATTR REG16(0xe000eda2) - -/* - * See ARM v7-M Architecture Reference Manual - * Section B3.5.5 MPU Type Register, MPU_TYPE - */ -#define MPU_TYPE_UNIFIED_MASK 0x00FF0001 -#define MPU_TYPE_REG_COUNT(t) (((t) >> 8) & 0xFF) - -#define MPU_CTRL_PRIVDEFEN BIT(2) -#define MPU_CTRL_HFNMIENA BIT(1) -#define MPU_CTRL_ENABLE BIT(0) - -/* - * Minimum region size is 32 bytes, 5 bits of address space - */ -#define MPU_SIZE_BITS_MIN 5 - -/* - * XN (execute never) bit. It's bit 12 if accessed by halfword. - * 0: XN off - * 1: XN on - */ -#define MPU_ATTR_XN BIT(12) - -/* AP bit. See table 3-5 of Stellaris LM4F232H5QC datasheet for details */ -#define MPU_ATTR_NO_NO (0 << 8) /* previleged no access, unprev no access */ -#define MPU_ATTR_RW_NO (1 << 8) /* previleged ReadWrite, unprev no access */ -#define MPU_ATTR_RW_RO (2 << 8) /* previleged ReadWrite, unprev Read-only */ -#define MPU_ATTR_RW_RW (3 << 8) /* previleged ReadWrite, unprev ReadWrite */ -#define MPU_ATTR_RO_NO (5 << 8) /* previleged Read-only, unprev no access */ - -/* Suggested value for TEX S/C/B bit. See table 3-6 of Stellaris LM4F232H5QC - * datasheet and table 38 of STM32F10xxx Cortex-M3 programming manual. */ -#ifndef MPU_ATTR_INTERNAL_SRAM -#define MPU_ATTR_INTERNAL_SRAM 6 /* for Internal SRAM */ -#endif -#ifndef MPU_ATTR_FLASH_MEMORY -#define MPU_ATTR_FLASH_MEMORY 2 /* for flash memory */ -#endif - -/* Represent RW with at most 2 MPU regions. */ -#define MAX_RW_REGIONS 2 -struct mpu_rw_regions { - int num_regions; - uint32_t addr[MAX_RW_REGIONS]; - uint32_t size[MAX_RW_REGIONS]; -}; - -/** - * Enable MPU - */ -void mpu_enable(void); - -/** - * Returns the value of MPU type register - * - * Bit fields: - * [15:8] Number of the data regions implemented or 0 if MPU is not present. - * [1] 0: unified (no distinction between instruction and data) - * 1: separated - */ -uint32_t mpu_get_type(void); - -/* Location of iram.text */ -extern char __iram_text_start; -extern char __iram_text_end; - -/** - * Protect RAM from code execution - */ -int mpu_protect_data_ram(void); - -/** - * Protect code RAM from being overwritten - */ -int mpu_protect_code_ram(void); - -/** - * Protect internal mapped flash memory from code execution - */ -int mpu_lock_ro_flash(void); -int mpu_lock_rw_flash(void); - -/** - * Protect/unprotect rollback region readback. - */ -int mpu_lock_rollback(int lock); - -/** - * Initialize MPU. - * It disables all regions if MPU is implemented. Otherwise, returns - * EC_ERROR_UNIMPLEMENTED. - */ -int mpu_pre_init(void); - -#endif /* __CROS_EC_MPU_H */ diff --git a/core/cortex-m/include/mpu_private.h b/core/cortex-m/include/mpu_private.h deleted file mode 100644 index e6030114c2..0000000000 --- a/core/cortex-m/include/mpu_private.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright 2020 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. - */ - -/** - * @file - * - * @brief Private header file. Not meant to be used outside of mpu.c and tests. - */ - -#ifndef __CROS_EC_MPU_PRIVATE_H -#define __CROS_EC_MPU_PRIVATE_H - -int mpu_num_regions(void); -bool has_mpu(void); -bool mpu_is_unified(void); -void mpu_disable(void); -int mpu_update_region(uint8_t region, uint32_t addr, uint8_t size_bit, - uint16_t attr, uint8_t enable, uint8_t srd); -int mpu_config_region(uint8_t region, uint32_t addr, uint32_t size, - uint16_t attr, uint8_t enable); -struct mpu_rw_regions mpu_get_rw_regions(void); - -#endif /* __CROS_EC_MPU_PRIVATE_H */ diff --git a/core/cortex-m/init.S b/core/cortex-m/init.S deleted file mode 100644 index bc650c4c64..0000000000 --- a/core/cortex-m/init.S +++ /dev/null @@ -1,135 +0,0 @@ -/* Copyright 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 - -.global reset -.thumb_func -reset: - /* - * Ensure we're in privileged mode with main stack. Necessary if - * we've jumped directly here from another image after task_start(). - */ -#ifdef CONFIG_FPU - mov r0, #(1 << 2) @ priv. mode / main stack / floating point on -#else - mov r0, #0 @ priv. mode / main stack / no floating point -#endif - msr control, r0 - isb @ ensure the write is done - - /* Set the vector table on our current code */ - ldr 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 - - /* Copy initialized data to Internal RAM */ - ldr r0,_data_lma_start - - /* - * When the .data section is linked into the .init_rom section, - * _data_lma_start is defined as a flash offset instead of a full - * 32-bit address by the linker script. Add the 32-bit flash base - * address to get a full 32-bit address. - * - * Flash locking isn't needed here as no tasks have been started. - */ -#ifdef CONFIG_CHIP_DATA_IN_INIT_ROM - ldr r1, =CONFIG_MAPPED_STORAGE_BASE - add r0, r0, r1 -#endif - - 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 - - /* - * Set stack pointer. Already done by Cortex-M hardware, but re-doing - * this here allows software to jump directly to the reset vector. - */ - ldr r0, =stack_end - mov sp, r0 - -#ifdef CONFIG_FPU - /* Enable FPU */ - /* CPACR is located at address 0xE000ED88 */ - ldr r0, =0xE000ED88 - /* Read CPACR */ - ldr r1, [r0] - /* Set bits 20-23 to enable CP10 and CP11 coprocessors */ - orr r1, r1, #(0xF << 20) - /* Write back the modified value to the CPACR */ - str r1, [r0] /* wait for store to complete */ - dsb - /* reset pipeline now the FPU is enabled */ - isb -#endif /* CONFIG_FPU */ - -#ifdef CONFIG_DEBUG_DISABLE_WRITE_BUFFER - /* Disable write buffer used for default memory map accesses */ - ldr r0, =0xE000E008 /* Load address of ACTLR */ - ldr r1, [r0] /* Read ACTLR */ - orr r1, r1, #2 /* Set DISDEFWBUF bit */ - str r1, [r0] /* Write back ACTLR */ - dsb /* Wait for store to complete */ - isb /* Reset pipeline */ -#endif /* CONFIG_DEBUG_DISABLE_WRITE_BUFFER */ - - /* Jump to C code */ - bl main - - /* That should not return. If it does, loop forever. */ -fini_loop: - b fini_loop - -.align 2 -_bss_start: -.long __bss_start -_bss_end: -.long __bss_end -_data_start: -.long __data_start -_data_end: -.long __data_end -_data_lma_start: -.long __data_lma_start - -/* Mock 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 - -/* Reserve space for system stack */ -.section .bss.system_stack -stack_start: -.space CONFIG_STACK_SIZE, 0 -stack_end: -.global stack_end - diff --git a/core/cortex-m/irq_handler.h b/core/cortex-m/irq_handler.h deleted file mode 100644 index ae5d95cd94..0000000000 --- a/core/cortex-m/irq_handler.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2014 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. - */ - -/* Helper to declare IRQ handling routines */ - -#ifndef __CROS_EC_IRQ_HANDLER_H -#define __CROS_EC_IRQ_HANDLER_H - -#ifdef CONFIG_TASK_PROFILING -#define bl_task_start_irq_handler "bl task_start_irq_handler\n" -#else -#define bl_task_start_irq_handler "" -#endif - -/* Helper macros to build the IRQ handler and priority struct names */ -#define IRQ_HANDLER(irqname) CONCAT3(irq_, irqname, _handler) -#define IRQ_PRIORITY(irqname) CONCAT2(prio_, irqname) -/* - * Macro to connect the interrupt handler "routine" to the irq number "irq" and - * ensure it is enabled in the interrupt controller with the right priority. - */ -#define DECLARE_IRQ(irq, routine, priority) DECLARE_IRQ_(irq, routine, priority) -#define DECLARE_IRQ_(irq, routine, priority) \ - void IRQ_HANDLER(irq)(void) __attribute__((naked)); \ - typedef struct { \ - int fake[irq >= CONFIG_IRQ_COUNT ? -1 : 1]; \ - } irq_num_check_##irq; \ - void __keep routine(void); \ - void IRQ_HANDLER(irq)(void) \ - { \ - asm volatile("mov r0, lr\n" \ - "push {r0, lr}\n" \ - bl_task_start_irq_handler \ - "bl "#routine"\n" \ - "pop {r0, lr}\n" \ - "b task_resched_if_needed\n" \ - ); \ - } \ - const struct irq_priority __keep IRQ_PRIORITY(irq) \ - __attribute__((section(".rodata.irqprio"))) \ - = {irq, priority} -#endif /* __CROS_EC_IRQ_HANDLER_H */ diff --git a/core/cortex-m/ldivmod.S b/core/cortex-m/ldivmod.S deleted file mode 120000 index afdeb4ec1f..0000000000 --- a/core/cortex-m/ldivmod.S +++ /dev/null @@ -1 +0,0 @@ -../../third_party/libaeabi-cortexm0/core/cortex-m/ldivmod.S
\ No newline at end of file diff --git a/core/cortex-m/llsr.c b/core/cortex-m/llsr.c deleted file mode 100644 index 0827121e97..0000000000 --- a/core/cortex-m/llsr.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Enable the use of right shift for uint64_t. */ - -#include <console.h> -#include <compile_time_macros.h> -#include <stdint.h> - -union words { - uint64_t u64; - uint32_t w[2]; -}; - -uint64_t __attribute__((used)) __aeabi_llsr(uint64_t v, uint32_t shift) -{ - union words val; - union words res; - - val.u64 = v; - res.w[1] = val.w[1] >> shift; - res.w[0] = val.w[0] >> shift; - res.w[0] |= val.w[1] >> (shift - 32); /* Handle shift >= 32*/ - res.w[0] |= val.w[1] << (32 - shift); /* Handle shift <= 32*/ - return res.u64; -} - -#ifdef CONFIG_LLSR_TEST - -static int command_llsr(int argc, char **argv) -{ - /* Volatile to prevent compilier optimization from interfering. */ - volatile uint64_t start = 0x123456789ABCDEF0ull; - uint32_t x; - - const struct { - uint32_t shift_by; - uint64_t result; - } cases[] = { - {0, start}, - {16, 0x123456789ABCull}, - {32, 0x12345678u}, - {48, 0x1234u}, - {64, 0u} - }; - - for (x = 0; x < ARRAY_SIZE(cases); ++x) { - if ((start >> cases[x].shift_by) != cases[x].result) { - ccprintf("FAILED %d\n", cases[x].shift_by); - return EC_ERROR_UNKNOWN; - } - } - - ccprintf("SUCCESS\n"); - return EC_SUCCESS; -} - -DECLARE_CONSOLE_COMMAND( - llsrtest, command_llsr, - "", - "Run tests against the LLSR ABI. Prints SUCCESS or FAILURE."); - -#endif /* CONFIG_LLSR_TEST */ diff --git a/core/cortex-m/mpu.c b/core/cortex-m/mpu.c deleted file mode 100644 index 29da931a28..0000000000 --- a/core/cortex-m/mpu.c +++ /dev/null @@ -1,457 +0,0 @@ -/* Copyright 2013 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. - */ - -/* MPU module for Chrome EC */ - -#include "mpu.h" -#include "console.h" -#include "cpu.h" -#include "registers.h" -#include "task.h" -#include "util.h" - -/** - * @return Number of regions supported by the MPU. 0 means the processor does - * not implement an MPU. - */ -int mpu_num_regions(void) -{ - return MPU_TYPE_REG_COUNT(mpu_get_type()); -} - -/** - * @return true if processor has MPU, false otherwise - */ -bool has_mpu(void) -{ - return mpu_num_regions() != 0; -} - -/** - * @return true if MPU has unified instruction and data maps, false otherwise - */ -bool mpu_is_unified(void) -{ - return (mpu_get_type() & MPU_TYPE_UNIFIED_MASK) == 0; -} - - -/** - * Update a memory region. - * - * region: index of the region to update - * addr: base address of the region - * size_bit: size of the region in power of two. - * attr: attribute bits. Current value will be overwritten if enable is true. - * enable: enables the region if non zero. Otherwise, disables the region. - * srd: subregion mask to partition region into 1/8ths, 0 = subregion enabled. - * - * Based on 3.1.4.1 'Updating an MPU Region' of Stellaris LM4F232H5QC Datasheet - */ -int mpu_update_region(uint8_t region, uint32_t addr, uint8_t size_bit, - uint16_t attr, uint8_t enable, uint8_t srd) -{ - /* - * Note that on the Cortex-M3, Cortex-M4, and Cortex-M7, the base - * address used for an MPU region must be aligned to the size of the - * region: - * - * https://developer.arm.com/docs/dui0553/a/cortex-m4-peripherals/optional-memory-protection-unit/mpu-region-base-address-register - * https://developer.arm.com/docs/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit/mpu-region-base-address-register - * https://developer.arm.com/docs/dui0646/a/cortex-m7-peripherals/optional-memory-protection-unit/mpu-region-base-address-register#BABDAHJG - */ - if (!is_aligned(addr, BIT(size_bit))) - return -EC_ERROR_INVAL; - - if (region >= mpu_num_regions()) - return -EC_ERROR_INVAL; - - if (size_bit < MPU_SIZE_BITS_MIN) - return -EC_ERROR_INVAL; - - asm volatile("isb; dsb;"); - - MPU_NUMBER = region; - MPU_SIZE &= ~1; /* Disable */ - if (enable) { - MPU_BASE = addr; - /* - * MPU_ATTR = attr; - * MPU_SIZE = (srd << 8) | ((size_bit - 1) << 1) | 1; - * - * WORKAROUND: the 2 half-word accesses above should work - * according to the doc, but they don't ..., do a single 32-bit - * one. - */ - REG32(&MPU_SIZE) = ((uint32_t)attr << 16) - | (srd << 8) | ((size_bit - 1) << 1) | 1; - } - - asm volatile("isb; dsb;"); - - return EC_SUCCESS; -} - -/* - * Greedily configure the largest possible part of the given region from the - * base address. - * - * Returns EC_SUCCESS on success and sets *consumed to the number of bytes - * mapped from the base address. In case of error, the value of *consumed is - * unpredictable. - * - * For instance, if addr is 0x10070000 and size is 0x30000 then memory in the - * range 0x10070000-0x10080000 will be configured and *consumed will be set to - * 0x10000. - */ -static int mpu_config_region_greedy(uint8_t region, uint32_t addr, - uint32_t size, uint16_t attr, - uint8_t enable, uint32_t *consumed) -{ - /* - * Compute candidate alignment to be used for the MPU region. - * - * This is the minimum of the base address and size alignment, since - * regions must be naturally aligned to their size. - */ - uint8_t natural_alignment = MIN(addr == 0 ? 32 : alignment_log2(addr), - alignment_log2(size)); - uint8_t subregion_disable = 0; - - if (natural_alignment >= 5) { - int sr_idx; - uint32_t subregion_base, subregion_size; - /* - * For MPU regions larger than 256 bytes we can use subregions, - * (which are a minimum of 32 bytes in size) making the actual - * MPU region 8x larger. Depending on the address alignment this - * can allow us to cover a larger area (and never a smaller - * one). - */ - natural_alignment += 3; - /* Region size cannot exceed 4GB. */ - if (natural_alignment > 32) - natural_alignment = 32; - - /* - * Generate the subregion mask by walking through each, - * disabling if it is not completely contained in the requested - * range. - */ - subregion_base = addr & ~((1 << natural_alignment) - 1); - subregion_size = 1 << (natural_alignment - 3); - *consumed = 0; - for (sr_idx = 0; sr_idx < 8; sr_idx++) { - if (subregion_base < addr || - (subregion_base + subregion_size) > (addr + size)) - /* lsb of subregion mask is lowest address */ - subregion_disable |= 1 << sr_idx; - else - /* not disabled means consumed */ - *consumed += subregion_size; - - subregion_base += subregion_size; - } - } else { - /* Not using subregions; all enabled */ - *consumed = 1 << natural_alignment; - } - - return mpu_update_region(region, - addr & ~((1 << natural_alignment) - 1), - natural_alignment, - attr, enable, subregion_disable); -} - -/** - * Configure a region - * - * region: index of the region to update - * addr: Base address of the region - * size: Size of the region in bytes - * attr: Attribute bits. Current value will be overwritten if enable is set. - * enable: Enables the region if non zero. Otherwise, disables the region. - * - * Returns EC_SUCCESS on success, -EC_ERROR_OVERFLOW if it is not possible to - * fully configure the given region, or -EC_ERROR_INVAL if a parameter is - * invalid (such as the address or size having unsupported alignment). - */ -int mpu_config_region(uint8_t region, uint32_t addr, uint32_t size, - uint16_t attr, uint8_t enable) -{ - int rv; - uint32_t consumed; - - /* Zero size doesn't require configuration */ - if (size == 0) - return EC_SUCCESS; - - rv = mpu_config_region_greedy(region, addr, size, - attr, enable, &consumed); - if (rv != EC_SUCCESS) - return rv; - ASSERT(consumed <= size); - addr += consumed; - size -= consumed; - - /* Regions other than DATA_RAM_TEXT may use two MPU regions */ - if (size > 0 && region != REGION_DATA_RAM_TEXT) { - rv = mpu_config_region_greedy(region + 1, addr, size, - attr, enable, &consumed); - if (rv != EC_SUCCESS) - return rv; - ASSERT(consumed <= size); - addr += consumed; - size -= consumed; - } - - if (size > 0) - return EC_ERROR_OVERFLOW; - return EC_SUCCESS; -} - -/** - * Set a region executable and read-write. - * - * region: index of the region - * addr: base address of the region - * size: size of the region in bytes - * texscb: TEX and SCB bit field - */ -static int mpu_unlock_region(uint8_t region, uint32_t addr, uint32_t size, - uint8_t texscb) -{ - return mpu_config_region(region, addr, size, - MPU_ATTR_RW_RW | texscb, 1); -} - -void mpu_enable(void) -{ - MPU_CTRL |= MPU_CTRL_PRIVDEFEN | MPU_CTRL_HFNMIENA | MPU_CTRL_ENABLE; -} - -void mpu_disable(void) -{ - MPU_CTRL &= ~(MPU_CTRL_PRIVDEFEN | MPU_CTRL_HFNMIENA | MPU_CTRL_ENABLE); -} - -uint32_t mpu_get_type(void) -{ - return MPU_TYPE; -} - -int mpu_protect_data_ram(void) -{ - int ret; - - /* Prevent code execution from data RAM */ - ret = mpu_config_region(REGION_DATA_RAM, - CONFIG_RAM_BASE, - CONFIG_DATA_RAM_SIZE, - MPU_ATTR_XN | - MPU_ATTR_RW_RW | - MPU_ATTR_INTERNAL_SRAM, - 1); - if (ret != EC_SUCCESS) - return ret; - - /* Exempt the __iram_text section */ - return mpu_unlock_region( - REGION_DATA_RAM_TEXT, (uint32_t)&__iram_text_start, - (uint32_t)(&__iram_text_end - &__iram_text_start), - MPU_ATTR_INTERNAL_SRAM); -} - -#if defined(CONFIG_EXTERNAL_STORAGE) || !defined(CONFIG_FLASH_PHYSICAL) -int mpu_protect_code_ram(void) -{ - /* Prevent write access to code RAM */ - return mpu_config_region(REGION_STORAGE, - CONFIG_PROGRAM_MEMORY_BASE + CONFIG_RO_MEM_OFF, - CONFIG_CODE_RAM_SIZE, - MPU_ATTR_RO_NO | MPU_ATTR_INTERNAL_SRAM, - 1); -} -#else -int mpu_lock_ro_flash(void) -{ - /* Prevent execution from internal mapped RO flash */ - return mpu_config_region(REGION_STORAGE, - CONFIG_MAPPED_STORAGE_BASE + CONFIG_RO_MEM_OFF, - CONFIG_RO_SIZE, - MPU_ATTR_XN | MPU_ATTR_RW_RW | - MPU_ATTR_FLASH_MEMORY, 1); -} - -/* Represent RW with at most 2 MPU regions. */ -struct mpu_rw_regions mpu_get_rw_regions(void) -{ - int aligned_size_bit; - struct mpu_rw_regions regions = {}; - - regions.addr[0] = CONFIG_MAPPED_STORAGE_BASE + CONFIG_RW_MEM_OFF; - - /* - * Least significant set bit of the address determines the max size of - * the region because on the Cortex-M3, Cortex-M4 and Cortex-M7, the - * address used for an MPU region must be aligned to the size. - */ - aligned_size_bit = - __fls(regions.addr[0] & -regions.addr[0]); - regions.size[0] = MIN(BIT(aligned_size_bit), CONFIG_RW_SIZE); - regions.addr[1] = regions.addr[0] + regions.size[0]; - regions.size[1] = CONFIG_RW_SIZE - regions.size[0]; - regions.num_regions = (regions.size[1] == 0) ? 1 : 2; - - return regions; -} - -int mpu_lock_rw_flash(void) -{ - /* Prevent execution from internal mapped RW flash */ - const uint16_t mpu_attr = MPU_ATTR_XN | MPU_ATTR_RW_RW | - MPU_ATTR_FLASH_MEMORY; - const struct mpu_rw_regions regions = mpu_get_rw_regions(); - int rv; - - rv = mpu_config_region(REGION_STORAGE, regions.addr[0], regions.size[0], - mpu_attr, 1); - if ((rv != EC_SUCCESS) || (regions.num_regions == 1)) - return rv; - - /* If this fails then it's impossible to represent with two regions. */ - return mpu_config_region(REGION_STORAGE2, regions.addr[1], - regions.size[1], mpu_attr, 1); -} -#endif /* !CONFIG_EXTERNAL_STORAGE */ - -#ifdef CONFIG_ROLLBACK_MPU_PROTECT -int mpu_lock_rollback(int lock) -{ - int rv; - int num_mpu_regions = mpu_num_regions(); - - const uint32_t rollback_region_start_address = - CONFIG_MAPPED_STORAGE_BASE + CONFIG_ROLLBACK_OFF; - const uint32_t rollback_region_total_size = CONFIG_ROLLBACK_SIZE; - const uint16_t mpu_attr = - MPU_ATTR_XN /* Execute never */ | - MPU_ATTR_NO_NO /* No access (privileged or unprivileged */; - - /* - * Originally rollback MPU support was added on Cortex-M7, which - * supports 16 MPU regions and has rollback region aligned in a way - * that we can use a single region. - */ - uint8_t rollback_mpu_region = REGION_ROLLBACK; - - if (rollback_mpu_region < num_mpu_regions) { - rv = mpu_config_region(rollback_mpu_region, - rollback_region_start_address, - rollback_region_total_size, mpu_attr, - lock); - return rv; - } - - /* - * If we get here, we can't use REGION_ROLLBACK because our MPU doesn't - * have enough regions. Instead, we choose unused MPU regions. - * - * Note that on the Cortex-M3, Cortex-M4, and Cortex-M7, the base - * address used for an MPU region must be aligned to the size of the - * region, so it's not possible to use a single region to protect the - * entire rollback flash on the STM32F412 (bloonchipper); we have to - * use two. - * - * See mpu_update_region for alignment details. - */ - - rollback_mpu_region = REGION_CHIP_RESERVED; - rv = mpu_config_region(rollback_mpu_region, - rollback_region_start_address, - rollback_region_total_size / 2, mpu_attr, lock); - if (rv != EC_SUCCESS) - return rv; - - rollback_mpu_region = REGION_CODE_RAM; - rv = mpu_config_region(rollback_mpu_region, - rollback_region_start_address + - (rollback_region_total_size / 2), - rollback_region_total_size / 2, mpu_attr, lock); - return rv; -} -#endif - -#ifdef CONFIG_CHIP_UNCACHED_REGION -/* Store temporarily the regions ranges to use them for the MPU configuration */ -#define REGION(_name, _flag, _start, _size) \ - static const uint32_t CONCAT2(_region_start_, _name) \ - __attribute__((unused, section(".unused"))) = _start; \ - static const uint32_t CONCAT2(_region_size_, _name) \ - __attribute__((unused, section(".unused"))) = _size; -#include "memory_regions.inc" -#undef REGION -#endif /* CONFIG_CHIP_UNCACHED_REGION */ - -int mpu_pre_init(void) -{ - int i; - int num_mpu_regions; - int rv; - - if (!has_mpu()) - return EC_ERROR_HW_INTERNAL; - - num_mpu_regions = mpu_num_regions(); - - /* Supports MPU with 8 or 16 unified regions */ - if (!mpu_is_unified() || - (num_mpu_regions != 8 && num_mpu_regions != 16)) - return EC_ERROR_UNIMPLEMENTED; - - mpu_disable(); - - for (i = 0; i < num_mpu_regions; ++i) { - /* - * Disable all regions. - * - * We use the smallest possible size (32 bytes), but it - * doesn't really matter since the regions are disabled. - * - * Use the fixed SRAM region base to ensure base is aligned - * to the region size. - */ - rv = mpu_update_region(i, CORTEX_M_SRAM_BASE, MPU_SIZE_BITS_MIN, - 0, 0, 0); - if (rv != EC_SUCCESS) - return rv; - } - - if (IS_ENABLED(CONFIG_ROLLBACK_MPU_PROTECT)) { - rv = mpu_lock_rollback(1); - if (rv != EC_SUCCESS) - return rv; - } - - if (IS_ENABLED(CONFIG_ARMV7M_CACHE)) { -#ifdef CONFIG_CHIP_UNCACHED_REGION - rv = mpu_config_region( - REGION_UNCACHED_RAM, - CONCAT2(_region_start_, CONFIG_CHIP_UNCACHED_REGION), - CONCAT2(_region_size_, CONFIG_CHIP_UNCACHED_REGION), - MPU_ATTR_XN | MPU_ATTR_RW_RW, 1); - if (rv != EC_SUCCESS) - return rv; - -#endif - } - - mpu_enable(); - - if (IS_ENABLED(CONFIG_ARMV7M_CACHE)) - cpu_enable_caches(); - - return EC_SUCCESS; -} diff --git a/core/cortex-m/panic-internal.h b/core/cortex-m/panic-internal.h deleted file mode 100644 index 1a58afa8a2..0000000000 --- a/core/cortex-m/panic-internal.h +++ /dev/null @@ -1,11 +0,0 @@ -/* Copyright 2018 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. - */ - -#ifndef __CROS_EC_PANIC_INTERNAL_H -#define __CROS_EC_PANIC_INTERNAL_H - -void exception_panic(void) __attribute__((naked)); - -#endif /* __CROS_EC_PANIC_INTERNAL_H */ diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c deleted file mode 100644 index da6900b1b9..0000000000 --- a/core/cortex-m/panic.c +++ /dev/null @@ -1,475 +0,0 @@ -/* Copyright 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 "common.h" -#include "console.h" -#include "cpu.h" -#include "host_command.h" -#include "panic.h" -#include "panic-internal.h" -#include "printf.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "uart.h" -#include "util.h" -#include "watchdog.h" - -/* Whether bus fault is ignored */ -static int bus_fault_ignored; - - -/* Panic data goes at the end of RAM. */ -static struct panic_data * const pdata_ptr = PANIC_DATA_PTR; - -/* Preceded by stack, rounded down to nearest 64-bit-aligned boundary */ -static const uint32_t pstack_addr = (CONFIG_RAM_BASE + CONFIG_RAM_SIZE - - sizeof(struct panic_data)) & ~7; - -/** - * Print the name and value of a register - * - * This is a convenient helper function for displaying a register value. - * It shows the register name in a 3 character field, followed by a colon. - * The register value is regs[index], and this is shown in hex. If regs is - * NULL, then we display spaces instead. - * - * After displaying the value, either a space or \n is displayed depending - * on the register number, so that (assuming the caller passes all 16 - * registers in sequence) we put 4 values per line like this - * - * r0 :0000000b r1 :00000047 r2 :60000000 r3 :200012b5 - * r4 :00000000 r5 :08004e64 r6 :08004e1c r7 :200012a8 - * r8 :08004e64 r9 :00000002 r10:00000000 r11:00000000 - * r12:0000003f sp :200009a0 lr :0800270d pc :0800351a - * - * @param regnum Register number to display (0-15) - * @param regs Pointer to array holding the registers, or NULL - * @param index Index into array where the register value is present - */ -static void print_reg(int regnum, const uint32_t *regs, int index) -{ - static const char regname[] = "r10r11r12sp lr pc "; - static char rname[3] = "r "; - const char *name; - - rname[1] = '0' + regnum; - name = regnum < 10 ? rname : ®name[(regnum - 10) * 3]; - panic_printf("%c%c%c:", name[0], name[1], name[2]); - if (regs) - panic_printf("%08x", regs[index]); - else - panic_puts(" "); - panic_puts((regnum & 3) == 3 ? "\n" : " "); -} - -/* - * Returns non-zero if the exception frame was created on the main stack, or - * zero if it's on the process stack. - * - * See B1.5.8 "Exception return behavior" of ARM DDI 0403D for details. - */ -static int32_t is_frame_in_handler_stack(const uint32_t exc_return) -{ - return (exc_return & 0xf) == 1 || (exc_return & 0xf) == 9; -} - -#ifdef CONFIG_DEBUG_EXCEPTIONS -/* Names for each of the bits in the cfs register, starting at bit 0 */ -static const char * const cfsr_name[32] = { - /* MMFSR */ - [0] = "Instruction access violation", - [1] = "Data access violation", - [3] = "Unstack from exception violation", - [4] = "Stack from exception violation", - - /* BFSR */ - [8] = "Instruction bus error", - [9] = "Precise data bus error", - [10] = "Imprecise data bus error", - [11] = "Unstack from exception bus fault", - [12] = "Stack from exception bus fault", - - /* UFSR */ - [16] = "Undefined instructions", - [17] = "Invalid state", - [18] = "Invalid PC", - [19] = "No coprocessor", - [24] = "Unaligned", - [25] = "Divide by 0", -}; - -/* Names for the first 5 bits in the DFSR */ -static const char * const dfsr_name[] = { - "Halt request", - "Breakpoint", - "Data watchpoint/trace", - "Vector catch", - "External debug request", -}; - -/** - * Helper function to display a separator after the previous item - * - * If items have been displayed already, we display a comma separator. - * In any case, the count of items displayed is incremeneted. - * - * @param count Number of items displayed so far (0 for none) - */ -static void do_separate(int *count) -{ - if (*count) - panic_puts(", "); - (*count)++; -} - -/** - * Show a textual representaton of the fault registers - * - * A list of detected faults is shown, with no trailing newline. - * - * @param cfsr Value of Configurable Fault Status - * @param hfsr Value of Hard Fault Status - * @param dfsr Value of Debug Fault Status - */ -static void show_fault(uint32_t cfsr, uint32_t hfsr, uint32_t dfsr) -{ - unsigned int upto; - int count = 0; - - for (upto = 0; upto < 32; upto++) { - if ((cfsr & BIT(upto)) && cfsr_name[upto]) { - do_separate(&count); - panic_puts(cfsr_name[upto]); - } - } - - if (hfsr & CPU_NVIC_HFSR_DEBUGEVT) { - do_separate(&count); - panic_puts("Debug event"); - } - if (hfsr & CPU_NVIC_HFSR_FORCED) { - do_separate(&count); - panic_puts("Forced hard fault"); - } - if (hfsr & CPU_NVIC_HFSR_VECTTBL) { - do_separate(&count); - panic_puts("Vector table bus fault"); - } - - for (upto = 0; upto < 5; upto++) { - if ((dfsr & BIT(upto))) { - do_separate(&count); - panic_puts(dfsr_name[upto]); - } - } -} - -/* - * Returns the size of the exception frame. - * - * See B1.5.7 "Stack alignment on exception entry" of ARM DDI 0403D for details. - * In short, the exception frame size can be either 0x20, 0x24, 0x68, or 0x6c - * depending on FPU context and padding for 8-byte alignment. - */ -static uint32_t get_exception_frame_size(const struct panic_data *pdata) -{ - uint32_t frame_size = 0; - - /* base exception frame */ - frame_size += 8 * sizeof(uint32_t); - - /* CPU uses xPSR[9] to indicate whether it padded the stack for - * alignment or not. */ - if (pdata->cm.frame[7] & BIT(9)) - frame_size += sizeof(uint32_t); - -#ifdef CONFIG_FPU - /* CPU uses EXC_RETURN[4] to indicate whether it stored extended - * frame for FPU or not. */ - if (!(pdata->cm.regs[11] & BIT(4))) - frame_size += 18 * sizeof(uint32_t); -#endif - - return frame_size; -} - -/* - * Returns the position of the process stack before the exception frame. - * It computes the size of the exception frame and adds it to psp. - * If the exception happened in the exception context, it returns psp as is. - */ -static uint32_t get_process_stack_position(const struct panic_data *pdata) -{ - uint32_t psp = pdata->cm.regs[0]; - - if (!is_frame_in_handler_stack(pdata->cm.regs[11])) - psp += get_exception_frame_size(pdata); - - return psp; -} - -/* - * Show extra information that might be useful to understand a panic() - * - * We show fault register information, including the fault address registers - * if valid. - */ -static void panic_show_extra(const struct panic_data *pdata) -{ - show_fault(pdata->cm.cfsr, pdata->cm.hfsr, pdata->cm.dfsr); - if (pdata->cm.cfsr & CPU_NVIC_CFSR_BFARVALID) - panic_printf(", bfar = %x", pdata->cm.bfar); - if (pdata->cm.cfsr & CPU_NVIC_CFSR_MFARVALID) - panic_printf(", mfar = %x", pdata->cm.mfar); - panic_printf("\ncfsr = %x, ", pdata->cm.cfsr); - panic_printf("shcsr = %x, ", pdata->cm.shcsr); - panic_printf("hfsr = %x, ", pdata->cm.hfsr); - panic_printf("dfsr = %x\n", pdata->cm.dfsr); -} - -/* - * Prints process stack contents stored above the exception frame. - */ -static void panic_show_process_stack(const struct panic_data *pdata) -{ - panic_printf("\n=========== Process Stack Contents ==========="); - if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) { - uint32_t psp = get_process_stack_position(pdata); - int i; - for (i = 0; i < 16; i++) { - if (psp + sizeof(uint32_t) > - CONFIG_RAM_BASE + CONFIG_RAM_SIZE) - break; - if (i % 4 == 0) - panic_printf("\n%08x:", psp); - panic_printf(" %08x", *(uint32_t *)psp); - psp += sizeof(uint32_t); - } - } else { - panic_printf("\nBad psp"); - } -} -#endif /* CONFIG_DEBUG_EXCEPTIONS */ - -/* - * Print panic data - */ -void panic_data_print(const struct panic_data *pdata) -{ - const uint32_t *lregs = pdata->cm.regs; - const uint32_t *sregs = NULL; - const int32_t in_handler = - is_frame_in_handler_stack(pdata->cm.regs[11]); - int i; - - if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) - sregs = pdata->cm.frame; - - panic_printf("\n=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n", - in_handler ? "HANDLER" : "PROCESS", - lregs[1] & 0xff, sregs ? sregs[7] : -1); - for (i = 0; i < 4; i++) - print_reg(i, sregs, i); - for (i = 4; i < 10; i++) - print_reg(i, lregs, i - 1); - print_reg(10, lregs, 9); - print_reg(11, lregs, 10); - print_reg(12, sregs, 4); - print_reg(13, lregs, in_handler ? 2 : 0); - print_reg(14, sregs, 5); - print_reg(15, sregs, 6); - -#ifdef CONFIG_DEBUG_EXCEPTIONS - panic_show_extra(pdata); -#endif -} - -void __keep report_panic(void) -{ - /* - * Don't need to get pointer via get_panic_data_write() - * because memory below pdata_ptr is stack now (see exception_panic()) - */ - struct panic_data *pdata = pdata_ptr; - uint32_t sp; - - pdata->magic = PANIC_DATA_MAGIC; - pdata->struct_size = sizeof(*pdata); - pdata->struct_version = 2; - pdata->arch = PANIC_ARCH_CORTEX_M; - pdata->flags = 0; - pdata->reserved = 0; - - /* Choose the right sp (psp or msp) based on EXC_RETURN value */ - sp = is_frame_in_handler_stack(pdata->cm.regs[11]) - ? pdata->cm.regs[2] : pdata->cm.regs[0]; - /* If stack is valid, copy exception frame to pdata */ - if ((sp & 3) == 0 && - sp >= CONFIG_RAM_BASE && - sp <= CONFIG_RAM_BASE + CONFIG_RAM_SIZE - 8 * sizeof(uint32_t)) { - const uint32_t *sregs = (const uint32_t *)sp; - int i; - - /* Skip r0-r3 and r12 registers if necessary */ - for (i = CORTEX_PANIC_FRAME_REGISTER_R0; - i <= CORTEX_PANIC_FRAME_REGISTER_R12; i++) - if (IS_ENABLED(CONFIG_PANIC_STRIP_GPR)) - pdata->cm.frame[i] = 0; - else - pdata->cm.frame[i] = sregs[i]; - - for (i = CORTEX_PANIC_FRAME_REGISTER_LR; - i < NUM_CORTEX_PANIC_FRAME_REGISTERS; i++) - pdata->cm.frame[i] = sregs[i]; - - pdata->flags |= PANIC_DATA_FLAG_FRAME_VALID; - } - - /* Save extra information */ - pdata->cm.cfsr = CPU_NVIC_CFSR; - pdata->cm.bfar = CPU_NVIC_BFAR; - pdata->cm.mfar = CPU_NVIC_MFAR; - pdata->cm.shcsr = CPU_NVIC_SHCSR; - pdata->cm.hfsr = CPU_NVIC_HFSR; - pdata->cm.dfsr = CPU_NVIC_DFSR; - -#ifdef CONFIG_UART_PAD_SWITCH - uart_reset_default_pad_panic(); -#endif - panic_data_print(pdata); -#ifdef CONFIG_DEBUG_EXCEPTIONS - panic_show_process_stack(pdata); - /* - * TODO(crosbug.com/p/23760): Dump main stack contents as well if the - * exception happened in a handler's context. - */ -#endif - - /* Make sure that all changes are saved into RAM */ - if (IS_ENABLED(CONFIG_ARMV7M_CACHE)) - cpu_clean_invalidate_dcache(); - - panic_reboot(); -} - -/** - * Default exception handler, which reports a panic. - * - * Declare this as a naked call so we can extract raw LR and IPSR values. - */ -void exception_panic(void) -{ - /* Save registers and branch directly to panic handler */ - asm volatile( - "mov r0, %[pregs]\n" - "mrs r1, psp\n" - "mrs r2, ipsr\n" - "mov r3, sp\n" -#ifdef CONFIG_PANIC_STRIP_GPR - /* - * Check if we are in exception. This is similar to - * in_interrupt_context(). Exception bits are 9 LSB, so - * we can perform left shift for 23 bits and check if result - * is 0 (lsls instruction is setting appropriate flags). - */ - "lsls r6, r2, #23\n" - /* - * If this is software panic (shift result == 0) then register - * r4 and r5 contain additional info about panic. - * Clear r6-r11 always and r4, r5 only if this is exception - * panic. To clear r4 and r5, 'movne' conditional instruction - * is used. It works only when flags contain information that - * result was != 0. Itt is pseudo instruction which is used - * to make sure we are using correct conditional instructions. - */ - "itt ne\n" - "movne r4, #0\n" - "movne r5, #0\n" - "mov r6, #0\n" - "mov r7, #0\n" - "mov r8, #0\n" - "mov r9, #0\n" - "mov r10, #0\n" - "mov r11, #0\n" -#endif - "stmia r0, {r1-r11, lr}\n" - "mov sp, %[pstack]\n" - "bl report_panic\n" : : - [pregs] "r" (pdata_ptr->cm.regs), - [pstack] "r" (pstack_addr) : - /* Constraints protecting these from being clobbered. - * Gcc should be using r0 & r12 for pregs and pstack. */ - "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", - "r10", "r11", "cc", "memory" - ); -} - -#ifdef CONFIG_SOFTWARE_PANIC -void software_panic(uint32_t reason, uint32_t info) -{ - __asm__("mov " STRINGIFY(SOFTWARE_PANIC_INFO_REG) ", %0\n" - "mov " STRINGIFY(SOFTWARE_PANIC_REASON_REG) ", %1\n" - "bl exception_panic\n" - : : "r"(info), "r"(reason)); - __builtin_unreachable(); -} - -void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception) -{ - struct panic_data * const pdata = get_panic_data_write(); - uint32_t *lregs; - - lregs = pdata->cm.regs; - - /* Setup panic data structure */ - memset(pdata, 0, CONFIG_PANIC_DATA_SIZE); - pdata->magic = PANIC_DATA_MAGIC; - pdata->struct_size = CONFIG_PANIC_DATA_SIZE; - pdata->struct_version = 2; - pdata->arch = PANIC_ARCH_CORTEX_M; - - /* Log panic cause */ - lregs[1] = exception; - lregs[3] = reason; - lregs[4] = info; -} - -void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception) -{ - struct panic_data * const pdata = panic_get_data(); - uint32_t *lregs; - - if (pdata && pdata->struct_version == 2) { - lregs = pdata->cm.regs; - *exception = lregs[1]; - *reason = lregs[3]; - *info = lregs[4]; - } else { - *exception = *reason = *info = 0; - } -} -#endif - -void bus_fault_handler(void) -{ - if (!bus_fault_ignored) - exception_panic(); -} - -void ignore_bus_fault(int ignored) -{ - if (IS_ENABLED(CHIP_FAMILY_STM32H7)) { - if (ignored == 0) - asm volatile("dsb; isb"); - } - - /* - * Flash code might call this before cpu_init(), - * ensure that the bus faults really go through our handler. - */ - CPU_NVIC_SHCSR |= CPU_NVIC_SHCSR_BUSFAULTENA; - bus_fault_ignored = ignored; -} diff --git a/core/cortex-m/switch.S b/core/cortex-m/switch.S deleted file mode 100644 index f56c5e4c74..0000000000 --- a/core/cortex-m/switch.S +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright 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. - * - * 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 the 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 - * - * if using the FPU, then to store FPU context, add FP regs to the stack. in - * this case the exception frame by default contains: - * r0, r1, r2, r3, r12, lr, pc, psr, - * s0 - s15, FPSCR, +1 word for 64-bit alignment - * then in addition we store the following registers: - * r4, r5, r6, r7, r8, r9, r10, r11 - * s16 - s31 (stored iff FP was used by the task (see EXC_RETURN[4])) - * note that for the context switch to know if the next task has the extra FP - * regs on the stack or not, we make use of the least significant bit of the - * stack pointer. lsb of stack pointer is 1 if task has FP regs on stack, and - * 0 otherwise. - * - */ -.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-r11 in the task stack - -#ifdef CONFIG_FPU - tst lr, #(1<<4) @ test EXC_RETURN[4] for old task - itt eq @ if EXC_RETURN[4] is zero, add FP regs to stack - vstmdbeq r3!, {s16-s31}@ save additional FP s16-s31 in the task stack. - @ if using lazy stacking, this will trigger saving - @ s0-s15 in the reserved stack space. - orreq r3, #1 @ set lsb of old stack pointer high to represent this - @ task uses FPU. note stack pointer should be 64-bit - @ aligned, so using this bit should be safe. - - tst r2, #1 @ test lsb of next stack pointer - ittte ne @ if lsb is 1, then next task has FP regs on stack - bicne r2, #1 @ clear lsb of new stack pointer - bicne lr, #(1<<4) @ clear EXC_RETURN[4] for next task - vldmiane r2!, {s16-s31}@ restore s16-s31 for the next task context - orreq lr, #(1<<4) @ else if new stack doesn't use FP, set EXC_RETURN[4] -#endif - - ldmia r2!, {r4-r11} @ restore r4-r11 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. r0 is a pointer to task_stack_ready, which is - * set to 1 after the task stack is set up. - */ -.global __task_start -.thumb_func -__task_start: - ldr r2,=scratchpad @ area used as thread stack for the first switch - mov r3, #2 @ use : priv. mode / thread stack / no floating point - @ setting FP to unused here means first context switch - @ will not store FP regs - add r2, #17*4 @ put the pointer at the top of the stack - mov r1, #0 @ __Schedule parameter : re-schedule nothing - msr psp, r2 @ setup a thread stack up to the first context switch - mov r2, #1 - isb @ ensure the write is done - msr control, r3 - mov r3, r0 - mov r0, #0 @ __Schedule parameter : de-schedule nothing - isb @ ensure the write is done - str r2, [r3] @ Task scheduling is now active - 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 deleted file mode 100644 index bf0eb5b397..0000000000 --- a/core/cortex-m/task.c +++ /dev/null @@ -1,1088 +0,0 @@ -/* Copyright 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. - */ - -/* Task scheduling / events module for Chrome EC operating system */ - -#include "atomic.h" -#include "common.h" -#include "console.h" -#include "cpu.h" -#include "link_defs.h" -#include "panic.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -typedef union { - struct { - /* - * Note that sp must be the first element in the task struct - * for __switchto() to work. - */ - uint32_t sp; /* Saved stack pointer for context switch */ - uint32_t events; /* Bitmaps of received events */ - uint64_t runtime; /* Time spent in task */ - uint32_t *stack; /* Start of stack */ - }; -} task_; - -/* Value to store in unused stack */ -#define STACK_UNUSED_VALUE 0xdeadd00d - -/* declare task routine prototypes */ -#define TASK(n, r, d, s) void r(void *); -void __idle(void); -CONFIG_TASK_LIST -CONFIG_TEST_TASK_LIST -CONFIG_CTS_TASK_LIST -#undef TASK - -/* Task names for easier debugging */ -#define TASK(n, r, d, s) #n, -static const char * const task_names[] = { - "<< idle >>", - CONFIG_TASK_LIST - CONFIG_TEST_TASK_LIST - CONFIG_CTS_TASK_LIST -}; -#undef TASK - -#ifdef CONFIG_TASK_PROFILING -static uint64_t task_start_time; /* Time task scheduling started */ -/* - * We only keep 32-bit values for exception start/end time, to avoid - * accounting errors when we service interrupt when the timer wraps around. - */ -static uint32_t exc_start_time; /* Time of task->exception transition */ -static uint32_t exc_end_time; /* Time of exception->task transition */ -static uint64_t exc_total_time; /* Total time in exceptions */ -static uint32_t svc_calls; /* Number of service calls */ -static uint32_t task_switches; /* Number of times active task changed */ -static uint32_t irq_dist[CONFIG_IRQ_COUNT]; /* Distribution of IRQ calls */ -#endif - -extern void __switchto(task_ *from, task_ *to); -extern int __task_start(int *task_stack_ready); - -#ifndef CONFIG_LOW_POWER_IDLE -/* Idle task. Executed when no tasks are ready to be scheduled. */ -void __idle(void) -{ - while (1) { -#ifdef CHIP_NPCX - - /* - * Using host access to make sure M4 core clock will - * return when the eSPI accesses the Host modules if - * CSAE bit is set. Please notice this symptom only - * occurs at npcx5. - */ -#if defined(CHIP_FAMILY_NPCX5) && defined(CONFIG_HOSTCMD_ESPI) - /* Enable Host access wakeup */ - SET_BIT(NPCX_WKEN(MIWU_TABLE_0, MIWU_GROUP_5), 6); -#endif - - /* - * TODO (ML): A interrupt that occurs shortly before entering - * idle mode starts getting services while the Core transitions - * into idle mode. The results in a hard fault when the Core, - * shortly therefore, resumes execution on exiting idle mode. - * Workaround: Replace the idle function with the followings - */ - asm ( - "cpsid i\n" /* Disable interrupt */ - "push {r0-r5}\n" /* Save needed registers */ - "wfi\n" /* Wait for int to enter idle */ - "ldm %0, {r0-r5}\n" /* Add a delay after WFI */ - "pop {r0-r5}\n" /* Restore regs before enabling ints */ - "isb\n" /* Flush the cpu pipeline */ - "cpsie i\n" :: "r" (0x100A8000) /* Enable interrupts */ - ); -#else - /* - * Wait for the next irq event. This stops the CPU clock - * (sleep / deep sleep, depending on chip config). - */ - asm("wfi"); -#endif - } -} -#endif /* !CONFIG_LOW_POWER_IDLE */ - -static void task_exit_trap(void) -{ - int i = task_get_current(); - cprints(CC_TASK, "Task %d (%s) exited!", i, task_names[i]); - /* Exited tasks simply sleep forever */ - while (1) - task_wait_event(-1); -} - -/* Startup parameters for all tasks. */ -#define TASK(n, r, d, s) { \ - .r0 = (uint32_t)d, \ - .pc = (uint32_t)r, \ - .stack_size = s, \ -}, -static const struct { - uint32_t r0; - uint32_t pc; - uint16_t stack_size; -} tasks_init[] = { - TASK(IDLE, __idle, 0, IDLE_TASK_STACK_SIZE) - CONFIG_TASK_LIST - CONFIG_TEST_TASK_LIST - CONFIG_CTS_TASK_LIST -}; -#undef TASK - -/* Contexts for all tasks */ -static task_ tasks[TASK_ID_COUNT]; - -/* Reset constants and state for all tasks */ -#define TASK_RESET_SUPPORTED BIT(31) -#define TASK_RESET_LOCK BIT(30) -#define TASK_RESET_STATE_MASK (TASK_RESET_SUPPORTED | TASK_RESET_LOCK) -#define TASK_RESET_WAITERS_MASK ~TASK_RESET_STATE_MASK -#define TASK_RESET_UNSUPPORTED 0 -#define TASK_RESET_STATE_LOCKED (TASK_RESET_SUPPORTED | TASK_RESET_LOCK) -#define TASK_RESET_STATE_UNLOCKED TASK_RESET_SUPPORTED - -#ifdef CONFIG_TASK_RESET_LIST -#define ENABLE_RESET(n) \ - [TASK_ID_##n] = TASK_RESET_SUPPORTED, -static uint32_t task_reset_state[TASK_ID_COUNT] = { -#ifdef CONFIG_TASK_RESET_LIST - CONFIG_TASK_RESET_LIST -#endif -}; -#undef ENABLE_RESET -#endif /* CONFIG_TASK_RESET_LIST */ - -/* Validity checks about static task invariants */ -BUILD_ASSERT(TASK_ID_COUNT <= sizeof(unsigned) * 8); -BUILD_ASSERT(TASK_ID_COUNT < (1 << (sizeof(task_id_t) * 8))); -BUILD_ASSERT(BIT(TASK_ID_COUNT) < TASK_RESET_LOCK); - -/* Stacks for all tasks */ -#define TASK(n, r, d, s) + s -uint8_t task_stacks[0 - TASK(IDLE, __idle, 0, IDLE_TASK_STACK_SIZE) - CONFIG_TASK_LIST - CONFIG_TEST_TASK_LIST - CONFIG_CTS_TASK_LIST -] __aligned(8); - -#undef TASK - -/* Reserve space to discard context on first context switch. */ -uint32_t scratchpad[17]; - -static task_ *current_task = (task_ *)scratchpad; - -/* - * Should IRQs chain to svc_handler()? This should be set if either of the - * following is true: - * - * 1) Task scheduling has started, and task profiling is enabled. Task - * profiling does its tracking in svc_handler(). - * - * 2) An event was set by an interrupt; this could result in a higher-priority - * task unblocking. After checking for a task switch, svc_handler() will clear - * the flag (unless profiling is also enabled; then the flag remains set). - */ -static int need_resched_or_profiling; - -/* - * Bitmap of all tasks ready to be run. - * - * Start off with only the hooks task marked as ready such that all the modules - * can do their init within a task switching context. The hooks task will then - * make a call to enable all tasks. - */ -static uint32_t tasks_ready = BIT(TASK_ID_HOOKS); -/* - * Initially allow only the HOOKS and IDLE task to run, regardless of ready - * status, in order for HOOK_INIT to complete before other tasks. - * task_enable_all_tasks() will open the flood gates. - */ -static uint32_t tasks_enabled = BIT(TASK_ID_HOOKS) | BIT(TASK_ID_IDLE); - -static int start_called; /* Has task swapping started */ - -static inline task_ *__task_id_to_ptr(task_id_t id) -{ - return tasks + id; -} - -void interrupt_disable(void) -{ - asm("cpsid i"); -} - -void interrupt_enable(void) -{ - asm("cpsie i"); -} - -inline int is_interrupt_enabled(void) -{ - int primask; - - /* Interrupts are enabled when PRIMASK bit is 0 */ - asm("mrs %0, primask":"=r"(primask)); - - return !(primask & 0x1); -} - -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; -} - -#ifdef CONFIG_TASK_PROFILING -static inline int get_interrupt_context(void) -{ - int ret; - asm("mrs %0, ipsr \n":"=r"(ret)); /* read exception number */ - return ret & 0x1ff; /* exception bits are the 9 LSB */ -} -#endif - -task_id_t task_get_current(void) -{ -#ifdef CONFIG_DEBUG_BRINGUP - /* If we haven't done a context switch then our task ID isn't valid */ - ASSERT(current_task != (task_ *)scratchpad); -#endif - return current_task - tasks; -} - -uint32_t *task_get_event_bitmap(task_id_t tskid) -{ - task_ *tsk = __task_id_to_ptr(tskid); - return &tsk->events; -} - -int task_start_called(void) -{ - return start_called; -} - -/** - * Scheduling system call - */ -void svc_handler(int desched, task_id_t resched) -{ - task_ *current, *next; -#ifdef CONFIG_TASK_PROFILING - int exc = get_interrupt_context(); - uint32_t t; -#endif - - /* - * Push the priority to -1 until the return, to avoid being - * interrupted. - */ - asm volatile("cpsid f\n" - "isb\n"); - -#ifdef CONFIG_TASK_PROFILING - /* - * SVCall isn't triggered via DECLARE_IRQ(), so it needs to track its - * start time explicitly. - */ - if (exc == 0xb) { - exc_start_time = get_time().le.lo; - svc_calls++; - } -#endif - - current = current_task; - -#ifdef CONFIG_DEBUG_STACK_OVERFLOW - if (*current->stack != STACK_UNUSED_VALUE) { - panic_printf("\n\nStack overflow in %s task!\n", - task_names[current - tasks]); -#ifdef CONFIG_SOFTWARE_PANIC - software_panic(PANIC_SW_STACK_OVERFLOW, current - tasks); -#endif - } -#endif - - if (desched && !current->events) { - /* - * Remove our own ready bit (current - tasks is same as - * task_get_current()) - */ - tasks_ready &= ~(1 << (current - tasks)); - } - ASSERT(resched <= TASK_ID_COUNT); - tasks_ready |= 1 << resched; - - ASSERT(tasks_ready & tasks_enabled); - next = __task_id_to_ptr(__fls(tasks_ready & tasks_enabled)); - -#ifdef CONFIG_TASK_PROFILING - /* Track time in interrupts */ - t = get_time().le.lo; - exc_total_time += (t - exc_start_time); - - /* - * Bill the current task for time between the end of the last interrupt - * and the start of this one. - */ - current->runtime += (exc_start_time - exc_end_time); - exc_end_time = t; -#else - /* - * Don't chain here from interrupts until the next time an interrupt - * sets an event. - */ - need_resched_or_profiling = 0; -#endif - - /* Nothing to do */ - if (next == current) - return; - - /* Switch to new task */ -#ifdef CONFIG_TASK_PROFILING - task_switches++; -#endif - current_task = next; - __switchto(current, next); -} - -void __schedule(int desched, int resched) -{ - register int p0 asm("r0") = desched; - register int p1 asm("r1") = resched; - - asm("svc 0"::"r"(p0),"r"(p1)); -} - -#ifdef CONFIG_TASK_PROFILING -void __keep task_start_irq_handler(void *excep_return) -{ - /* - * Get time before checking depth, in case this handler is - * pre-empted. - */ - uint32_t t = get_time().le.lo; - int irq = get_interrupt_context() - 16; - - /* - * Track IRQ distribution. No need for atomic add, because an IRQ - * can't pre-empt itself. - */ - if (irq < ARRAY_SIZE(irq_dist)) - irq_dist[irq]++; - - /* - * Continue iff a rescheduling event happened or profiling is active, - * and we are not called from another exception (this must match the - * logic for when we chain to svc_handler() below). - */ - if (!need_resched_or_profiling || (((uint32_t)excep_return & 0xf) == 1)) - return; - - exc_start_time = t; -} -#endif - -void __keep task_resched_if_needed(void *excep_return) -{ - /* - * Continue iff a rescheduling event happened or profiling is active, - * and we are not called from another exception. - */ - if (!need_resched_or_profiling || (((uint32_t)excep_return & 0xf) == 1)) - return; - - svc_handler(0, 0); -} - -static uint32_t __wait_evt(int timeout_us, task_id_t resched) -{ - task_ *tsk = current_task; - task_id_t me = tsk - tasks; - uint32_t evt; - int ret __attribute__((unused)); - - /* - * Scheduling task when interrupts are disabled will result in Forced - * Hard Fault because: - * - Disabling interrupt using 'cpsid i' also disables SVCall handler - * (because it has configurable priority) - * - Escalation to Hard Fault (also known as 'priority escalation') - * occurs when handler for that fault is not enabled - */ - ASSERT(is_interrupt_enabled()); - 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_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); - /* Ensure timer event is clear, we no longer care about it */ - atomic_clear_bits(&tsk->events, TASK_EVENT_TIMER); - } - return evt; -} - -uint32_t task_set_event(task_id_t tskid, uint32_t event) -{ - task_ *receiver = __task_id_to_ptr(tskid); - ASSERT(receiver); - - /* Set the event bit in the receiver message bitmap */ - atomic_or(&receiver->events, event); - - /* Re-schedule if priorities have changed */ - if (in_interrupt_context() || !is_interrupt_enabled()) { - /* The receiver might run again */ - atomic_or(&tasks_ready, 1 << tskid); -#ifndef CONFIG_TASK_PROFILING - if (start_called) - need_resched_or_profiling = 1; -#endif - } else { - __schedule(0, tskid); - } - - return 0; -} - -uint32_t task_wait_event(int timeout_us) -{ - return __wait_evt(timeout_us, TASK_ID_IDLE); -} - -uint32_t task_wait_event_mask(uint32_t event_mask, int timeout_us) -{ - uint64_t deadline = get_time().val + timeout_us; - uint32_t events = 0; - int time_remaining_us = timeout_us; - - /* Add the timer event to the mask so we can indicate a timeout */ - event_mask |= TASK_EVENT_TIMER; - - while (!(events & event_mask)) { - /* Collect events to re-post later */ - events |= __wait_evt(time_remaining_us, TASK_ID_IDLE); - - time_remaining_us = deadline - get_time().val; - if (timeout_us > 0 && time_remaining_us <= 0) { - /* Ensure we return a TIMER event if we timeout */ - events |= TASK_EVENT_TIMER; - break; - } - } - - /* Re-post any other events collected */ - if (events & ~event_mask) - atomic_or(¤t_task->events, events & ~event_mask); - - return events & event_mask; -} - -void task_enable_all_tasks(void) -{ - /* Mark all tasks as ready and able to run. */ - tasks_ready = tasks_enabled = BIT(TASK_ID_COUNT) - 1; - /* Reschedule the highest priority task. */ - if (is_interrupt_enabled()) - __schedule(0, 0); -} - -void task_enable_task(task_id_t tskid) -{ - atomic_or(&tasks_enabled, BIT(tskid)); -} - -void task_disable_task(task_id_t tskid) -{ - atomic_clear_bits(&tasks_enabled, BIT(tskid)); - - if (!in_interrupt_context() && is_interrupt_enabled() && - tskid == task_get_current()) - __schedule(0, 0); -} - -void task_enable_irq(int irq) -{ - CPU_NVIC_EN(irq / 32) = 1 << (irq % 32); -} - -void __keep task_disable_irq(int irq) -{ - CPU_NVIC_DIS(irq / 32) = 1 << (irq % 32); -} - -void task_clear_pending_irq(int irq) -{ - CPU_NVIC_UNPEND(irq / 32) = 1 << (irq % 32); -} - -void task_trigger_irq(int irq) -{ - CPU_NVIC_SWTRIG = irq; -} - -static uint32_t init_task_context(task_id_t id) -{ - uint32_t *sp; - /* Stack size in words */ - uint32_t ssize = tasks_init[id].stack_size / 4; - - /* - * Update stack used by first frame: 8 words for the normal - * stack, plus 8 for R4-R11. Even if using FPU, the first frame - * does not store FP regs. - */ - sp = tasks[id].stack + ssize - 16; - tasks[id].sp = (uint32_t)sp; - - /* Initial context on stack (see __switchto()) */ - sp[8] = tasks_init[id].r0; /* r0 */ - sp[13] = (uint32_t)task_exit_trap; /* lr */ - sp[14] = tasks_init[id].pc; /* pc */ - sp[15] = 0x01000000; /* psr */ - - /* Fill unused stack; also used to detect stack overflow. */ - for (sp = tasks[id].stack; sp < (uint32_t *)tasks[id].sp; sp++) - *sp = STACK_UNUSED_VALUE; - - return ssize; -} - -#ifdef CONFIG_TASK_RESET_LIST - -/* - * Re-initializes a task stack to its initial state, and marks it ready. - * The task reset lock must be held prior to calling this function. - */ -static void do_task_reset(task_id_t id) -{ - interrupt_disable(); - init_task_context(id); - tasks_ready |= 1 << id; - /* TODO: Clear all pending events? */ - interrupt_enable(); -} - -/* We can't pass a parameter to a deferred call. Use this instead. */ -/* Mask of task IDs waiting to be reset. */ -static uint32_t deferred_reset_task_ids; - -/* Tasks may call this function if they want to reset themselves. */ -static void deferred_task_reset(void) -{ - while (deferred_reset_task_ids) { - task_id_t reset_id = __fls(deferred_reset_task_ids); - - atomic_clear_bits(&deferred_reset_task_ids, 1 << reset_id); - do_task_reset(reset_id); - } -} -DECLARE_DEFERRED(deferred_task_reset); - -/* - * Helper for updating task_reset state atomically. Checks the current state, - * and if it matches if_value, updates the state to new_value, and returns - * TRUE. - */ -static int update_reset_state(uint32_t *state, - uint32_t if_value, - uint32_t to_value) -{ - int update; - - interrupt_disable(); - update = *state == if_value; - if (update) - *state = to_value; - interrupt_enable(); - - return update; -} - -/* - * Helper that acquires the reset lock iff it is not currently held. - * Returns TRUE if the lock was acquired. - */ -static inline int try_acquire_reset_lock(uint32_t *state) -{ - return update_reset_state(state, - /* if the lock is not held */ - TASK_RESET_STATE_UNLOCKED, - /* acquire it */ - TASK_RESET_STATE_LOCKED); -} - -/* - * Helper that releases the reset lock iff it is currently held, and there - * are no pending resets. Returns TRUE if the lock was released. - */ -static inline int try_release_reset_lock(uint32_t *state) -{ - return update_reset_state(state, - /* if the lock is held, with no waiters */ - TASK_RESET_STATE_LOCKED, - /* release it */ - TASK_RESET_STATE_UNLOCKED); -} - -/* - * Helper to cause the current task to sleep indefinitely; useful if the - * calling task just needs to block until it is reset. - */ -static inline void sleep_forever(void) -{ - while (1) - usleep(-1); -} - -void task_enable_resets(void) -{ - task_id_t id = task_get_current(); - uint32_t *state = &task_reset_state[id]; - - if (*state == TASK_RESET_UNSUPPORTED) { - cprints(CC_TASK, - "%s called from non-resettable task, id: %d", - __func__, id); - return; - } - - /* - * A correctly written resettable task will only call this function - * if resets are currently disabled; this implies that this task - * holds the reset lock. - */ - - if (*state == TASK_RESET_STATE_UNLOCKED) { - cprints(CC_TASK, - "%s called, but resets already enabled, id: %d", - __func__, id); - return; - } - - /* - * Attempt to release the lock. If we cannot, it means there are tasks - * waiting for a reset. - */ - if (try_release_reset_lock(state)) - return; - - /* People are waiting for us to reset; schedule a reset. */ - atomic_or(&deferred_reset_task_ids, 1 << id); - /* - * This will always trigger a deferred call after our new ID was - * written. If the hook call is currently executing, it will run - * again. - */ - hook_call_deferred(&deferred_task_reset_data, 0); - /* Wait to be reset. */ - sleep_forever(); -} - -void task_disable_resets(void) -{ - task_id_t id = task_get_current(); - uint32_t *state = &task_reset_state[id]; - - if (*state == TASK_RESET_UNSUPPORTED) { - cprints(CC_TASK, - "%s called from non-resettable task, id %d", - __func__, id); - return; - } - - /* - * A correctly written resettable task will only call this function - * if resets are currently enabled; this implies that this task does - * not hold the reset lock. - */ - - if (try_acquire_reset_lock(state)) - return; - - /* - * If we can't acquire the lock, we are about to be reset by another - * task. - */ - sleep_forever(); -} - -int task_reset_cleanup(void) -{ - task_id_t id = task_get_current(); - uint32_t *state = &task_reset_state[id]; - - /* - * If the task has never started before, state will be - * TASK_RESET_ENABLED. - * - * If the task was reset, the TASK_RESET_LOCK bit will be set, and - * there may additionally be bits representing tasks we must notify - * that we have reset. - */ - - /* - * Only this task can unset the lock bit so we can read this safely, - * even though other tasks may be modifying the state to add themselves - * as waiters. - */ - int cleanup_req = *state & TASK_RESET_LOCK; - - /* - * Attempt to release the lock. We can only do this when there are no - * tasks waiting to be notified that we have been reset, so we loop - * until no tasks are waiting. - * - * Other tasks may still be trying to reset us at this point; if they - * do, they will add themselves to the list of tasks we must notify. We - * will simply notify them (multiple times if necessary) until we are - * free to unlock. - */ - if (cleanup_req) { - while (!try_release_reset_lock(state)) { - /* Find the first waiter to notify. */ - task_id_t notify_id = __fls( - *state & TASK_RESET_WAITERS_MASK); - /* - * Remove the task from waiters first, so that - * when it wakes after being notified, it is in - * a consistent state (it should not be waiting - * to be notified and running). - * After being notified, the task may try to - * reset us again; if it does, it will just add - * itself back to the list of tasks to notify, - * and we will notify it again. - */ - atomic_clear_bits(state, 1 << notify_id); - /* - * Skip any invalid ids set by tasks that - * requested a non-blocking reset. - */ - if (notify_id < TASK_ID_COUNT) - task_set_event(notify_id, - TASK_EVENT_RESET_DONE); - } - } - - return cleanup_req; -} - -int task_reset(task_id_t id, int wait) -{ - task_id_t current = task_get_current(); - uint32_t *state = &task_reset_state[id]; - uint32_t waiter_id; - int resets_disabled; - - if (id == current) - return EC_ERROR_INVAL; - - /* - * This value is only set at compile time, and will never be modified. - */ - if (*state == TASK_RESET_UNSUPPORTED) - return EC_ERROR_INVAL; - - /* - * If we are not blocking for reset, we use an invalid task id to notify - * the task that _someone_ wanted it to reset, but didn't want to be - * notified when the reset is complete. - */ - waiter_id = 1 << (wait ? current : TASK_ID_COUNT); - - /* - * Try and take the lock. If we can't have it, just notify the task we - * tried; it will reset itself when it next tries to release the lock. - */ - interrupt_disable(); - resets_disabled = *state & TASK_RESET_LOCK; - if (resets_disabled) - *state |= waiter_id; - else - *state |= TASK_RESET_LOCK; - interrupt_enable(); - - if (!resets_disabled) { - /* We got the lock, do the reset immediately. */ - do_task_reset(id); - } else if (wait) { - /* - * We couldn't get the lock, and have been asked to block for - * reset. We have asked the task to reset itself; it will notify - * us when it has. - */ - task_wait_event_mask(TASK_EVENT_RESET_DONE, -1); - } - - return EC_SUCCESS; -} - -#endif /* CONFIG_TASK_RESET_LIST */ - -/* - * Initialize IRQs 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 */ - int exc_calls = __irqprio_end - __irqprio; - int i; - - /* Mask and clear all pending interrupts */ - for (i = 0; i < 5; i++) { - CPU_NVIC_DIS(i) = 0xffffffff; - CPU_NVIC_UNPEND(i) = 0xffffffff; - } - - /* - * Re-enable global interrupts in case they're disabled. On a reboot, - * they're already enabled; if we've jumped here from another image, - * they're not. - */ - interrupt_enable(); - - /* Set priorities */ - for (i = 0; i < exc_calls; i++) { - cpu_set_interrupt_priority(__irqprio[i].irq, - __irqprio[i].priority); - } -} - -void mutex_lock(struct mutex *mtx) -{ - uint32_t value; - uint32_t id; - - /* - * mutex_lock() must not be used in interrupt context (because we wait - * if there is contention). - */ - ASSERT(!in_interrupt_context()); - - /* - * Task ID is not valid before task_start() (since current_task is - * scratchpad), and no need for mutex locking before task switching has - * begun. - */ - if (!task_start_called()) - return; - - id = 1 << task_get_current(); - - 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" (2) : "cc"); - /* - * "value" is equals to 1 if the store conditional failed, - * 2 if somebody else owns the mutex, 0 else. - */ - if (value == 2) - /* Contention on the mutex */ - task_wait_event_mask(TASK_EVENT_MUTEX, 0); - } while (value); - - atomic_clear_bits(&mtx->waiters, id); -} - -void mutex_unlock(struct mutex *mtx) -{ - uint32_t waiters; - task_ *tsk = current_task; - - /* - * Add a critical section to keep the unlock and the snapshotting of - * waiters atomic in case a task switching occurs between them. - */ - interrupt_disable(); - waiters = mtx->waiters; - mtx->lock = 0; - interrupt_enable(); - - while (waiters) { - task_id_t id = __fls(waiters); - waiters &= ~BIT(id); - - /* Somebody is waiting on the mutex */ - task_set_event(id, TASK_EVENT_MUTEX); - } - - /* Ensure no event is remaining from mutex wake-up */ - atomic_clear_bits(&tsk->events, TASK_EVENT_MUTEX); -} - -void task_print_list(void) -{ - int i; - - ccputs("Task Ready Name Events Time (s) StkUsed\n"); - - for (i = 0; i < TASK_ID_COUNT; i++) { - char is_ready = (tasks_ready & (1<<i)) ? 'R' : ' '; - uint32_t *sp; - - int stackused = tasks_init[i].stack_size; - - for (sp = tasks[i].stack; - sp < (uint32_t *)tasks[i].sp && *sp == STACK_UNUSED_VALUE; - sp++) - stackused -= sizeof(uint32_t); - - ccprintf("%4d %c %-16s %08x %11.6lld %3d/%3d\n", i, is_ready, - task_names[i], tasks[i].events, tasks[i].runtime, - stackused, tasks_init[i].stack_size); - cflush(); - } -} - -int command_task_info(int argc, char **argv) -{ -#ifdef CONFIG_TASK_PROFILING - int total = 0; - int i; -#endif - - task_print_list(); - -#ifdef CONFIG_TASK_PROFILING - ccputs("IRQ counts by type:\n"); - cflush(); - for (i = 0; i < ARRAY_SIZE(irq_dist); i++) { - if (irq_dist[i]) { - ccprintf("%4d %8d\n", i, irq_dist[i]); - total += irq_dist[i]; - } - } - ccprintf("Service calls: %11d\n", svc_calls); - ccprintf("Total exceptions: %11d\n", total + svc_calls); - ccprintf("Task switches: %11d\n", task_switches); - ccprintf("Task switching started: %11.6lld s\n", task_start_time); - ccprintf("Time in tasks: %11.6lld s\n", - get_time().val - task_start_time); - ccprintf("Time in exceptions: %11.6lld s\n", exc_total_time); -#endif - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(taskinfo, command_task_info, - NULL, - "Print task info"); - -#ifdef CONFIG_CMD_TASKREADY -static int command_task_ready(int argc, char **argv) -{ - if (argc < 2) { - ccprintf("tasks_ready: 0x%08x\n", tasks_ready); - } else { - tasks_ready = strtoi(argv[1], NULL, 16); - ccprintf("Setting tasks_ready to 0x%08x\n", tasks_ready); - __schedule(0, 0); - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(taskready, command_task_ready, - "[setmask]", - "Print/set ready tasks"); -#endif - -void task_pre_init(void) -{ - uint32_t *stack_next = (uint32_t *)task_stacks; - int i; - - /* Fill the task memory with initial values */ - for (i = 0; i < TASK_ID_COUNT; i++) { - tasks[i].stack = stack_next; - stack_next += init_task_context(i); - } - - /* - * Fill in guard value in scratchpad to prevent stack overflow - * detection failure on the first context switch. This works because - * the first word in the scratchpad is where the switcher will store - * sp, so it's ok to blow away. - */ - ((task_ *)scratchpad)->stack = (uint32_t *)scratchpad; - *(uint32_t *)scratchpad = STACK_UNUSED_VALUE; - - /* Initialize IRQs */ - __nvic_init_irqs(); -} - -void task_clear_fp_used(void) -{ - int ctrl; - - /* Clear the CONTROL.FPCA bit, which represents FP context active. */ - asm volatile("mrs %0, control" : "=r"(ctrl)); - ctrl &= ~0x4; - asm volatile("msr control, %0" : : "r"(ctrl)); - - /* Flush pipeline before returning. */ - asm volatile("isb"); -} - -int task_start(void) -{ -#ifdef CONFIG_TASK_PROFILING - timestamp_t t = get_time(); - - task_start_time = t.val; - exc_end_time = t.le.lo; -#endif - start_called = 1; - - return __task_start(&need_resched_or_profiling); -} - -#ifdef CONFIG_CMD_TASK_RESET -static int command_task_reset(int argc, char **argv) -{ - task_id_t id; - char *e; - - if (argc == 2) { - id = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - ccprintf("Resetting task %d\n", id); - return task_reset(id, 1); - } - - return EC_ERROR_PARAM_COUNT; -} -DECLARE_CONSOLE_COMMAND(taskreset, command_task_reset, - "task_id", - "Reset a task"); -#endif /* CONFIG_CMD_TASK_RESET */ diff --git a/core/cortex-m/uldivmod.S b/core/cortex-m/uldivmod.S deleted file mode 120000 index 7047a8c5d4..0000000000 --- a/core/cortex-m/uldivmod.S +++ /dev/null @@ -1 +0,0 @@ -../../third_party/libaeabi-cortexm0/core/cortex-m/uldivmod.S
\ No newline at end of file diff --git a/core/cortex-m/vecttable.c b/core/cortex-m/vecttable.c deleted file mode 100644 index 10b4b22422..0000000000 --- a/core/cortex-m/vecttable.c +++ /dev/null @@ -1,400 +0,0 @@ -/* Copyright 2018 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 vector table - */ - -#ifndef ___INIT -#define ___INIT -#include "config.h" -#include <task.h> -#endif - -typedef void (*func)(void); - -#ifndef PASS -#define PASS 1 -#endif - -#if PASS == 1 -/* Default exception handler */ -void __attribute__((used, naked)) default_handler(void); -void default_handler() -{ - asm( - ".thumb_func\n" - " b exception_panic" - ); -} - -#define table(x) x - -#define weak_with_default __attribute__((used,weak,alias("default_handler"))) - -#define vec(name) extern void weak_with_default name ## _handler(void); -#define irq(num) vec(irq_ ## num) - -#define item(name) extern void name(void); -#define null - -extern void stack_end(void); /* not technically correct, it's just a pointer */ -extern void reset(void); - -#pragma GCC diagnostic push -#if __GNUC__ >= 8 -#pragma GCC diagnostic ignored "-Wattribute-alias" -#endif -/* Call default_handler if svc_handler is not found (task.c is not built) */ -void weak_with_default svc_handler(int desched, task_id_t resched); -#pragma GCC diagnostic pop - -/* - * SVC handler helper - * - * Work around issue where a late exception can corrupt r0 to r3, - * see section 2.7 (svc) of Cortex-M3 Application Note 179: - * http://infocenter.arm.com/help/topic/com.arm.doc.dai0179b/AppsNote179.pdf - * - * This approach differs slightly from the one in the document, - * it only loads r0 (desched) and r1 (resched) for svc_handler. - */ -void __attribute__((used,naked)) svc_helper_handler(void); -void svc_helper_handler() -{ - asm( - ".thumb_func\n" - " tst lr, #4 /* see if called from supervisor mode */\n" - " mrs r2, msp /* get the correct stack pointer into r2 */\n" - " it ne\n" - " mrsne r2, psp\n" - " ldr r1, [r2, #4] /* get regs from stack frame */\n" - " ldr r0, [r2]\n" - " b %0 /* call svc_handler */\n" - : - : "i"(svc_handler) - ); -} - -#endif /* PASS 1 */ - -#if PASS == 2 -#undef table -#undef vec -#undef irq -#undef item -#undef null - -/* number of elements before the first irq vector */ -#define IRQ_OFFSET 16 -/* element in the table that is null: extra IRQs are routed there, - * then finally overwritten - */ -#define IRQ_UNUSED_OFFSET 8 - -/* Disable warning that "initializer overrides prior initialization of this - * subobject", since we are explicitly doing this to handle the unused IRQs. - */ -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Winitializer-overrides" -#endif /* __clang__ */ - -#define table(x) \ - const func vectors[] __attribute__((section(".text.vecttable"))) = { \ - x \ - [IRQ_UNUSED_OFFSET] = null \ - }; - -#define vec(name) name ## _handler, -#define irq(num) [num < CONFIG_IRQ_COUNT ? num + IRQ_OFFSET : IRQ_UNUSED_OFFSET] = vec(irq_ ## num) - -#define item(name) name, -#define null (void*)0, -#endif /* PASS 2 */ - -table( - item(stack_end) - item(reset) - vec(nmi) - vec(hard_fault) - vec(mpu_fault) - vec(bus_fault) - vec(usage_fault) - null - null - null - null - item(svc_helper_handler) - vec(debug) - null - vec(pendsv) - vec(sys_tick) - irq(0) - irq(1) - irq(2) - irq(3) - irq(4) - irq(5) - irq(6) - irq(7) - irq(8) - irq(9) - irq(10) - irq(11) - irq(12) - irq(13) - irq(14) - irq(15) - irq(16) - irq(17) - irq(18) - irq(19) - irq(20) - irq(21) - irq(22) - irq(23) - irq(24) - irq(25) - irq(26) - irq(27) - irq(28) - irq(29) - irq(30) - irq(31) - irq(32) - irq(33) - irq(34) - irq(35) - irq(36) - irq(37) - irq(38) - irq(39) - irq(40) - irq(41) - irq(42) - irq(43) - irq(44) - irq(45) - irq(46) - irq(47) - irq(48) - irq(49) - irq(50) - irq(51) - irq(52) - irq(53) - irq(54) - irq(55) - irq(56) - irq(57) - irq(58) - irq(59) - irq(60) - irq(61) - irq(62) - irq(63) - irq(64) - irq(65) - irq(66) - irq(67) - irq(68) - irq(69) - irq(70) - irq(71) - irq(72) - irq(73) - irq(74) - irq(75) - irq(76) - irq(77) - irq(78) - irq(79) - irq(80) - irq(81) - irq(82) - irq(83) - irq(84) - irq(85) - irq(86) - irq(87) - irq(88) - irq(89) - irq(90) - irq(91) - irq(92) - irq(93) - irq(94) - irq(95) - irq(96) - irq(97) - irq(98) - irq(99) - irq(100) - irq(101) - irq(102) - irq(103) - irq(104) - irq(105) - irq(106) - irq(107) - irq(108) - irq(109) - irq(110) - irq(111) - irq(112) - irq(113) - irq(114) - irq(115) - irq(116) - irq(117) - irq(118) - irq(119) - irq(120) - irq(121) - irq(122) - irq(123) - irq(124) - irq(125) - irq(126) - irq(127) - irq(128) - irq(129) - irq(130) - irq(131) - irq(132) - irq(133) - irq(134) - irq(135) - irq(136) - irq(137) - irq(138) - irq(139) - irq(140) - irq(141) - irq(142) - irq(143) - irq(144) - irq(145) - irq(146) - irq(147) - irq(148) - irq(149) - irq(150) - irq(151) - irq(152) - irq(153) - irq(154) - irq(155) - irq(156) - irq(157) - irq(158) - irq(159) - irq(160) - irq(161) - irq(162) - irq(163) - irq(164) - irq(165) - irq(166) - irq(167) - irq(168) - irq(169) - irq(170) - irq(171) - irq(172) - irq(173) - irq(174) - irq(175) - irq(176) - irq(177) - irq(178) - irq(179) - irq(180) - irq(181) - irq(182) - irq(183) - irq(184) - irq(185) - irq(186) - irq(187) - irq(188) - irq(189) - irq(190) - irq(191) - irq(192) - irq(193) - irq(194) - irq(195) - irq(196) - irq(197) - irq(198) - irq(199) - irq(200) - irq(201) - irq(202) - irq(203) - irq(204) - irq(205) - irq(206) - irq(207) - irq(208) - irq(209) - irq(210) - irq(211) - irq(212) - irq(213) - irq(214) - irq(215) - irq(216) - irq(217) - irq(218) - irq(219) - irq(220) - irq(221) - irq(222) - irq(223) - irq(224) - irq(225) - irq(226) - irq(227) - irq(228) - irq(229) - irq(230) - irq(231) - irq(232) - irq(233) - irq(234) - irq(235) - irq(236) - irq(237) - irq(238) - irq(239) - irq(240) - irq(241) - irq(242) - irq(243) - irq(244) - irq(245) - irq(246) - irq(247) - irq(248) - irq(249) - irq(250) - irq(251) - irq(252) - irq(253) - irq(254) -) - -#if PASS == 2 -#ifdef __clang__ -#pragma clang diagnostic pop -#endif /* __clang__ */ -#endif - -#if PASS == 1 -#undef PASS -#define PASS 2 -#include "vecttable.c" -#endif diff --git a/core/cortex-m/watchdog.c b/core/cortex-m/watchdog.c deleted file mode 100644 index c9faf54b2b..0000000000 --- a/core/cortex-m/watchdog.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 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. - */ - -/* Watchdog common code */ - -#include "common.h" -#include "cpu.h" -#include "panic.h" -#include "task.h" -#include "timer.h" -#include "watchdog.h" - -/* - * As defined by Armv7-M Reference Manual B1.5.6 "Exception Entry Behavior", - * the structure of the saved context on the stack is: - * r0, r1, r2, r3, r12, lr, pc, psr, ... - */ -#define STACK_IDX_REG_LR 5 -#define STACK_IDX_REG_PC 6 - -void __keep watchdog_trace(uint32_t excep_lr, uint32_t excep_sp) -{ - uint32_t psp; - uint32_t *stack; - - asm("mrs %0, psp" : "=r"(psp)); - if ((excep_lr & 0xf) == 1) { - /* we were already in exception context */ - stack = (uint32_t *)excep_sp; - } else { - /* we were in task context */ - stack = (uint32_t *)psp; - } - - panic_set_reason(PANIC_SW_WATCHDOG, stack[STACK_IDX_REG_PC], - (excep_lr & 0xf) == 1 ? 0xff : task_get_current()); - - /* - * This is our last breath, the last opportunity to sort out all - * matters. Flush and invalidate D-cache if cache enabled. - */ - if (IS_ENABLED(CONFIG_ARMV7M_CACHE)) - cpu_clean_invalidate_dcache(); - - panic_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ", - stack[STACK_IDX_REG_PC], stack[STACK_IDX_REG_LR], psp); - if ((excep_lr & 0xf) == 1) - panic_puts("(exc) ###\n"); - else - panic_printf("(task %d) ###\n", task_get_current()); - - /* If we are blocked in a high priority IT handler, the following debug - * messages might not appear but they are useless in that situation. */ - timer_print_info(); - task_print_list(); -} |