mirror of
https://github.com/google/pebble.git
synced 2025-07-07 07:10:30 -04:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
258
src/libos/mcu/cache_arm.c
Normal file
258
src/libos/mcu/cache_arm.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mcu/cache.h"
|
||||
#include "util/attributes.h"
|
||||
|
||||
#define CMSIS_COMPATIBLE
|
||||
#include <mcu.h>
|
||||
|
||||
// I-Cache definition doesn't always exist
|
||||
#ifndef __ICACHE_PRESENT
|
||||
# define __ICACHE_PRESENT 0U
|
||||
#endif
|
||||
|
||||
// D-Cache definition doesn't always exist
|
||||
#ifndef __DCACHE_PRESENT
|
||||
# define __DCACHE_PRESENT 0U
|
||||
#endif
|
||||
|
||||
// Most of these implementations are derived from CMSIS
|
||||
#define CCSIDR_LINESIZE(x) (((x) & SCB_CCSIDR_LINESIZE_Msk) >> SCB_CCSIDR_LINESIZE_Pos)
|
||||
#define CCSIDR_WAYS(x) (((x) & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos)
|
||||
|
||||
#define CSSELR_L1_DCACHE 0
|
||||
#define CSSELR_L1_ICACHE 1
|
||||
|
||||
#if __ICACHE_PRESENT
|
||||
static uint32_t s_icache_cssidr;
|
||||
#endif
|
||||
|
||||
#if __DCACHE_PRESENT
|
||||
static uint32_t s_dcache_cssidr;
|
||||
#endif
|
||||
|
||||
#if __ICACHE_PRESENT || __DCACHE_PRESENT
|
||||
static uint32_t prv_get_line_size(uint32_t ccsidr) {
|
||||
return ((CCSIDR_LINESIZE(ccsidr)) + 1) << 4;
|
||||
}
|
||||
|
||||
static void prv_cache_operation_range(volatile uint32_t *reg, uint32_t line_size, uintptr_t addr,
|
||||
size_t size) {
|
||||
intptr_t op_size = size;
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
|
||||
while (op_size > 0) {
|
||||
*reg = addr;
|
||||
addr += line_size;
|
||||
op_size -= line_size;
|
||||
}
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __DCACHE_PRESENT
|
||||
static void prv_dcache_operation_all(volatile uint32_t *reg) {
|
||||
uint32_t ccsidr;
|
||||
uint32_t sets;
|
||||
uint32_t ways;
|
||||
|
||||
ccsidr = s_dcache_cssidr;
|
||||
|
||||
sets = CCSIDR_SETS(ccsidr);
|
||||
do {
|
||||
ways = CCSIDR_WAYS(ccsidr);
|
||||
do {
|
||||
*reg = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
|
||||
((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk));
|
||||
#if defined(__CC_ARM)
|
||||
__schedule_barrier();
|
||||
#endif
|
||||
} while (ways--);
|
||||
} while (sets--);
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
}
|
||||
#endif
|
||||
|
||||
MOCKABLE void icache_enable(void) {
|
||||
#if __ICACHE_PRESENT
|
||||
SCB->CSSELR = CSSELR_L1_ICACHE;
|
||||
__DMB();
|
||||
s_icache_cssidr = SCB->CCSIDR;
|
||||
|
||||
icache_invalidate_all();
|
||||
|
||||
__DSB();
|
||||
__ISB();
|
||||
SCB->CCR |= SCB_CCR_IC_Msk; // enable I-Cache
|
||||
__DSB();
|
||||
__ISB();
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void icache_disable(void) {
|
||||
#if __ICACHE_PRESENT
|
||||
__DSB();
|
||||
__ISB();
|
||||
SCB->CCR &= ~SCB_CCR_IC_Msk; // disable I-Cache
|
||||
__DSB();
|
||||
__ISB();
|
||||
|
||||
icache_invalidate_all();
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE bool icache_is_enabled(void) {
|
||||
#if __ICACHE_PRESENT
|
||||
return SCB->CCR & SCB_CCR_IC_Msk;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
MOCKABLE uint32_t icache_line_size(void) {
|
||||
#if __ICACHE_PRESENT
|
||||
return prv_get_line_size(s_icache_cssidr);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
MOCKABLE void dcache_enable(void) {
|
||||
#if __DCACHE_PRESENT
|
||||
SCB->CSSELR = CSSELR_L1_DCACHE;
|
||||
__DMB();
|
||||
s_dcache_cssidr = SCB->CCSIDR;
|
||||
|
||||
dcache_invalidate_all();
|
||||
__DSB();
|
||||
SCB->CCR |= SCB_CCR_DC_Msk; // enable D-Cache
|
||||
__DSB();
|
||||
__ISB();
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void dcache_disable(void) {
|
||||
#if __DCACHE_PRESENT
|
||||
dcache_flush_invalidate_all();
|
||||
__DSB();
|
||||
SCB->CCR &= ~SCB_CCR_DC_Msk; // disable D-Cache
|
||||
__DSB();
|
||||
__ISB();
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE bool dcache_is_enabled(void) {
|
||||
#if __DCACHE_PRESENT
|
||||
return SCB->CCR & SCB_CCR_DC_Msk;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
MOCKABLE uint32_t dcache_line_size(void) {
|
||||
#if __DCACHE_PRESENT
|
||||
return prv_get_line_size(s_dcache_cssidr);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
MOCKABLE uint32_t dcache_alignment_mask_minimum(uint32_t min) {
|
||||
#if __DCACHE_PRESENT
|
||||
const uint32_t line_size = dcache_line_size();
|
||||
if (line_size > min) {
|
||||
return line_size - 1;
|
||||
}
|
||||
#endif
|
||||
return min - 1;
|
||||
}
|
||||
|
||||
MOCKABLE void icache_invalidate_all(void) {
|
||||
#if __ICACHE_PRESENT
|
||||
__DSB();
|
||||
__ISB();
|
||||
SCB->ICIALLU = 0;
|
||||
__DSB();
|
||||
__ISB();
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void icache_invalidate(void *addr, size_t size) {
|
||||
#if __ICACHE_PRESENT
|
||||
prv_cache_operation_range(&SCB->ICIMVAU, icache_line_size(), (uintptr_t)addr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void dcache_flush_all(void) {
|
||||
#if __DCACHE_PRESENT
|
||||
prv_dcache_operation_all(&SCB->DCCSW);
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void dcache_invalidate_all(void) {
|
||||
#if __DCACHE_PRESENT
|
||||
prv_dcache_operation_all(&SCB->DCISW);
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void dcache_flush_invalidate_all(void) {
|
||||
#if __DCACHE_PRESENT
|
||||
prv_dcache_operation_all(&SCB->DCCISW);
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void dcache_flush(const void *addr, size_t size) {
|
||||
#if __DCACHE_PRESENT
|
||||
prv_cache_operation_range(&SCB->DCCMVAC, dcache_line_size(), (uintptr_t)addr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void dcache_invalidate(void *addr, size_t size) {
|
||||
#if __DCACHE_PRESENT
|
||||
prv_cache_operation_range(&SCB->DCIMVAC, dcache_line_size(), (uintptr_t)addr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
MOCKABLE void dcache_flush_invalidate(const void *addr, size_t size) {
|
||||
#if __DCACHE_PRESENT
|
||||
prv_cache_operation_range(&SCB->DCCIMVAC, dcache_line_size(), (uintptr_t)addr, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void prv_align(uintptr_t *addr, size_t *size, uint32_t line_size) {
|
||||
uint32_t line_mask = line_size - 1;
|
||||
if (*addr & line_mask) {
|
||||
// Need to adjust the address and size because the address is unaligned.
|
||||
*size += *addr & line_mask;
|
||||
*addr &= ~line_mask;
|
||||
}
|
||||
if (*size & line_mask) {
|
||||
// Need to round the size up because the size is unaligned.
|
||||
*size = (*size + line_mask) & ~line_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void icache_align(uintptr_t *addr, size_t *size) {
|
||||
prv_align(addr, size, icache_line_size());
|
||||
}
|
||||
|
||||
void dcache_align(uintptr_t *addr, size_t *size) {
|
||||
prv_align(addr, size, dcache_line_size());
|
||||
}
|
39
src/libos/mcu/fpu_arm.c
Normal file
39
src/libos/mcu/fpu_arm.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mcu/fpu.h"
|
||||
|
||||
#define CMSIS_COMPATIBLE
|
||||
#include <mcu.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void mcu_fpu_cleanup(void) {
|
||||
// The lazy stacking mechanism for the Cortex M4 starts stacking FPU
|
||||
// registers during context switches once the thread has used the FPU
|
||||
// once. This is problematic because this bumps the stack cost of a context
|
||||
// switch by an additional 132 bytes. This routine resets the FPCA bit which
|
||||
// controls whether or not this stacking takes place
|
||||
// For the Cortex M3, this routine is a no-op
|
||||
|
||||
const uint32_t fpca_bit_mask = 0x4;
|
||||
uint32_t control = __get_CONTROL();
|
||||
|
||||
if ((control & fpca_bit_mask) != 0) {
|
||||
control &= ~fpca_bit_mask;
|
||||
__set_CONTROL(control);
|
||||
}
|
||||
}
|
22
src/libos/mcu/interrupts_arm.c
Normal file
22
src/libos/mcu/interrupts_arm.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mcu/interrupts.h"
|
||||
|
||||
bool mcu_state_are_interrupts_enabled(void) {
|
||||
// When this bit is set, all interrupts (of configureable priority) are disabled
|
||||
return ((__get_PRIMASK() & 0x1) == 0x0);
|
||||
}
|
35
src/libos/mcu/privilege_arm.c
Normal file
35
src/libos/mcu/privilege_arm.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mcu/privilege.h"
|
||||
|
||||
#include "mcu/interrupts.h"
|
||||
#include "util/attributes.h"
|
||||
|
||||
// These functions need to be called from assembly so they can't be inlined
|
||||
EXTERNALLY_VISIBLE void mcu_state_set_thread_privilege(bool privileged) {
|
||||
uint32_t control = __get_CONTROL();
|
||||
if (privileged) {
|
||||
control &= ~0x1;
|
||||
} else {
|
||||
control |= 0x1;
|
||||
}
|
||||
__set_CONTROL(control);
|
||||
}
|
||||
|
||||
bool mcu_state_is_privileged(void) {
|
||||
return mcu_state_is_thread_privileged() || mcu_state_is_isr();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue