Initial Release
This commit is contained in:
44
src/rp2_common/pico_runtime/CMakeLists.txt
Normal file
44
src/rp2_common/pico_runtime/CMakeLists.txt
Normal file
@ -0,0 +1,44 @@
|
||||
add_library(pico_runtime INTERFACE)
|
||||
|
||||
target_sources(pico_runtime INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/runtime.c
|
||||
)
|
||||
|
||||
target_include_directories(pico_runtime INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
|
||||
target_link_libraries(pico_runtime INTERFACE
|
||||
hardware_uart
|
||||
hardware_clocks
|
||||
hardware_irq
|
||||
pico_printf
|
||||
pico_sync
|
||||
)
|
||||
|
||||
if (TARGET pico_bit_ops)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_bit_ops)
|
||||
endif()
|
||||
if (TARGET pico_divider)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_divider)
|
||||
endif()
|
||||
if (TARGET pico_double)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_double)
|
||||
endif()
|
||||
if (TARGET pico_int64_ops)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_int64_ops)
|
||||
endif()
|
||||
if (TARGET pico_float)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_float)
|
||||
endif()
|
||||
if (TARGET pico_malloc)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_malloc)
|
||||
endif()
|
||||
if (TARGET pico_mem_ops)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_mem_ops)
|
||||
endif()
|
||||
if (TARGET pico_standard_link)
|
||||
target_link_libraries(pico_runtime INTERFACE pico_standard_link)
|
||||
endif()
|
||||
|
||||
# todo is this correct/needed?
|
||||
target_link_options(pico_runtime INTERFACE "--specs=nosys.specs")
|
||||
|
26
src/rp2_common/pico_runtime/include/pico/runtime.h
Normal file
26
src/rp2_common/pico_runtime/include/pico/runtime.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PICO_RUNTIME_H
|
||||
#define _PICO_RUNTIME_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file runtime.h
|
||||
* \defgroup pico_runtime pico_runtime
|
||||
* Aggregate runtime support including @ref pico_bit_ops, @ref pico_divider, @ref pico_double, @ref pico_int64_ops, @ref pico_float, @ref pico_malloc, @ref pico_mem_ops and @ref pico_standard_link
|
||||
*/
|
||||
|
||||
|
||||
void runtime_install_stack_guard(void *stack_bottom);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
243
src/rp2_common/pico_runtime/runtime.c
Normal file
243
src/rp2_common/pico_runtime/runtime.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "pico.h"
|
||||
|
||||
#include "hardware/regs/m0plus.h"
|
||||
#include "hardware/regs/resets.h"
|
||||
#include "hardware/structs/mpu.h"
|
||||
#include "hardware/structs/scb.h"
|
||||
#include "hardware/structs/padsbank0.h"
|
||||
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/resets.h"
|
||||
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/printf.h"
|
||||
|
||||
#ifndef PICO_NO_RAM_VECTOR_TABLE
|
||||
#define PICO_NO_RAM_VECTOR_TABLE 0
|
||||
#endif
|
||||
|
||||
extern char __StackLimit; /* Set by linker. */
|
||||
|
||||
uint32_t __attribute__((section(".ram_vector_table"))) ram_vector_table[48];
|
||||
|
||||
// this is called for each thread since they have their own MPU
|
||||
void runtime_install_stack_guard(void *stack_bottom) {
|
||||
// this is called b4 runtime_init is complete, so beware printf or assert
|
||||
|
||||
// make sure no one is using the MPU yet
|
||||
if (mpu_hw->ctrl) {
|
||||
// Note that it would be tempting to change this to a panic, but it happens so early, printing is not a good idea
|
||||
__breakpoint();
|
||||
}
|
||||
|
||||
uintptr_t addr = (uintptr_t) stack_bottom;
|
||||
// the minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will
|
||||
// just shorten the valid stack range a tad
|
||||
addr = (addr + 31u) & ~31u;
|
||||
|
||||
// mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want
|
||||
uint32_t subregion_select = 0xffu ^ (1u << ((addr >> 5u) & 7u));
|
||||
mpu_hw->ctrl = 5; // enable mpu with background default map
|
||||
mpu_hw->rbar = (addr & ~0xff) | 0x8 | 0;
|
||||
mpu_hw->rasr = 1 // enable region
|
||||
| (0x7 << 1) // size 2^(7 + 1) = 256
|
||||
| (subregion_select << 8)
|
||||
| 0x10000000; // XN = disable instruction fetch; no other bits means no permissions
|
||||
}
|
||||
|
||||
void runtime_init(void) {
|
||||
// Reset all peripherals to put system into a known state,
|
||||
// - except for QSPI pads and the XIP IO bank, as this is fatal if running from flash
|
||||
// - and the PLLs, as this is fatal if clock muxing has not been reset on this boot
|
||||
reset_block(~(
|
||||
RESETS_RESET_IO_QSPI_BITS |
|
||||
RESETS_RESET_PADS_QSPI_BITS |
|
||||
RESETS_RESET_PLL_USB_BITS |
|
||||
RESETS_RESET_PLL_SYS_BITS
|
||||
));
|
||||
|
||||
// Remove reset from peripherals which are clocked only by clk_sys and
|
||||
// clk_ref. Other peripherals stay in reset until we've configured clocks.
|
||||
unreset_block_wait(RESETS_RESET_BITS & ~(
|
||||
RESETS_RESET_ADC_BITS |
|
||||
RESETS_RESET_RTC_BITS |
|
||||
RESETS_RESET_SPI0_BITS |
|
||||
RESETS_RESET_SPI1_BITS |
|
||||
RESETS_RESET_UART0_BITS |
|
||||
RESETS_RESET_UART1_BITS |
|
||||
RESETS_RESET_USBCTRL_BITS
|
||||
));
|
||||
|
||||
// pre-init runs really early since we need it even for memcpy and divide!
|
||||
// (basically anything in aeabi that uses bootrom)
|
||||
|
||||
// Start and end points of the constructor list,
|
||||
// defined by the linker script.
|
||||
extern void (*__preinit_array_start)();
|
||||
extern void (*__preinit_array_end)();
|
||||
|
||||
// Call each function in the list.
|
||||
// We have to take the address of the symbols, as __preinit_array_start *is*
|
||||
// the first function pointer, not the address of it.
|
||||
for (void (**p)() = &__preinit_array_start; p < &__preinit_array_end; ++p) {
|
||||
(*p)();
|
||||
}
|
||||
|
||||
// After calling preinit we have enough runtime to do the exciting maths
|
||||
// in clocks_init
|
||||
clocks_init();
|
||||
|
||||
// Peripheral clocks should now all be running
|
||||
unreset_block_wait(RESETS_RESET_BITS);
|
||||
|
||||
#if !PICO_IE_26_29_UNCHANGED_ON_RESET
|
||||
// after resetting BANK0 we should disable IE on 26-29
|
||||
hw_clear_alias(padsbank0_hw)->io[26] = hw_clear_alias(padsbank0_hw)->io[27] =
|
||||
hw_clear_alias(padsbank0_hw)->io[28] = hw_clear_alias(padsbank0_hw)->io[29] = PADS_BANK0_GPIO0_IE_BITS;
|
||||
#endif
|
||||
|
||||
extern mutex_t __mutex_array_start;
|
||||
extern mutex_t __mutex_array_end;
|
||||
|
||||
// the first function pointer, not the address of it.
|
||||
for (mutex_t *m = &__mutex_array_start; m < &__mutex_array_end; m++) {
|
||||
mutex_init(m);
|
||||
}
|
||||
|
||||
#if !(PICO_NO_RAM_VECTOR_TABLE || PICO_NO_FLASH)
|
||||
__builtin_memcpy(ram_vector_table, (uint32_t *) scb_hw->vtor, sizeof(ram_vector_table));
|
||||
scb_hw->vtor = (intptr_t) ram_vector_table;
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
uint32_t xpsr;
|
||||
__asm volatile ("mrs %0, XPSR" : "=r" (xpsr)::);
|
||||
if (xpsr & 0xffu) {
|
||||
// crap; started in exception handler
|
||||
__asm ("bkpt #0");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PICO_USE_STACK_GUARDS
|
||||
// install core0 stack guard
|
||||
extern char __StackBottom;
|
||||
runtime_install_stack_guard(&__StackBottom);
|
||||
#endif
|
||||
|
||||
spin_locks_reset();
|
||||
irq_init_priorities();
|
||||
alarm_pool_init_default();
|
||||
|
||||
// Start and end points of the constructor list,
|
||||
// defined by the linker script.
|
||||
extern void (*__init_array_start)();
|
||||
extern void (*__init_array_end)();
|
||||
|
||||
// Call each function in the list.
|
||||
// We have to take the address of the symbols, as __init_array_start *is*
|
||||
// the first function pointer, not the address of it.
|
||||
for (void (**p)() = &__init_array_start; p < &__init_array_end; ++p) {
|
||||
(*p)();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void _exit(int status) {
|
||||
#if PICO_ENTER_USB_BOOT_ON_EXIT
|
||||
reset_usb_boot(0,0);
|
||||
#else
|
||||
while (1) {
|
||||
__breakpoint();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void *_sbrk(int incr) {
|
||||
extern char end; /* Set by linker. */
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
|
||||
if (heap_end == 0)
|
||||
heap_end = &end;
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
char *next_heap_end = heap_end + incr;
|
||||
|
||||
if (__builtin_expect(next_heap_end >= (&__StackLimit), false)) {
|
||||
#if PICO_USE_OPTIMISTIC_SBRK
|
||||
if (next_heap_end == &__StackLimit) {
|
||||
// errno = ENOMEM;
|
||||
return (char *) -1;
|
||||
}
|
||||
next_heap_end = &__StackLimit;
|
||||
#else
|
||||
return (char *) -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
heap_end = next_heap_end;
|
||||
return (void *) prev_heap_end;
|
||||
}
|
||||
|
||||
// exit is not useful... no desire to pull in __call_exitprocs
|
||||
void exit(int status) {
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
// incorrect warning from GCC 6
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
|
||||
void __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
|
||||
weak_raw_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n",
|
||||
failedexpr, file, line, func ? ", function: " : "",
|
||||
func ? func : "");
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
void __attribute__((noreturn)) panic_unsupported() {
|
||||
panic("not supported");
|
||||
}
|
||||
|
||||
// todo consider making this try harder to output if we panic early
|
||||
// right now, print mutex may be uninitialised (in which case it deadlocks - although after printing "PANIC")
|
||||
// more importantly there may be no stdout/UART initialized yet
|
||||
// todo we may want to think about where we print panic messages to; writing to USB appears to work
|
||||
// though it doesn't seem like we can expect it to... fine for now
|
||||
//
|
||||
void __attribute__((noreturn)) __printflike(1, 0) panic(const char *fmt, ...) {
|
||||
puts("\n*** PANIC ***\n");
|
||||
if (fmt) {
|
||||
#if PICO_PRINTF_NONE
|
||||
puts(fmt);
|
||||
#else
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
#if PICO_PRINTF_ALWAYS_INCLUDED
|
||||
vprintf(fmt, args);
|
||||
#else
|
||||
weak_raw_vprintf(fmt, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
puts("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
void hard_assertion_failure(void) {
|
||||
panic("Hard assert");
|
||||
}
|
Reference in New Issue
Block a user