Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • add_menu_vibration
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • dualcore
  • dx/flatten-config-module
  • dx/meh-bdf-to-stm
  • freertos-btle
  • genofire/ble-follow-py
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/textbuffer_api
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bluetooth-app-favorite
  • rahix/bma
  • rahix/user-space-ctx
  • renze/hatchery_apps
  • renze/safe_mode
  • schleicher-test
  • schneider/212-reset-hardware-when-entering-repl
  • schneider/ancs
  • schneider/ble-buffers
  • schneider/ble-central
  • schneider/ble-ecg-stream-visu
  • schneider/ble-fixes-2020-3
  • schneider/ble-mini-demo
  • schneider/ble-stability
  • schneider/ble-stability-new-phy
  • schneider/bonding
  • schneider/bonding-fail-if-full
  • schneider/bootloader-update-9a0d158
  • schneider/deepsleep
  • schneider/deepsleep2
  • schneider/deepsleep4
  • schneider/default-main
  • schneider/freertos-list-debug
  • schneider/fundamental-test
  • schneider/iaq-python
  • schneider/ir
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-exception-print
  • schneider/mp-for-old-bl
  • schneider/png
  • schneider/schleicher-test
  • schneider/sdk-0.2.1-11
  • schneider/sdk-0.2.1-7
  • schneider/sleep-display
  • schneider/spo2-playground
  • schneider/stream-locks
  • schneider/v1.17-changelog
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.10
  • v1.11
  • v1.12
  • v1.13
  • v1.14
  • v1.15
  • v1.16
  • v1.17
  • v1.18
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
82 results

Target

Select target project
  • card10/firmware
  • annejan/firmware
  • astro/firmware
  • fpletz/firmware
  • gerd/firmware
  • fleur/firmware
  • swym/firmware
  • l/firmware
  • uberardy/firmware
  • wink/firmware
  • madonius/firmware
  • mot/firmware
  • filid/firmware
  • q3k/firmware
  • hauke/firmware
  • Woazboat/firmware
  • pink/firmware
  • mossmann/firmware
  • omniskop/firmware
  • zenox/firmware
  • trilader/firmware
  • Danukeru/firmware
  • shoragan/firmware
  • zlatko/firmware
  • sistason/firmware
  • datenwolf/firmware
  • bene/firmware
  • amedee/firmware
  • martinling/firmware
  • griffon/firmware
  • chris007/firmware
  • adisbladis/firmware
  • dbrgn/firmware
  • jelly/firmware
  • rnestler/firmware
  • mh/firmware
  • ln/firmware
  • penguineer/firmware
  • monkeydom/firmware
  • jens/firmware
  • jnaulty/firmware
  • jeffmakes/firmware
  • marekventur/firmware
  • pete/firmware
  • h2obrain/firmware
  • DooMMasteR/firmware
  • jackie/firmware
  • prof_r/firmware
  • Draradech/firmware
  • Kartoffel/firmware
  • hinerk/firmware
  • abbradar/firmware
  • JustTB/firmware
  • LuKaRo/firmware
  • iggy/firmware
  • ente/firmware
  • flgr/firmware
  • Lorphos/firmware
  • matejo/firmware
  • ceddral7/firmware
  • danb/firmware
  • joshi/firmware
  • melle/firmware
  • fitch/firmware
  • deurknop/firmware
  • sargon/firmware
  • markus/firmware
  • kloenk/firmware
  • lucaswerkmeister/firmware
  • derf/firmware
  • meh/firmware
  • dx/card10-firmware
  • torben/firmware
  • yuvadm/firmware
  • AndyBS/firmware
  • klausdieter1/firmware
  • katzenparadoxon/firmware
  • xiretza/firmware
  • ole/firmware
  • techy/firmware
  • thor77/firmware
  • TilCreator/firmware
  • fuchsi/firmware
  • dos/firmware
  • yrlf/firmware
  • PetePriority/firmware
  • SuperVirus/firmware
  • sur5r/firmware
  • tazz/firmware
  • Alienmaster/firmware
  • flo_h/firmware
  • baldo/firmware
  • mmu_man/firmware
  • Foaly/firmware
  • sodoku/firmware
  • Guinness/firmware
  • ssp/firmware
  • led02/firmware
  • Stormwind/firmware
  • arist/firmware
  • coon/firmware
  • mdik/firmware
  • pippin/firmware
  • royrobotiks/firmware
  • zigot83/firmware
  • mo_k/firmware
106 results
Select Git revision
  • add_menu_vibration
  • blinkisync-as-preload
  • ch3/api-speed-eval2
  • ch3/dual-core
  • ch3/genapi-refactor
  • ch3/leds-api
  • ch3/splashscreen
  • dualcore
  • freertos-btle
  • genofire/ble-follow-py
  • koalo/bhi160-works-but-dirty
  • koalo/factory-reset
  • koalo/wip/i2c-for-python
  • master
  • msgctl/faultscreen
  • msgctl/textbuffer_api
  • ofscreen_lines
  • plaetzchen/ios-workaround
  • rahix/bhi
  • rahix/bma
  • rahix/meson-micropython
  • rahix/panic
  • rahix/proper-sleep
  • renze/hatchery_apps
  • renze/safe_mode
  • right_scroll_config
  • schleicher-test
  • schneider/ble-buffers
  • schneider/ble-stability
  • schneider/ble-stability-new-phy
  • schneider/ble-stability-new-phy-adv
  • schneider/bonding
  • schneider/bootloader-update-9a0d158
  • schneider/bsec
  • schneider/ecg-plot
  • schneider/fundamental-test
  • schneider/max30001
  • schneider/max30001-epicaridum
  • schneider/max30001-pycardium
  • schneider/maxim-sdk-update
  • schneider/mp-for-old-bl
  • schneider/schleicher-test
  • schneider/stream-locks
  • simple_menu_buttons
  • bootloader-v1
  • release-1
  • v0.0
  • v1.0
  • v1.1
  • v1.10
  • v1.11
  • v1.2
  • v1.3
  • v1.4
  • v1.5
  • v1.6
  • v1.7
  • v1.8
  • v1.9
59 results
Show changes
Showing
with 829 additions and 28 deletions
bootloader/splash-screen.png

6.1 KiB

......@@ -4,8 +4,10 @@ set -xe
cd "$(dirname "$0")"
test -d build/ && rm -r build/
git submodule update --init ./lib/micropython
meson --cross-file card10-cross.ini build/
# Get external libs (MicroPython, tiny-AES-c, SHA256)
git submodule deinit --all
git submodule update --init ./lib
meson --cross-file card10-cross.ini build/ "$@"
set +x
......
......@@ -4,9 +4,9 @@ ar = 'arm-none-eabi-ar'
strip = 'arm-none-eabi-strip'
[properties]
# TODO: Switch to hard float
c_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=hard', '-mfpu=fpv4-sp-d16', '-Wa,-mimplicit-it=thumb', '-ffunction-sections', '-fdata-sections', '-fsingle-precision-constant', '-fno-isolate-erroneous-paths-dereference']
c_link_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=hard', '-mfpu=fpv4-sp-d16']
c_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=softfp', '-mfpu=fpv4-sp-d16', '-Wa,-mimplicit-it=thumb', '-ffunction-sections', '-fdata-sections', '-fsingle-precision-constant', '-fno-isolate-erroneous-paths-dereference']
c_link_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=softfp', '-mfpu=fpv4-sp-d16', '-Wl,--start-group', '-lc', '-lnosys', '-Wl,--end-group', '--specs=nano.specs', '-Wl,-wrap,BbBleDrvRand']
target_defs = ['-DTARGET=32665', '-DTARGET_REV=0x4131', '-DBOARD_CARD10=1']
......
with import <nixpkgs> {};
let
py = python36;
# crc16 does not exist in pythonPackages - bring in our own.
crc16 = py.pkgs.buildPythonPackage rec {
pname = "crc16";
version = "0.1.1";
src = py.pkgs.fetchPypi {
inherit pname version;
sha256 = "15nkx0pa4lskwin84flpk8fsw3jqg6wic6v3s83syjqg76h6my61";
};
};
in stdenv.mkDerivation rec {
name = "card10";
nativeBuildInputs = [
bash
crc16
gcc-arm-embedded
git
meson
ninja
py
py.pkgs.pillow
];
src = ./.;
buildCommand = ''
build=$(pwd)/build
# Copy source over, as dev sources from '.' thend to have odd permissions.
cp -r $src $(pwd)/src
cd $(pwd)/src
# Ensure we have write right to patch shebangs.
chmod -R +w .
# The nix sandbox does not have /usr/bin/env bash, patch things up.
for f in lib/micropython/*.sh tools/*.sh; do
patchShebangs "$f"
done
# Actually run the build.
meson --cross-file card10-cross.ini "$build"
ninja -C "$build" -j $NIX_BUILD_CORES
# Copy ELFs for debugging
install -D -m 444 "$build/bootloader/bootloader.elf" -t "$out/lib/bootloader.elf"
install -D -m 444 "$build/epicardium/epicardium.elf" -t "$out/lib/epicardium.elf"
install -D -m 444 "$build/pycardium/pycardium.elf" -t "$out/lib/pycardium.elf"
# Create new flash contents
install -D -m 444 "$build/pycardium/pycardium_epicardium.bin" "$out/card10/card10.bin"
install -m 444 preload/*.py -t $out/card10/
cp -ar preload/apps $out/card10/
'';
}
import ws2812, gpio, bluetooth, time, display
from micropython import const
_IRQ_GATTS_WRITE = const(3)
WS2812_SERVICE_UUID = \
bluetooth.UUID("23238000-2342-2342-2342-234223422342")
SET_ALL = (
bluetooth.UUID("23238001-2342-2342-2342-234223422342"),
bluetooth.FLAG_WRITE
)
WS2812_SERVICE = (
WS2812_SERVICE_UUID,
(SET_ALL,)
)
def irq(event, data):
if event == _IRQ_GATTS_WRITE:
conn_handle, value_handle = data
value = ble.gatts_read(value_handle)
ws2812.set_all(gpio.WRISTBAND_3, [value] * 3)
if __name__ == "__main__":
display.open().backlight(0)
gpio.set_mode(gpio.WRISTBAND_3, gpio.mode.OUTPUT)
ble = bluetooth.BLE()
ble.active(True)
ble.irq(irq)
ble.gatts_register_services((WS2812_SERVICE,))
print("Waiting for connection!")
while True:
time.sleep(1)
#!/usr/bin/env python3
import bluepy
import time
import colorsys
# Change this to the MAC of your card10
p = bluepy.btle.Peripheral("CA:4D:10:01:ff:64")
c = p.getCharacteristics(
uuid='23238001-2342-2342-2342-234223422342')[0]
hue = 0
while 1:
r,g,b = colorsys.hsv_to_rgb(hue, 1, 0.1)
c.write(b"%c%c%c" %
(int(r*255), int(g*255), int(b*255)), True)
time.sleep(.1)
hue += 0.1
FROM ubuntu
RUN apt-get update && apt-get -y install gcc-arm-none-eabi binutils-arm-none-eabi libnewlib-arm-none-eabi python3 python3-pip ninja-build git
RUN pip3 install meson crc16 pillow
VOLUME /firmware
WORKDIR /firmware
CMD ./bootstrap.sh && ninja -C build && chown -R --reference=/firmware build
FROM debian:stretch-backports
RUN set -e -x ;\
export DEBIAN_FRONTEND=noninteractive ;\
apt-get update -y ;\
apt-get install -y \
git \
gcc-arm-none-eabi \
python3-pip ;\
apt-get install -y -t stretch-backports \
meson ;\
pip3 install crc16 pillow ;\
rm -rf /var/lib/apt/lists
#!/usr/bin/env bash
# Build and push the build env Docker container to the Gitlab container registry.
set -e
function rev() {
( cd $1; git describe --always --match "v[0-9].*" --dirty )
}
IMAGE=derq3k/card10-build-env
TAG=$(TZ=UTC date +%Y%m%d-%H%M%SZ)-$(rev .)
docker build -t $IMAGE:$TAG .
docker push $IMAGE:$TAG
echo "Pushed $IMAGE:$TAG"
FROM ubuntu:focal
RUN set -e -x ;\
export DEBIAN_FRONTEND=noninteractive ;\
apt-get update -y ;\
apt-get install -y \
clang \
git \
libclang-dev \
llvm \
python3-pip ;\
pip3 install \
clang==10.0.1 \
sphinx \
sphinx_rtd_theme ;\
rm -rf /var/lib/apt/lists
#!/usr/bin/env bash
# Build and push the deploy env Docker container to the Gitlab container registry.
set -e
function rev() {
( cd $1; git describe --always --match "v[0-9].*" --dirty )
}
IMAGE=derq3k/card10-deploy-env
TAG=$(TZ=UTC date +%Y%m%d-%H%M%SZ)-$(rev .)
docker build -t $IMAGE:$TAG .
docker push $IMAGE:$TAG
echo "Pushed $IMAGE:$TAG"
FROM ubuntu:bionic
RUN set -e -x ;\
export DEBIAN_FRONTEND=noninteractive ;\
apt-get update -y ;\
apt-get install -y \
curl \
ca-certificates \
clang-format \
git \
python3 \
python3-pip ;\
python3 -m pip install black ;\
rm -rf /var/lib/apt/lists
#!/usr/bin/env bash
# Build and push the deploy env Docker container to the Gitlab container registry.
set -e
function rev() {
( cd $1; git describe --always --match "v[0-9].*" --dirty )
}
IMAGE=derq3k/card10-lint-env
TAG=$(TZ=UTC date +%Y%m%d-%H%M%SZ)-$(rev .)
docker build -t $IMAGE:$TAG .
docker push $IMAGE:$TAG
echo "Pushed $IMAGE:$TAG"
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#include "max32665.h"
#include <assert.h>
/* CMSIS keeps a global updated with current system clock in Hz */
#define configCPU_CLOCK_HZ ((unsigned long)96000000)
/* TODO: Adjust this for tickless idle */
#define configTICK_RATE_HZ ((portTickType)1000)
/* Memory
*
* Heap is managed by libc (heap_3.c).
*/
#define configMINIMAL_STACK_SIZE ((unsigned short)256)
/* FIXME: Assign proper priorities to all interrupts */
#define configMAX_PRIORITIES 5
/* # of priority bits (configured in hardware) is provided by CMSIS */
#define configPRIO_BITS __NVIC_PRIO_BITS
/* Priority 7, or 255 as only the top three bits are implemented. This is the lowest priority. */
#define configKERNEL_INTERRUPT_PRIORITY \
( ( unsigned char ) 7 << ( 8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
( ( unsigned char ) 2 << ( 8 - configPRIO_BITS) )
/* We want to use preemption to easier integrate components */
#define configUSE_PREEMPTION 1
/*
* Tickless idle from the FreeRTOS port + our own hooks (defined further down in
* this file)
*/
#define configUSE_TICKLESS_IDLE 1
/* TODO: Adjust */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_CO_ROUTINES 0
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
/* Allow static allocation of data structures */
#define configSUPPORT_STATIC_ALLOCATION 1
/*
* Enable stack overflow detector.
*
* TODO: Remove for production.
*/
#define configCHECK_FOR_STACK_OVERFLOW 2
/* Alias the default handler names to match CMSIS weak symbols */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
/* Assert */
#define configASSERT(x) assert(x)
/* Tickless idle hooks */
typedef uint32_t TickType_t;
void pre_idle_sleep(TickType_t xExpectedIdleTime);
#define configPRE_SLEEP_PROCESSING(xModifiableIdleTime) \
pre_idle_sleep(xModifiableIdleTime); xModifiableIdleTime = 0
void post_idle_sleep(TickType_t xExpectedIdleTime);
#define configPOST_SLEEP_PROCESSING(xExpectedIdleTime) \
post_idle_sleep(xExpectedIdleTime)
/*
* Uncomment to trace FreeRTOS malloc wrapper.
*
*/
// extern int printf (const char *__restrict __format, ...);
// #define traceMALLOC( pvAddress, uiSize ) printf("[%s:%d] %p %d\n", __FILE__, __LINE__, pvAddress, uiSize)
#endif /* FREERTOS_CONFIG_H */
......@@ -2,11 +2,35 @@
#include "sema.h"
#include "api/caller.h"
#define MXC_ASSERT_ENABLE
#include "mxc_assert.h"
static uint32_t irq_save = 0;
void *_api_call_start(api_id_t id, uintptr_t size)
{
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {}
/*
* Disable all maskable interrupts here, to be turned on again at the
* end of _api_call_transact().
*/
irq_save = __get_PRIMASK();
__set_PRIMASK(1);
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {
}
/* TODO: Check flag */
if (API_CALL_MEM->call_flag != _API_FLAG_IDLE) {
/*
* The only way this can happen is if a call was issued from an
* interrupt hander while another call is still happening. This
* has to be prevented at all cost!
*/
mxc_assert(
"API recalled during ongoing call!",
__FILE__,
__LINE__
);
}
API_CALL_MEM->id = id;
return API_CALL_MEM->buffer;
......@@ -25,7 +49,8 @@ void*_api_call_transact(void*buffer)
/* Wait for the dispather to return */
__WFE();
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {}
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {
}
if (API_CALL_MEM->call_flag == _API_FLAG_RETURNED) {
break;
}
......@@ -35,5 +60,74 @@ void*_api_call_transact(void*buffer)
API_CALL_MEM->call_flag = _API_FLAG_IDLE;
SEMA_FreeSema(_API_SEMAPHORE);
/*
* Re-enable interrupts (if previously enabled) after completing the API
* call.
*/
__set_PRIMASK(irq_save);
return API_CALL_MEM->buffer;
}
__attribute__((noreturn)) void epic_exit(int ret)
{
/*
* Call __epic_exit() and then jump to the reset routine/
*/
void *buffer;
buffer = _api_call_start(API_SYSTEM_EXIT, sizeof(int));
*(int *)buffer = ret;
_api_call_transact(buffer);
API_CALL_MEM->reset_stub();
/* unreachable */
while (1)
;
}
int epic_exec(char *name)
{
/*
* Call __epic_exec(). If it succeeds, jump to the reset routine.
* Otherwise, return the error code.
*/
void *buffer;
buffer = _api_call_start(API_SYSTEM_EXEC, sizeof(char *));
*(char **)buffer = name;
int ret = *(int *)_api_call_transact(buffer);
if (ret < 0) {
return ret;
}
API_CALL_MEM->reset_stub();
/* unreachable */
while (1)
;
}
int api_fetch_args(char *buf, size_t cnt)
{
if (API_CALL_MEM->id != 0) {
/*
* When any call happened before the args are fetched, they are
* overwritten and no longer accessible.
*/
return (-1);
}
if (API_CALL_MEM->buffer[0x20] == '\0') {
return 0;
}
size_t i;
for (i = 0; i < cnt && API_CALL_MEM->buffer[i + 0x20] != '\0'; i++) {
buf[i] = API_CALL_MEM->buffer[i + 0x20];
}
return i - 1;
}
......@@ -27,3 +27,12 @@ void*_api_call_start(api_id_t id, uintptr_t size);
* - Pointer to a buffer containing the return value
*/
void *_api_call_transact(void *buffer);
/*
* Fetch arguments from the API buffer. This function will only work properly
* directly after startup of core 1. If api_fetch_args() is called after other
* calls have already happened, it will return -1.
*
* Otherwise it will return the length of data which was read.
*/
int api_fetch_args(char *buf, size_t cnt);
#pragma once
#include "epicardium.h"
#include <stdint.h>
#include <stdbool.h>
/*
* Semaphore used for API synchronization.
* TODO: Replace this with a LDREX/STREX based implementation
*/
#define _API_SEMAPHORE 0
#define _CONTROL_SEMAPHORE 1
/* Type of API IDs */
typedef uint32_t api_id_t;
......@@ -15,6 +20,13 @@ typedef uint32_t api_id_t ;
/* Layout of the shared memory for API calls */
struct api_call_mem {
/*
* Reset stub. The reset stub is a small function provided by
* epicardium that should be called by a payload when receiving the
* reset interrupt.
*/
void (*reset_stub)();
/*
* Flag for synchronization of API calls. When this flag
* is set, the caller has issued a call and is waiting for
......@@ -25,6 +37,9 @@ struct api_call_mem {
/* ID if the ongoing API call */
api_id_t id;
/* ID of the current interrupt */
volatile api_int_id_t int_id;
/*
* Buffer for arguments/return value. This buffer will be
* *overflown*, because there is guaranteed space behind it.
......
#include "epicardium.h"
#include "api/dispatcher.h"
#include "card10.h"
#include "max32665.h"
#include "sema.h"
#include "tmr.h"
static void __core1_init(void);
extern void interrupt_trigger_sync(api_int_id_t id);
struct core1_info {
/* Location of core1's interrupt vector table */
volatile uintptr_t ivt_addr;
/* Whether core 1 is ready for a new IVT */
volatile bool ready;
};
/*
* Information passing structure for controlling core 1.
*/
static volatile struct core1_info core1_info = {
.ivt_addr = 0x00,
.ready = false,
};
/*
* Minimal IVT needed for initial startup. This IVT only contains the initial
* stack pointer and reset-handler and is used to startup core 1. Afterwards,
* the payload's IVT is loaded into VTOR and used from then on.
*/
static uintptr_t core1_initial_ivt[] = {
/* Initial Stack Pointer */
0x20080000,
/* Reset Handler */
(uintptr_t)__core1_reset,
};
/*
* Reset Handler
*
* Calls __core1_init() to reset & prepare the core for loading a new payload.
*/
__attribute__((naked)) void __core1_reset(void)
{
/* Reset stack to MSP and set it to 0x20080000 */
__asm volatile(
"mov r0, #0\n\t"
"msr control, r0\n\t"
"mov sp, %0\n\t"
: /* No Outputs */
: "r"(core1_initial_ivt[0])
: "r0");
/* Reset FPU */
SCB->CPACR = 0x00000000;
FPU->FPDSCR = 0x00000000;
FPU->FPCCR = 0x00000000;
__DSB();
__ISB();
__core1_init();
}
/*
* Init core 1. This function will reset the core and wait for a new IVT
* address from Epicardium. Once this address is received, it will start
* execution with the supplied reset handler.
*/
void __core1_init(void)
{
/*
* Clear any pending API interrupts.
*/
TMR_IntClear(MXC_TMR5);
/*
* Disable the SysTick
*/
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk;
/*
* Reset Interrupts
*
* To ensure proper operation of the new payload, disable all interrupts
* and clear all pending ones.
*/
for (int i = 0; i < MXC_IRQ_EXT_COUNT; i++) {
NVIC_DisableIRQ(i);
NVIC_ClearPendingIRQ(i);
NVIC_SetPriority(i, 0);
}
/*
* Check whether we catched the core during an interrupt. If this is
* the case, try returning from the exception handler first and call
* __core1_reset() again in thread context.
*/
if ((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0) {
/*
* Construct an exception frame so the CPU will jump back to our
* __core1_reset() function once we exit from the exception
* handler.
*
* To exit the exception, a special "EXC_RETURN" value is loaded
* into the link register and then branched to.
*/
__asm volatile(
"ldr r0, =0x41000000\n\t"
"ldr r1, =0\n\t"
"push { r0 }\n\t" /* xPSR */
"push { %0 }\n\t" /* PC */
"push { %0 }\n\t" /* LR */
"push { r1 }\n\t" /* R12 */
"push { r1 }\n\t" /* R3 */
"push { r1 }\n\t" /* R2 */
"push { r1 }\n\t" /* R1 */
"push { r1 }\n\t" /* R0 */
"ldr lr, =0xFFFFFFF9\n\t"
"bx lr\n\t"
: /* No Outputs */
: "r"((uintptr_t)__core1_reset)
: "pc", "lr");
/* unreachable */
while (1)
;
}
/* Wait for the IVT address */
while (1) {
while (SEMA_GetSema(_CONTROL_SEMAPHORE) == E_BUSY) {
}
__DMB();
__ISB();
/*
* The IVT address is reset to 0 by Epicardium before execution
* gets here. Once a new address has been set, core 1 can use
* the new IVT.
*/
if (core1_info.ivt_addr != 0x00) {
break;
}
/* Signal that we are ready for an IVT address */
core1_info.ready = true;
/*
* Reset the API interrupt so we never block Epicardium when it
* attempts to trigger an interrupt.
*/
API_CALL_MEM->int_id = (-1);
SEMA_FreeSema(_CONTROL_SEMAPHORE);
__WFE();
}
uintptr_t *ivt = (uintptr_t *)core1_info.ivt_addr;
core1_info.ivt_addr = 0x00;
SEMA_FreeSema(_CONTROL_SEMAPHORE);
/*
* Reset the call-flag before entering the payload so API calls behave
* properly. This is necessary because epic_exec() will set the flag
* to "returning" on exit.
*/
API_CALL_MEM->call_flag = _API_FLAG_IDLE;
/*
* Set the IVT
*/
SCB->VTOR = (uintptr_t)ivt;
/*
* Clear any pending API interrupts.
*/
TMR_IntClear(MXC_TMR5);
NVIC_ClearPendingIRQ(TMR5_IRQn);
/*
* Jump to payload's reset handler
*/
__asm volatile(
"ldr r0, %0\n\t"
"blx r0\n\r"
: /* No Outputs */
: "m"(*(ivt + 1))
: "r0");
}
void core1_boot(void)
{
/*
* Boot using the initial IVT. This will place core 1 into a loop,
* waiting for a payload.
*/
core1_start(&core1_initial_ivt);
}
void core1_trigger_reset(void)
{
/*
* Signal core 1 that we intend to load a new payload.
*
* This needs to be synchroneous because otherwise we will deadlock
* (Lifecycle task busy-spins and interrupt can never get dispatched).
*/
interrupt_trigger_sync(EPIC_INT_RESET);
}
bool core1_is_ready(void)
{
bool ready;
while (SEMA_GetSema(_CONTROL_SEMAPHORE) == E_BUSY) {
}
/*
* core 1 will set the ready flag once it is spinning in the
* above loop, waiting for a new IVT.
*/
ready = core1_info.ready;
SEMA_FreeSema(_CONTROL_SEMAPHORE);
return ready;
}
void core1_wait_ready(void)
{
/* Wait for the core to accept */
while (1) {
if (core1_is_ready()) {
break;
}
for (int i = 0; i < 10000; i++) {
}
}
/*
* TODO: If the other core does not respond within a certain grace
* period, we need to force it into our desired state by overwriting
* all of its memory. Yes, I don't like this method either ...
*/
}
void core1_load(void *ivt, char *args)
{
while (SEMA_GetSema(_CONTROL_SEMAPHORE) == E_BUSY) {
}
/* If the core is currently in an API call, reset it. */
API_CALL_MEM->call_flag = _API_FLAG_IDLE;
API_CALL_MEM->id = 0;
API_CALL_MEM->int_id = (-1);
api_prepare_args(args);
core1_info.ivt_addr = (uintptr_t)ivt;
core1_info.ready = false;
__DMB();
__ISB();
SEMA_FreeSema(_CONTROL_SEMAPHORE);
__SEV();
__WFE();
}
#include <stdlib.h>
#include "sema.h"
#include "api/dispatcher.h"
#include "max32665.h"
#include "sema.h"
#include <stdlib.h>
#include <string.h>
/* This function is defined by the generated dispatcher code */
void __api_dispatch_call(api_id_t id, void *buffer);
static volatile bool call_pending = false;
int api_dispatcher_init()
{
int ret;
ret = SEMA_Init(NULL);
SEMA_FreeSema(_API_SEMAPHORE);
API_CALL_MEM->reset_stub = __core1_reset;
API_CALL_MEM->call_flag = _API_FLAG_IDLE;
API_CALL_MEM->id = 0;
API_CALL_MEM->int_id = (-1);
/*
* Enable TX events for both cores.
* TODO: Is this the right place?
*/
MXC_GCR->evten |= 0x24;
MXC_GCR->evten |=
MXC_F_GCR_EVTEN_CPU0TXEVENT | MXC_F_GCR_EVTEN_CPU1TXEVENT;
return ret;
}
api_id_t api_dispatcher_poll()
bool api_dispatcher_poll_once()
{
api_id_t id = 0;
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {}
if (call_pending) {
return false;
}
while (SEMA_GetSema(_API_SEMAPHORE) == E_BUSY) {
}
if (API_CALL_MEM->call_flag != _API_FLAG_CALLING) {
SEMA_FreeSema(_API_SEMAPHORE);
return false;
}
call_pending = true;
return true;
}
bool api_dispatcher_poll()
{
if (call_pending) {
return true;
}
return api_dispatcher_poll_once();
}
bool api_dispatcher_call_pending()
{
return call_pending;
}
api_id_t api_dispatcher_exec()
{
if (!call_pending) {
return 0;
}
id = API_CALL_MEM->id;
api_id_t id = API_CALL_MEM->id;
__api_dispatch_call(id, API_CALL_MEM->buffer);
API_CALL_MEM->call_flag = _API_FLAG_RETURNED;
call_pending = false;
SEMA_FreeSema(_API_SEMAPHORE);
/* Notify the caller that we returned */
......@@ -40,3 +83,15 @@ api_id_t api_dispatcher_poll()
return id;
}
void api_prepare_args(char *args)
{
/*
* The args are stored with an offset of 0x20 to make sure they won't
* collide with any integer return value of API calls like epic_exec().
*/
API_CALL_MEM->id = 0;
for (size_t i = 0; i <= strlen(args); i++) {
API_CALL_MEM->buffer[i + 0x20] = args[i];
}
}
......@@ -7,11 +7,52 @@
int api_dispatcher_init();
/*
* Attempt to dispatch a call, if the caller has requested one.
* Will return 0 if no call was dispatched and the ID of the dispatched
* call otherwise.
* Check whether the other core requested a call. If this function returns
* true, the dispatcher should call api_dispatcher_exec() to actually dispatch
* the call. Consecutive calls to this function will return false. Use
* api_dispatcher_poll() if your need to recheck.
*/
api_id_t api_dispatcher_poll();
bool api_dispatcher_poll_once();
bool api_dispatcher_poll();
/* This function is defined by the generated dispatcher code */
void __api_dispatch_call(api_id_t id, void*buffer);
/*
* Check if the other core requested a call or if we are already excuting it.
* Only returns a cached version, without acquiring any locks.
*/
bool api_dispatcher_call_pending();
/*
* Attempt to dispatch a call, if one had been polled using
* api_dispatcher_poll(). Will return 0 if no call was dispatched or the ID of
* the dispatched call otherwise.
*/
api_id_t api_dispatcher_exec();
/*
* Fill the API buffer with data for l0dable/pycardium startup.
*
* The data is a NULL-terminated string.
*/
void api_prepare_args(char *args);
/*********************************************************************
* core 1 control *
*********************************************************************/
/* Startup core1 into a state where it is ready to receive a payload. */
void core1_boot(void);
/* Reset core 1 into a state where it can accept a new payload */
void core1_trigger_reset(void);
/* Check if core 1 is ready for a new payload */
bool core1_is_ready(void);
/* Wait for core 1 to respond that it is ready for a new payload */
void core1_wait_ready(void);
/* Load a payload into core 1 */
void core1_load(void *ivt, char *args);
/* core 1 reset stub. See epicardium/api/control.c for details. */
void __core1_reset(void);