From 665be1aefb623c3616ce65a353bc8457594ae743 Mon Sep 17 00:00:00 2001 From: Damian Loewnau Date: Thu, 1 Dec 2022 13:17:48 +0100 Subject: [PATCH 1/2] hal: add armv8m33-nrf9160 port JIRA: RTOS-283 --- hal/armv8m/Makefile | 13 ++ hal/armv8m/arch/cpu.h | 232 ++++++++++++++++++++++++++ hal/armv8m/arch/exceptions.h | 52 ++++++ hal/armv8m/arch/interrupts.h | 38 +++++ hal/armv8m/arch/pmap.h | 61 +++++++ hal/armv8m/arch/spinlock.h | 33 ++++ hal/armv8m/arch/types.h | 53 ++++++ hal/armv8m/armv8m.h | 37 +++++ hal/armv8m/cpu.c | 251 ++++++++++++++++++++++++++++ hal/armv8m/exceptions.c | 129 ++++++++++++++ hal/armv8m/hal.c | 62 +++++++ hal/armv8m/nrf/91/Makefile | 9 + hal/armv8m/nrf/91/config.h | 27 +++ hal/armv8m/nrf/91/console.c | 205 +++++++++++++++++++++++ hal/armv8m/nrf/91/nrf91.c | 221 ++++++++++++++++++++++++ hal/armv8m/nrf/91/nrf91.h | 69 ++++++++ hal/armv8m/nrf/91/timer.c | 127 ++++++++++++++ hal/armv8m/nrf/Makefile | 14 ++ hal/armv8m/nrf/_init.S | 314 +++++++++++++++++++++++++++++++++++ hal/armv8m/nrf/interrupts.c | 228 +++++++++++++++++++++++++ hal/armv8m/pmap.c | 103 ++++++++++++ hal/armv8m/spinlock.c | 120 +++++++++++++ hal/armv8m/string.c | 256 ++++++++++++++++++++++++++++ include/arch/nrf9160.h | 31 ++++ include/arch/syspage-nrf91.h | 33 ++++ 25 files changed, 2718 insertions(+) create mode 100644 hal/armv8m/Makefile create mode 100644 hal/armv8m/arch/cpu.h create mode 100644 hal/armv8m/arch/exceptions.h create mode 100644 hal/armv8m/arch/interrupts.h create mode 100644 hal/armv8m/arch/pmap.h create mode 100644 hal/armv8m/arch/spinlock.h create mode 100644 hal/armv8m/arch/types.h create mode 100644 hal/armv8m/armv8m.h create mode 100644 hal/armv8m/cpu.c create mode 100644 hal/armv8m/exceptions.c create mode 100644 hal/armv8m/hal.c create mode 100644 hal/armv8m/nrf/91/Makefile create mode 100644 hal/armv8m/nrf/91/config.h create mode 100644 hal/armv8m/nrf/91/console.c create mode 100644 hal/armv8m/nrf/91/nrf91.c create mode 100644 hal/armv8m/nrf/91/nrf91.h create mode 100644 hal/armv8m/nrf/91/timer.c create mode 100644 hal/armv8m/nrf/Makefile create mode 100644 hal/armv8m/nrf/_init.S create mode 100644 hal/armv8m/nrf/interrupts.c create mode 100644 hal/armv8m/pmap.c create mode 100644 hal/armv8m/spinlock.c create mode 100644 hal/armv8m/string.c create mode 100644 include/arch/nrf9160.h create mode 100644 include/arch/syspage-nrf91.h diff --git a/hal/armv8m/Makefile b/hal/armv8m/Makefile new file mode 100644 index 000000000..d6005da9f --- /dev/null +++ b/hal/armv8m/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for Phoenix-RTOS kernel (ARMv8M HAL) +# +# Copyright 2022 Phoenix Systems +# + + +ifneq (, $(findstring nrf, $(TARGET_SUBFAMILY))) + include hal/armv8m/nrf/Makefile + CFLAGS += -Ihal/armv8m +endif + +OBJS += $(addprefix $(PREFIX_O)hal/armv8m/, string.o spinlock.o cpu.o hal.o pmap.o exceptions.o) diff --git a/hal/armv8m/arch/cpu.h b/hal/armv8m/arch/cpu.h new file mode 100644 index 000000000..2b21c335a --- /dev/null +++ b/hal/armv8m/arch/cpu.h @@ -0,0 +1,232 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * CPU related routines + * + * Copyright 2014, 2017, 2022 Phoenix Systems + * Author: Jacek Popko, Pawel Pisarczyk, Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_ARMV8M_CPU_H_ +#define _HAL_ARMV8M_CPU_H_ + + +#if defined(CPU_NRF9160) +#define CPU_NRF91 +#endif + +#include "types.h" + +#define SIZE_PAGE 0x200 + +#ifndef SIZE_USTACK +#define SIZE_USTACK (3 * SIZE_PAGE) +#endif + +#ifndef SIZE_KSTACK +#define SIZE_KSTACK (4 * SIZE_PAGE) +#endif + +/* values based on EXC_RETURN requirements */ +#define RET_HANDLER_MSP 0xfffffff1u +#define RET_THREAD_MSP 0xfffffff9u +#define RET_THREAD_PSP 0xfffffffdu +#define HWCTXSIZE 8 +#define USERCONTROL 0x3u + +#ifndef __ASSEMBLY__ + + +#define SYSTICK_INTERVAL 1000 + + +#define PUTONSTACK(kstack, t, v) \ + do { \ + (kstack) -= (sizeof(t) + 3) & ~0x3u; \ + *((t *)kstack) = (v); \ + } while (0) + + +#define GETFROMSTACK(ustack, t, v, n) \ + do { \ + ustack = (void *)(((ptr_t)ustack + sizeof(t) - 1) & ~(sizeof(t) - 1)); \ + (v) = *(t *)ustack; \ + ustack += (sizeof(t) + 3) & ~0x3u; \ + } while (0) + +typedef struct _cpu_context_t { + u32 savesp_s; + u32 padding; + + /* Saved by ISR */ + u32 psp; + u32 r4; + u32 r5; + u32 r6; + u32 r7; + u32 r8; + u32 r9; + u32 r10; + u32 r11; + u32 irq_ret; + + /* Saved by hardware */ + u32 r0; + u32 r1; + u32 r2; + u32 r3; + u32 r12; + u32 lr; + u32 pc; + u32 psr; + +} cpu_context_t; + + +static inline void hal_cpuDisableInterrupts(void) +{ + __asm__ volatile("cpsid if"); +} + + +static inline void hal_cpuEnableInterrupts(void) +{ + __asm__ volatile("cpsie if"); +} + + +static inline void hal_cpuHalt(void) +{ +} + + +/* bit operations */ + + +static inline unsigned int hal_cpuGetLastBit(unsigned long v) +{ + int pos; + /* clang-format off */ + __asm__ volatile("clz %0, %1" : "=r" (pos) : "r" (v)); + + return 31 - pos; +} + + +static inline unsigned int hal_cpuGetFirstBit(unsigned long v) +{ + unsigned pos; + + __asm__ volatile("\ + rbit %0, %1; \ + clz %0, %0;" : "=r" (pos) : "r" (v)); + + return pos; +} + + +/* context management */ + +static inline void hal_cpuSetCtxGot(cpu_context_t *ctx, void *got) +{ + ctx->r9 = (u32)got; +} + + +static inline void hal_cpuSetGot(void *got) +{ + __asm__ volatile("mov r9, %0" :: "r" (got)); +} + + +static inline void *hal_cpuGetGot(void) +{ + void *got; + + __asm__ volatile("mov %0, r9" : "=r" (got)); + + return got; +} + + +static inline void hal_cpuRestore(cpu_context_t *curr, cpu_context_t *next) +{ + curr->savesp_s = (u32)next; +} + + +static inline void hal_cpuSetReturnValue(cpu_context_t *ctx, int retval) +{ + ctx->r0 = retval; +} + + +static inline u32 hal_cpuGetPC(void) +{ + void *pc; + + __asm__ volatile("mov %0, pc" : "=r" (pc)); + /* clang-format on */ + + return (u32)pc; +} + + +static inline void _hal_cpuSetKernelStack(void *kstack) +{ +} + + +static inline void *hal_cpuGetSP(cpu_context_t *ctx) +{ + return (void *)ctx; +} + + +static inline void *hal_cpuGetUserSP(cpu_context_t *ctx) +{ + return (void *)ctx->psp; +} + + +static inline int hal_cpuSupervisorMode(cpu_context_t *ctx) +{ + return ((ctx->irq_ret & (1 << 2)) == 0) ? 1 : 0; +} + + +static inline int hal_cpuPushSignal(void *kstack, void (*handler)(void), int sig) +{ + return 0; +} + + +/* core management */ + + +static inline unsigned int hal_cpuGetID(void) +{ + return 0; +} + + +static inline unsigned int hal_cpuGetCount(void) +{ + return 1; +} + + +static inline void cpu_sendIPI(unsigned int cpu, unsigned int intr) +{ +} + + +#endif + +#endif diff --git a/hal/armv8m/arch/exceptions.h b/hal/armv8m/arch/exceptions.h new file mode 100644 index 000000000..c1066448d --- /dev/null +++ b/hal/armv8m/arch/exceptions.h @@ -0,0 +1,52 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Exceptions handling + * + * Copyright 2022 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_ARMV8M_EXCEPTIONS_H_ +#define _HAL_ARMV8M_EXCEPTIONS_H_ + +#include "types.h" + +#define EXC_DEFAULT 128 + +#define EXC_UNDEFINED 3 + +#define SIZE_CTXDUMP 512 /* Size of dumped context */ + + +typedef struct _exc_context_t { + /* Saved by ISR */ + u32 psp; + u32 r4; + u32 r5; + u32 r6; + u32 r7; + u32 r8; + u32 r9; + u32 r10; + u32 r11; + u32 excret; + + /* Saved by hardware */ + u32 r0; + u32 r1; + u32 r2; + u32 r3; + u32 r12; + u32 lr; + u32 pc; + u32 psr; +} exc_context_t; + +#endif diff --git a/hal/armv8m/arch/interrupts.h b/hal/armv8m/arch/interrupts.h new file mode 100644 index 000000000..bf1f5a5b0 --- /dev/null +++ b/hal/armv8m/arch/interrupts.h @@ -0,0 +1,38 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Interrupt handling + * + * Copyright 2016, 2017, 2020, 2022 Phoenix Systems + * Author: Pawel Pisarczyk, Artur Wodejko, Hubert Buczynski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _HAL_ARMV8M_INTERRUPTS_H_ +#define _HAL_ARMV8M_INTERRUPTS_H_ + +#include "cpu.h" + +#define SVC_IRQ 11 +#define PENDSV_IRQ 14 +#define SYSTICK_IRQ 15 + + +typedef struct _intr_handler_t { + struct _intr_handler_t *next; + struct _intr_handler_t *prev; + /* irq */ + unsigned int n; + /* handler function */ + int (*f)(unsigned int, cpu_context_t *, void *); + void *data; + void *got; +} intr_handler_t; + +#endif diff --git a/hal/armv8m/arch/pmap.h b/hal/armv8m/arch/pmap.h new file mode 100644 index 000000000..a7d28fdaa --- /dev/null +++ b/hal/armv8m/arch/pmap.h @@ -0,0 +1,61 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * pmap interface - machine dependent part of VM subsystem (ARMv8) + * + * Copyright 2017, 2020, 2022 Phoenix Systems + * Author: Pawel Pisarczyk, Aleksander Kaminski, Hubert Buczynski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_PMAP_ARMV8M_H_ +#define _HAL_PMAP_ARMV8M_H_ + +#include "types.h" + +#define PGHD_PRESENT 0x01u +#define PGHD_USER 0x04u +#define PGHD_WRITE 0x02u +#define PGHD_EXEC 0x00u +#define PGHD_DEV 0x00u +#define PGHD_NOT_CACHED 0x00u + +/* Page flags */ +#define PAGE_FREE 0x00000001u + +#define PAGE_OWNER_BOOT (0u << 1) +#define PAGE_OWNER_KERNEL (1u << 1) +#define PAGE_OWNER_APP (2u << 1) + +#define PAGE_KERNEL_SYSPAGE (1u << 4) +#define PAGE_KERNEL_CPU (2u << 4) +#define PAGE_KERNEL_PTABLE (3u << 4) +#define PAGE_KERNEL_PMAP (4u << 4) +#define PAGE_KERNEL_STACK (5u << 4) +#define PAGE_KERNEL_HEAP (6u << 4) + + +#ifndef __ASSEMBLY__ + +typedef struct _page_t { + addr_t addr; + u8 idx; + u16 flags; + struct _page_t *next; +} page_t; + + +typedef struct _pmap_t { + u32 mpr; + void *start; + void *end; +} pmap_t; + +#endif + +#endif diff --git a/hal/armv8m/arch/spinlock.h b/hal/armv8m/arch/spinlock.h new file mode 100644 index 000000000..247f05fc0 --- /dev/null +++ b/hal/armv8m/arch/spinlock.h @@ -0,0 +1,33 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Spinlock + * + * Copyright 2014, 2017, 2022 Phoenix Systems + * Author: Jacek Popko, Pawel Pisarczyk, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_ARMV8M_SPINLOCK_H_ +#define _HAL_ARMV8M_SPINLOCK_H_ + +#include "types.h" + +typedef struct _spinlock_t { + const char *name; + struct _spinlock_t *next; + struct _spinlock_t *prev; + + u8 lock; +} spinlock_t; + + +typedef u32 spinlock_ctx_t; + + +#endif diff --git a/hal/armv8m/arch/types.h b/hal/armv8m/arch/types.h new file mode 100644 index 000000000..676779ec7 --- /dev/null +++ b/hal/armv8m/arch/types.h @@ -0,0 +1,53 @@ + +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Types + * + * Copyright 2023 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_ARMV8M_TYPES_H_ +#define _HAL_ARMV8M_TYPES_H_ + +#define NULL 0 + +#ifndef __ASSEMBLY__ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef u32 addr_t; +typedef u32 cycles_t; + +typedef s64 offs_t; + +typedef unsigned int size_t; +typedef unsigned long long time_t; + +typedef u32 ptr_t; + +/* Object identifier - contains server port and object id */ +typedef u32 id_t; +typedef struct _oid_t { + u32 port; + id_t id; +} oid_t; + +#endif + +#endif diff --git a/hal/armv8m/armv8m.h b/hal/armv8m/armv8m.h new file mode 100644 index 000000000..32c9a46e5 --- /dev/null +++ b/hal/armv8m/armv8m.h @@ -0,0 +1,37 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * ARMv8 Cortex-M related routines + * + * Copyright 2021, 2022 Phoenix Systems + * Author: Hubert Buczynski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_ARMV8M_H_ +#define _HAL_ARMV8M_H_ + + +static inline void hal_cpuDataMemoryBarrier(void) +{ + __asm__ volatile("dmb"); +} + + +static inline void hal_cpuDataSyncBarrier(void) +{ + __asm__ volatile("dsb"); +} + + +static inline void hal_cpuInstrBarrier(void) +{ + __asm__ volatile("isb"); +} + +#endif diff --git a/hal/armv8m/cpu.c b/hal/armv8m/cpu.c new file mode 100644 index 000000000..f4afb3581 --- /dev/null +++ b/hal/armv8m/cpu.c @@ -0,0 +1,251 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * CPU related routines + * + * Copyright 2014, 2017, 2022 Phoenix Systems + * Author: Jacek Popko, Pawel Pisarczyk, Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "../cpu.h" +#include "../interrupts.h" +#include "../spinlock.h" +#include "../string.h" +#include "../hal.h" +#include "../timer.h" + +#include "config.h" + +struct { + int busy; + spinlock_t busySp; +} cpu_common; + + +volatile cpu_context_t *_cpu_nctx; + + +extern void _interrupts_nvicSystemReset(void); + + +/* performance */ + + +void hal_cpuLowPower(time_t us, spinlock_t *spinlock, spinlock_ctx_t *sc) +{ + hal_spinlockClear(spinlock, sc); + hal_cpuHalt(); +} + + +void hal_cpuGetCycles(cycles_t *cb) +{ + /* Cycle counter is not available on armv8m + assumption that 1 cycle is 1us, so we use hal_timerGetUs() with 1ms resolution + both cycles_t and time_t have the same size on armv8m */ + *cb = hal_timerGetUs(); +} + + +void hal_cpuSetDevBusy(int s) +{ + spinlock_ctx_t scp; + + hal_spinlockSet(&cpu_common.busySp, &scp); + if (s == 1) { + ++cpu_common.busy; + } + else { + --cpu_common.busy; + } + + if (cpu_common.busy < 0) { + cpu_common.busy = 0; + } + hal_spinlockClear(&cpu_common.busySp, &scp); +} + + +int hal_cpuCreateContext(cpu_context_t **nctx, void *start, void *kstack, size_t kstacksz, void *ustack, void *arg) +{ + cpu_context_t *ctx; + + *nctx = 0; + if (kstack == NULL) { + return -1; + } + + if (kstacksz < sizeof(cpu_context_t)) { + return -1; + } + + /* Align user stack to 8 bytes */ + ustack = (void *)((ptr_t)ustack & ~0x7u); + + /* Prepare initial kernel stack */ + ctx = (cpu_context_t *)(kstack + kstacksz - sizeof(cpu_context_t)); + + hal_memset(ctx, 0, sizeof(*ctx)); + + ctx->savesp_s = (u32)ctx; + ctx->psp = (ustack != NULL) ? (u32)ustack - (HWCTXSIZE * sizeof(int)) : NULL; + ctx->r4 = 0x44444444u; + ctx->r5 = 0x55555555u; + ctx->r6 = 0x66666666u; + ctx->r7 = 0x77777777u; + ctx->r8 = 0x88888888u; + ctx->r9 = 0x99999999u; + ctx->r10 = 0xaaaaaaaau; + ctx->r11 = 0xbbbbbbbbu; + + if (ustack != NULL) { + ((u32 *)ctx->psp)[0] = (u32)arg; /* r0 */ + ((u32 *)ctx->psp)[1] = 0x11111111u; /* r1 */ + ((u32 *)ctx->psp)[2] = 0x22222222u; /* r2 */ + ((u32 *)ctx->psp)[3] = 0x33333333u; /* r3 */ + ((u32 *)ctx->psp)[4] = 0xccccccccu; /* r12 */ + ((u32 *)ctx->psp)[5] = 0xeeeeeeeeu; /* lr */ + ((u32 *)ctx->psp)[6] = (u32)start; /* pc */ + ((u32 *)ctx->psp)[7] = 0x01000000u; /* psr */ + ctx->irq_ret = RET_THREAD_PSP; + } + else { + ctx->r0 = (u32)arg; + ctx->r1 = 0x11111111u; + ctx->r2 = 0x22222222u; + ctx->r3 = 0x33333333u; + ctx->r12 = 0xccccccccu; + ctx->lr = 0xeeeeeeeeu; + ctx->pc = (u32)start; + ctx->psr = 0x01000000u; + ctx->irq_ret = RET_THREAD_MSP; + } + + *nctx = ctx; + return 0; +} + + +void hal_longjmp(cpu_context_t *ctx) +{ + /* clang-format off */ + __asm__ volatile(" \ + cpsid if; \ + str %1, [%0]; \ + bl _hal_invokePendSV; \ + cpsie if; \ + 1: b 1b" + : + : "r" (&_cpu_nctx), "r" (ctx) + : "memory"); + /* clang-format on */ +} + + +/* core management */ + + +char *hal_cpuInfo(char *info) +{ + int i; + unsigned int cpuinfo; + +#ifdef CPU_NRF91 + cpuinfo = _nrf91_cpuid(); +#else + hal_strcpy(info, "unknown"); + return info; +#endif + + hal_strcpy(info, HAL_NAME_PLATFORM); + i = sizeof(HAL_NAME_PLATFORM) - 1; + + if (((cpuinfo >> 24) & 0xffu) == 0x41u) { + hal_strcpy(info + i, "ARM "); + i += 4; + } + + if (((cpuinfo >> 4) & 0xfffu) == 0xd21u) { + hal_strcpy(info + i, "Cortex-M33 "); + i += 11; + } + + *(info + i++) = 'r'; + *(info + i++) = '0' + ((cpuinfo >> 20) & 0xfu); + *(info + i++) = ' '; + + *(info + i++) = 'p'; + *(info + i++) = '0' + (cpuinfo & 0xfu); + *(info + i) = '\0'; + + return info; +} + + +char *hal_cpuFeatures(char *features, unsigned int len) +{ + unsigned int n = 0; +#ifdef CPU_NRF91 + if ((len - n) > 8) { + hal_strcpy(features + n, "softfp, "); + n += 8; + } +#endif + /* TODO: get regions count from MPU controller */ + if ((len - n) > 8) { + hal_strcpy(features + n, "MPU, "); + n += 5; + } + + if ((len - n) > 7) { + hal_strcpy(features + n, "Thumb, "); + n += 7; + } + + if (n > 0) { + features[n - 2] = '\0'; + } + else { + features[0] = '\0'; + } + + return features; +} + + +/* TODO: add Watchdog implementation */ +void hal_wdgReload(void) +{ +} + + +/* TODO: add implementation */ +void hal_cleanDCache(ptr_t start, size_t len) +{ +} + + +void _hal_cpuInit(void) +{ + cpu_common.busy = 0; + _cpu_nctx = NULL; + + hal_spinlockCreate(&cpu_common.busySp, "devBusy"); + +#ifdef CPU_NRF91 + _nrf91_platformInit(); +#endif +} + + +/* Not safe to call if TLS is not present (tls_base mustn't be NULL) */ +void hal_cpuTlsSet(hal_tls_t *tls, cpu_context_t *ctx) +{ + *(ptr_t *)tls->arm_m_tls = tls->tls_base - 8; +} diff --git a/hal/armv8m/exceptions.c b/hal/armv8m/exceptions.c new file mode 100644 index 000000000..32af88a35 --- /dev/null +++ b/hal/armv8m/exceptions.c @@ -0,0 +1,129 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Exception handling + * + * Copyright 2017, 2022 Phoenix Systems + * Author: Pawel Pisarczyk, Jakub Sejdak, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "../exceptions.h" +#include "../cpu.h" +#include "../console.h" +#include "../string.h" +#include "config.h" + + +void hal_exceptionsDumpContext(char *buff, exc_context_t *ctx, int n) +{ + static const char *mnemonics[] = { + "0 #InitialSP", "1 #Reset", "2 #NMI", "3 #HardFault", + "4 #MemMgtFault", "5 #BusFault", "6 #UsageFault", "7 #SecureFault", + "8 #", "9 #", "10 #", "11 #SVC", + "12 #Debug", "13 #", "14 #PendSV", "15 #SysTick" + }; + size_t i = 0; + u32 msp = (u32)ctx + sizeof(*ctx); + u32 psp = ctx->psp; + cpu_hwContext_t *hwctx; + + /* If we came from userspace HW ctx in on psp stack (according to EXC_RETURN) */ + if (ctx->excret | (1u << 2)) { + hwctx = (void *)ctx->psp; + msp -= sizeof(cpu_hwContext_t); + psp += sizeof(cpu_hwContext_t); + } + else { + hwctx = &ctx->mspctx; + } + + n &= 0xf; + + hal_strcpy(buff, "\nException: "); + i = sizeof("\nException: ") - 1; + hal_strcpy(&buff[i], mnemonics[n]); + i += hal_strlen(mnemonics[n]); + + i += hal_i2s("\n r0=", &buff[i], ctx->r0, 16, 1); + i += hal_i2s(" r1=", &buff[i], ctx->r1, 16, 1); + i += hal_i2s(" r2=", &buff[i], ctx->r2, 16, 1); + i += hal_i2s(" r3=", &buff[i], ctx->r3, 16, 1); + + i += hal_i2s("\n r4=", &buff[i], ctx->r4, 16, 1); + i += hal_i2s(" r5=", &buff[i], ctx->r5, 16, 1); + i += hal_i2s(" r6=", &buff[i], ctx->r6, 16, 1); + i += hal_i2s(" r7=", &buff[i], ctx->r7, 16, 1); + + i += hal_i2s("\n r8=", &buff[i], ctx->r8, 16, 1); + i += hal_i2s(" r9=", &buff[i], ctx->r9, 16, 1); + i += hal_i2s(" r10=", &buff[i], ctx->r10, 16, 1); + i += hal_i2s(" r11=", &buff[i], ctx->r11, 16, 1); + + i += hal_i2s("\nr12=", &buff[i], ctx->r12, 16, 1); + i += hal_i2s(" sp=", &buff[i], (u32)ctx - 17 * 4, 16, 1); + i += hal_i2s(" lr=", &buff[i], ctx->lr, 16, 1); + i += hal_i2s(" pc=", &buff[i], ctx->pc, 16, 1); + + i += hal_i2s("\npsp_s=", &buff[i], ctx->psp_s, 16, 1); + i += hal_i2s(" psr=", &buff[i], ctx->psr, 16, 1); + i += hal_i2s(" exr=", &buff[i], ctx->excret, 16, 1); + i += hal_i2s(" bfa=", &buff[i], *(u32 *)0xe000ed38, 16, 1); + + i += hal_i2s("\ncfs=", &buff[i], *(u32 *)0xe000ed28, 16, 1); + + buff[i++] = '\n'; + + buff[i] = 0; +} + + +void exceptions_dispatch(unsigned int n, exc_context_t *ctx) +{ + char buff[SIZE_CTXDUMP]; + + hal_exceptionsDumpContext(buff, ctx, n); + hal_consolePrint(ATTR_BOLD, buff); + +#ifdef NDEBUG +#ifdef CPU_NRF91 + _interrupts_nvicSystemReset(); +#endif +#else + hal_cpuHalt(); +#endif +} + + +ptr_t hal_exceptionsPC(exc_context_t *ctx) +{ + return ctx->pc; +} + + +int hal_exceptionsFaultType(unsigned int n, exc_context_t *ctx) +{ + return 0; +} + + +void *hal_exceptionsFaultAddr(unsigned int n, exc_context_t *ctx) +{ + return NULL; +} + + +int hal_exceptionsSetHandler(unsigned int n, void (*handler)(unsigned int, exc_context_t *)) +{ + return 0; +} + + +void _hal_exceptionsInit(void) +{ +} diff --git a/hal/armv8m/hal.c b/hal/armv8m/hal.c new file mode 100644 index 000000000..ca671f1ac --- /dev/null +++ b/hal/armv8m/hal.c @@ -0,0 +1,62 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Hardware Abstraction Layer (ARMv8M) + * + * Copyright 2016-2017, 2022 Phoenix Systems + * Author: Pawel Pisarczyk, Artur Wodejko, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "../hal.h" +struct { + int started; +} hal_common; + + +hal_syspage_t *syspage; + + +extern void _hal_cpuInit(void); + + +void *hal_syspageRelocate(void *data) +{ + return data; +} + + +ptr_t hal_syspageAddr(void) +{ + return (ptr_t)syspage; +} + + +int hal_started(void) +{ + return hal_common.started; +} + + +void _hal_start(void) +{ + hal_common.started = 1; +} + + +void _hal_init(void) +{ + _hal_spinlockInit(); + _hal_exceptionsInit(); + _hal_interruptsInit(); + _hal_cpuInit(); + _hal_consoleInit(); + _hal_timerInit(SYSTICK_INTERVAL); + + hal_common.started = 0; +} diff --git a/hal/armv8m/nrf/91/Makefile b/hal/armv8m/nrf/91/Makefile new file mode 100644 index 000000000..150e3a696 --- /dev/null +++ b/hal/armv8m/nrf/91/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for Phoenix-RTOS kernel (ARMv8 HAL) +# +# Copyright 2016-2017, 2019-2020, 2022 Phoenix Systems +# + +CFLAGS += -Ihal/armv8m/nrf/91 + +OBJS += $(addprefix $(PREFIX_O)hal/armv8m/nrf/91/, nrf91.o console.o timer.o) diff --git a/hal/armv8m/nrf/91/config.h b/hal/armv8m/nrf/91/config.h new file mode 100644 index 000000000..537748415 --- /dev/null +++ b/hal/armv8m/nrf/91/config.h @@ -0,0 +1,27 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Configuration file for nRF9160 + * + * Copyright 2021, 2022 Phoenix Systems + * Author: Hubert Buczynski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_CONFIG_H_ +#define _HAL_CONFIG_H_ + + +#ifndef __ASSEMBLY__ +#include "nrf91.h" +#include "../../include/arch/syspage-nrf91.h" + +#define HAL_NAME_PLATFORM "NRF91 " +#endif + +#endif diff --git a/hal/armv8m/nrf/91/console.c b/hal/armv8m/nrf/91/console.c new file mode 100644 index 000000000..99676dfc6 --- /dev/null +++ b/hal/armv8m/nrf/91/console.c @@ -0,0 +1,205 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * HAL console (nRF9160 UART) + * + * Copyright 2022 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "nrf91.h" + +#include "../../../console.h" +#include "../../../cpu.h" +#include "../../../string.h" +#include "../../spinlock.h" +#include "../../armv8m.h" +#include + +#define TX_DMA_SIZE 64 + + +union { + void *ptr; + const char *str; +} u; + + +static struct { + volatile u32 *base; + u8 txPin; + u8 rxPin; + u8 rtsPin; + u8 ctsPin; + char txDma[TX_DMA_SIZE]; + int txDmaSize; + spinlock_t busySp; +} console_common; + + +/* clang-format off */ +enum { uarte_startrx = 0, uarte_stoprx, uarte_starttx, uarte_stoptx, + uarte_events_cts = 64, uarte_events_txdrdy = 71, uarte_events_endtx, uarte_events_error, uarte_events_txstarted = 84, + uarte_inten = 192, uarte_errorsrc = 288, uarte_intenset, uarte_intenclr, uarte_enable = 320, + uarte_psel_rts = 322, uarte_psel_txd, uarte_psel_cts, uarte_psel_rxd, uarte_baudrate = 329, + uarte_rxd_ptr = 333, uarte_rxd_maxcnt, uarte_rxd_amount, uarte_txd_ptr = 337, uarte_txd_maxcnt, uarte_txd_amount, + uarte_config = 347 }; +/* clang-format on */ + + +/* Init pins according to nrf9160 product specification */ +static void console_configPins(void) +{ + _nrf91_gpioConfig(console_common.txPin, gpio_output, gpio_nopull); + _nrf91_gpioConfig(console_common.rxPin, gpio_input, gpio_nopull); + _nrf91_gpioConfig(console_common.rtsPin, gpio_output, gpio_nopull); + _nrf91_gpioConfig(console_common.ctsPin, gpio_input, gpio_pulldown); + + _nrf91_gpioSet(console_common.txPin, gpio_high); + _nrf91_gpioSet(console_common.rtsPin, gpio_high); +} + + +/* Send cnt bytes of data pointed by ptr using dma in console uart instance */ +static void console_dmaSend(void *ptr, size_t cnt) +{ + *(console_common.base + uarte_txd_ptr) = (u32)ptr; + *(console_common.base + uarte_txd_maxcnt) = cnt; + *(console_common.base + uarte_starttx) = 1u; + while (*(console_common.base + uarte_events_txstarted) != 1u) { + } + *(console_common.base + uarte_events_txstarted) = 0u; + + while (*(console_common.base + uarte_events_endtx) != 1u) { + } + *(console_common.base + uarte_events_endtx) = 0u; +} + + +void _hal_consolePrint(const char *s) +{ + volatile char *tx_dma_buff = (volatile char *)console_common.txDma; + int pos = 0; + size_t len = 0; + + while (s[len] != '\0') { + len++; + } + + /* copy to RAM only if it's not there. (6.7.7. EasyDMA chapter in NRF9160 PS) */ + if (((u32)s & 0xE0000000u) == 0x20000000u) { + /* avoid discarding const */ + u.str = s; + console_dmaSend(u.ptr, len); + } + /* copy to RAM */ + else { + while (s[pos] != '\0') { + len = 0; + while ((s[pos] != '\0') && (len < console_common.txDmaSize)) { + tx_dma_buff[len++] = s[pos++]; + } + console_dmaSend(console_common.txDma, len); + } + } +} + + +void hal_consolePrint(int attr, const char *s) +{ + spinlock_ctx_t sc; + + hal_spinlockSet(&console_common.busySp, &sc); + + if (attr == ATTR_BOLD) { + _hal_consolePrint(CONSOLE_BOLD); + } + else if (attr != ATTR_USER) { + _hal_consolePrint(CONSOLE_CYAN); + } + + _hal_consolePrint(s); + _hal_consolePrint(CONSOLE_NORMAL); + + hal_spinlockClear(&console_common.busySp, &sc); +} + + +void hal_consolePutch(const char c) +{ + volatile char *tx_dma_buff = (volatile char *)console_common.txDma; + spinlock_ctx_t sc; + + hal_spinlockSet(&console_common.busySp, &sc); + tx_dma_buff[0] = c; + console_dmaSend(console_common.txDma, 1); + hal_spinlockClear(&console_common.busySp, &sc); +} + + +/* UART0 supported for the hal console */ +void _hal_consoleInit(void) +{ + const struct { + u8 uart; + volatile u32 *base; + u8 txPin; + u8 rxPin; + u8 rtsPin; + u8 ctsPin; + } uarts[] = { + { 0, (u32 *)0x50008000u, UART0_TX, UART0_RX, UART0_RTS, UART0_CTS }, + { 1, (u32 *)0x50009000u, UART1_TX, UART1_RX, UART1_RTS, UART1_CTS }, + { 2, (u32 *)0x5000a000u, UART2_TX, UART2_RX, UART2_RTS, UART2_CTS }, + { 3, (u32 *)0x5000b000u, UART3_TX, UART3_RX, UART3_RTS, UART3_CTS } + }; + + const int uart = UART_CONSOLE; + console_common.base = uarts[uart].base; + console_common.txPin = uarts[uart].txPin; + console_common.rxPin = uarts[uart].rxPin; + console_common.rtsPin = uarts[uart].rtsPin; + console_common.ctsPin = uarts[uart].ctsPin; + console_common.txDmaSize = sizeof(console_common.txDma); + + hal_spinlockCreate(&console_common.busySp, "dmaBusy"); + + console_configPins(); + + /* disable uarte instance */ + *(console_common.base + uarte_enable) = 0u; + hal_cpuDataMemoryBarrier(); + + /* Select pins */ + *(console_common.base + uarte_psel_txd) = console_common.txPin; + *(console_common.base + uarte_psel_rxd) = console_common.rxPin; + *(console_common.base + uarte_psel_rts) = console_common.rtsPin; + *(console_common.base + uarte_psel_cts) = console_common.ctsPin; + + /* set baud rate to 115200 */ + *(console_common.base + uarte_baudrate) = 0x01d60000u; + + /* Default settings - hardware flow control disabled, exclude parity bit, one stop bit */ + *(console_common.base + uarte_config) = 0u; + + /* Set default max number of bytes in specific buffers */ + *(console_common.base + uarte_txd_maxcnt) = TX_DMA_SIZE; + + + /* Set default memory regions for uart dma */ + *(console_common.base + uarte_txd_ptr) = (volatile u32)console_common.txDma; + + /* disable all uart interrupts */ + *(console_common.base + uarte_intenclr) = 0xffffffffu; + hal_cpuDataMemoryBarrier(); + + /* enable uarte instance */ + *(console_common.base + uarte_enable) = 0x8u; + hal_cpuDataMemoryBarrier(); +} diff --git a/hal/armv8m/nrf/91/nrf91.c b/hal/armv8m/nrf/91/nrf91.c new file mode 100644 index 000000000..a6808b388 --- /dev/null +++ b/hal/armv8m/nrf/91/nrf91.c @@ -0,0 +1,221 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * nRF91 basic peripherals control functions + * + * Copyright 2022 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "nrf91.h" + +#include "../../../cpu.h" +#include "../../armv8m.h" +#include "../../../../include/errno.h" + + +static struct { + volatile u32 *scb; + volatile u32 *power; + volatile u32 *clock; + volatile u32 *gpio; + u32 cpuclk; + spinlock_t pltctlSp; +} nrf91_common; + + +/* clang-format off */ +enum { power_tasks_constlat = 30, power_tasks_lowpwr, power_inten = 192, power_intenset, power_intenclr, power_status = 272}; + + +enum { clock_tasks_hfclkstart = 0, clock_inten = 192, clock_intenset, clock_intenclr, clock_hfclkrun = 258, clock_hfclkstat }; + + +enum { gpio_out = 1, gpio_outset, gpio_outclr, gpio_in, gpio_dir, gpio_dirsetout, gpio_dirsetin, gpio_cnf = 128 }; + + +enum { syst_csr = 4, syst_rvr, syst_cvr, syst_calib }; + + +enum { fpu_cpacr = 34, fpu_fpccr = 141, fpu_fpcar, fpu_fpdscr }; +/* clang-format on */ + + +/* platformctl syscall */ + + +/* TODO: add platformctl implementation */ +int hal_platformctl(void *ptr) +{ + return -ENOSYS; +} + + +void _nrf91_platformInit(void) +{ + hal_spinlockCreate(&nrf91_common.pltctlSp, "pltctl"); +} + + +/* SysTick */ + + +int _nrf91_systickInit(u32 interval) +{ + u64 load = ((u64)interval * nrf91_common.cpuclk) / 1000000; + if (load > 0x00ffffff) { + return -EINVAL; + } + + *(nrf91_common.scb + syst_rvr) = (u32)load; + *(nrf91_common.scb + syst_cvr) = 0u; + + /* Enable systick */ + *(nrf91_common.scb + syst_csr) |= 0x7u; + + return EOK; +} + + +/* GPIO */ + + +int _nrf91_gpioConfig(u8 pin, u8 dir, u8 pull) +{ + if (pin > 31) { + return -1; + } + + if (dir == gpio_output) { + *(nrf91_common.gpio + gpio_dirsetout) = (1u << pin); + hal_cpuDataMemoryBarrier(); + } + else if (dir == gpio_input) { + *(nrf91_common.gpio + gpio_dirsetin) = (1u << pin); + hal_cpuDataMemoryBarrier(); + /* connect input buffer */ + *(nrf91_common.gpio + gpio_cnf + pin) &= ~0x2; + } + + if (pull) { + *(nrf91_common.gpio + gpio_cnf + pin) = (pull << 2); + } + + return 0; +} + + +int _nrf91_gpioSet(u8 pin, u8 val) +{ + if (pin > 31) { + return -1; + } + + if (val == gpio_high) { + *(nrf91_common.gpio + gpio_outset) = (1u << pin); + hal_cpuDataMemoryBarrier(); + } + else if (val == gpio_low) { + *(nrf91_common.gpio + gpio_outclr) = (1u << pin); + hal_cpuDataMemoryBarrier(); + } + + return 0; +} + + +/* SCB */ + + +void _nrf91_scbSetPriorityGrouping(u32 group) +{ + u32 t; + + /* Get register value and clear bits to set */ + t = *(nrf91_common.scb + scb_aircr) & ~0xffff0700; + + /* Set AIRCR.PRIGROUP to 3: 16 priority groups and 16 subgroups + The value is same as for armv7m4-stm32l4x6 target + Setting various priorities is not supported on Phoenix-RTOS, so it's just default value */ + *(nrf91_common.scb + scb_aircr) = t | 0x5fa0000 | ((group & 7) << 8); +} + + +u32 _nrf91_scbGetPriorityGrouping(void) +{ + return (*(nrf91_common.scb + scb_aircr) & 0x700) >> 8; +} + + +void _nrf91_scbSetPriority(s8 excpn, u32 priority) +{ + volatile u8 *ptr; + + ptr = &((u8 *)(nrf91_common.scb + scb_shp1))[excpn - 4]; + + /* We set only group priority field */ + *ptr = (priority << 4) & 0xff; +} + + +u32 _nrf91_scbGetPriority(s8 excpn) +{ + volatile u8 *ptr; + + ptr = &((u8 *)(nrf91_common.scb + scb_shp1))[excpn - 4]; + + return *ptr >> 4; +} + + +/* CPU info */ + + +unsigned int _nrf91_cpuid(void) +{ + return *(nrf91_common.scb + scb_cpuid); +} + + +void _nrf91_init(void) +{ + nrf91_common.scb = (void *)0xe000e000; + nrf91_common.power = (void *)0x50005000; + nrf91_common.clock = (void *)0x50005000; + nrf91_common.gpio = (void *)0x50842500; + + /* Based on nRF9160 product specification there is fixed cpu frequency */ + nrf91_common.cpuclk = 64 * 1000 * 1000; + + /* Enable low power mode */ + *(nrf91_common.power + power_tasks_lowpwr) = 1u; + hal_cpuDataMemoryBarrier(); + + /* Disable all power interrupts */ + *(nrf91_common.power + power_intenclr) = 0x64u; + + /* Disable all clock interrupts */ + *(nrf91_common.power + power_intenclr) = 0x3u; + + hal_cpuDataMemoryBarrier(); + + *(nrf91_common.clock + clock_tasks_hfclkstart) = 1u; + /* Wait until HXFO start and clear event flag */ + while (*(nrf91_common.clock + clock_hfclkrun) != 1u) { + } + *(nrf91_common.clock + clock_hfclkrun) = 0u; + hal_cpuDataMemoryBarrier(); + + /* Enable UsageFault, BusFault and MemManage exceptions */ + *(nrf91_common.scb + scb_shcsr) |= (1u << 16) | (1u << 17) | (1u << 18); + + /* Disable FPU */ + *(nrf91_common.scb + fpu_cpacr) = 0u; + *(nrf91_common.scb + fpu_fpccr) = 0u; +} diff --git a/hal/armv8m/nrf/91/nrf91.h b/hal/armv8m/nrf/91/nrf91.h new file mode 100644 index 000000000..748539392 --- /dev/null +++ b/hal/armv8m/nrf/91/nrf91.h @@ -0,0 +1,69 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * nRF91 basic peripherals control functions + * + * Copyright 2022 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _HAL_NRF91_H_ +#define _HAL_NRF91_H_ + +#include +#include "../pmap.h" + +#include "../../../include/arch/nrf9160.h" + + +/* clang-format off */ +enum { gpio_input = 0, gpio_output }; +enum { gpio_low = 0, gpio_high }; +enum { gpio_nopull = 0, gpio_pulldown, gpio_pullup = 3}; + + +enum { scb_actlr = 2, scb_cpuid = 832, scb_icsr, scb_vtor, scb_aircr, scb_scr, scb_ccr, scb_shp1, scb_shp2, + scb_shp3, scb_shcsr, scb_cfsr, scb_mmsr, scb_bfsr, scb_ufsr, scb_hfsr, scb_mmar, scb_bfar, scb_afsr }; +/* clang-format on */ + + +extern void _nrf91_platformInit(void); + + +extern int hal_platformctl(void *); + + +extern void _nrf91_platformInit(void); + + +extern int _nrf91_systickInit(u32 interval); + + +extern int _nrf91_gpioConfig(u8 pin, u8 dir, u8 pull); + + +extern int _nrf91_gpioSet(u8 pin, u8 val); + + +extern void _nrf91_scbSetPriorityGrouping(u32 group); + + +extern u32 _nrf91_scbGetPriorityGrouping(void); + + +extern void _nrf91_scbSetPriority(s8 excpn, u32 priority); + + +extern u32 _nrf91_scbGetPriority(s8 excpn); + + +extern unsigned int _nrf91_cpuid(void); + + +#endif diff --git a/hal/armv8m/nrf/91/timer.c b/hal/armv8m/nrf/91/timer.c new file mode 100644 index 000000000..acd3e0449 --- /dev/null +++ b/hal/armv8m/nrf/91/timer.c @@ -0,0 +1,127 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * System timer driver + * + * Copyright 2022 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "config.h" +#include "../../armv8m.h" +#include "../../../timer.h" +#include "../../../interrupts.h" +#include "../../../spinlock.h" + + +/* nrf9160 timer module provides instances from 0 to 2 */ +#ifndef KERNEL_TIMER_INSTANCE +#define KERNEL_TIMER_INSTANCE 0 +#endif + + +static struct { + volatile u32 *timer[3]; + intr_handler_t overflowh; + spinlock_t sp; + volatile time_t timeUs; + volatile u32 *lptim; + volatile time_t upper; + volatile int wakeup; + u32 interval; +} timer_common; + + +/* clang-format off */ +enum { timer_tasks_start = 0, timer_tasks_stop, timer_tasks_count, timer_tasks_clear, timer_tasks_shutdown, + timer_tasks_capture0 = 16, timer_tasks_capture1, timer_tasks_capture2, timer_tasks_capture3, timer_tasks_capture4, timer_tasks_capture5, + timer_events_compare0 = 80, timer_events_compare1, timer_events_compare2, timer_events_compare3, timer_events_compare4, timer_events_compare5, + timer_intenset = 193, timer_intenclr, timer_mode = 321, timer_bitmode, timer_prescaler = 324, + timer_cc0 = 336, timer_cc1, timer_cc2, timer_cc3, timer_cc4, timer_cc5 }; +/* clang-format on */ + +static int timer_irqHandler(unsigned int n, cpu_context_t *ctx, void *arg) +{ + (void)n; + (void)ctx; + (void)arg; + int ret = 0; + + /* Clear compare event */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_events_compare0) = 0u; + /* Clear counter */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_tasks_clear) = 1u; + + timer_common.timeUs += timer_common.interval; + hal_cpuDataSyncBarrier(); + + return ret; +} + + +/* Interface functions */ + + +void hal_timerSetWakeup(u32 when) +{ +} + + +time_t hal_timerGetUs(void) +{ + return timer_common.timeUs; +} + + +int hal_timerRegister(int (*f)(unsigned int, cpu_context_t *, void *), void *data, intr_handler_t *h) +{ + h->f = f; + h->n = SYSTICK_IRQ; + h->data = data; + + return hal_interruptsSetHandler(h); +} + + +void _hal_timerInit(u32 interval) +{ + /* using nrf9160 timer module */ + timer_common.timer[0] = (void *)0x5000f000u; + timer_common.timer[1] = (void *)0x50010000u; + timer_common.timer[2] = (void *)0x50011000u; + timer_common.upper = 0; + timer_common.wakeup = 0; + timer_common.timeUs = 0; + timer_common.interval = interval; + + hal_spinlockCreate(&timer_common.sp, "timer"); + + /* Set timer mode */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_mode) = 0u; + /* Set 16-bit mode */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_bitmode) = 0u; + /* 1 tick per 1 us */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_prescaler) = 4u; + /* 1 compare event per interval * 1us */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_cc0) = interval; + /* Enable interrupts from compare0 events */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_intenset) = 0x10000; + + /* Clear and start timer0 */ + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_tasks_clear) = 1u; + *(timer_common.timer[KERNEL_TIMER_INSTANCE] + timer_tasks_start) = 1u; + + timer_common.overflowh.f = timer_irqHandler; + /* irq number always equals nrf peripheral id + 16 */ + timer_common.overflowh.n = timer0_irq + 16; + timer_common.overflowh.got = NULL; + timer_common.overflowh.data = NULL; + hal_interruptsSetHandler(&timer_common.overflowh); + _nrf91_systickInit(interval); +} diff --git a/hal/armv8m/nrf/Makefile b/hal/armv8m/nrf/Makefile new file mode 100644 index 000000000..a8b87d3b3 --- /dev/null +++ b/hal/armv8m/nrf/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for Phoenix-RTOS kernel (ARMv8 HAL) +# +# Copyright 2016-2017, 2019-2020, 2022 Phoenix Systems +# + + +ifneq (, $(findstring nrf91, $(TARGET_SUBFAMILY))) + include hal/armv8m/nrf/91/Makefile +endif + +CFLAGS += -Ihal/armv8m/nrf + +OBJS += $(addprefix $(PREFIX_O)hal/armv8m/nrf/, _init.o interrupts.o) diff --git a/hal/armv8m/nrf/_init.S b/hal/armv8m/nrf/_init.S new file mode 100644 index 000000000..b9c04e0d1 --- /dev/null +++ b/hal/armv8m/nrf/_init.S @@ -0,0 +1,314 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Low-level initialization for Cortex-M33 (ARMv8) architecture + * + * Copyright 2012, 2016-2017, 2022 Phoenix Systems + * Author: Jacek Popko, Pawel Pisarczyk, Jakub Sejdak, Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#define __ASSEMBLY__ + +#include + +#define ADDR_SCB 0xe000ed00u + +.syntax unified +.cpu cortex-m33 + + +.extern _cpu_nctx +.extern syscalls +.extern syspage + + +.section .init, "x" + +.globl _init_vectors +.type _init_vectors, %object +_init_vectors: +.word _end + 1024 + 256 +.word _start + +.word _exceptions_dispatch /* NMI */ +.word _exceptions_dispatch /* HardFault */ +.word _exceptions_dispatch /* MemMgtFault */ +.word _exceptions_dispatch /* BusFault */ +.word _exceptions_dispatch /* UsageFault */ +.word _exceptions_dispatch /* SecureFault */ +.word 0 +.word 0 +.word 0 +.word _syscall_dispatch /* SVC */ +.word _exceptions_dispatch /* Debug */ +.word 0 +.word _pendsv /* PendSV */ +.word _interrupts_dispatch /* Systick */ + +.rept 67 /* Max number of ext interrupts - last peripheral id + 1 */ +.word _interrupts_dispatch +.endr +.size _init_vectors, .-_init_vectors + + +.thumb +.thumb_func + +.globl _start +.type _start, %function + +_start: + cpsid if + isb + + /* Point to syspage */ + ldr r8, =syspage + str r9, [r8] + + /* Init vector table pointer */ + ldr r0, =0xe000ed08u + ldr r1, =_init_vectors + str r1, [r0] + isb + dmb + bl _nrf91_init + + bl main +.size _start, .-_start +.ltorg + +.globl _syscall_dispatch +.type _syscall_dispatch, %function +.type _syscallend, %function + +_syscall_dispatch: + mov r0, #0 + msr control, r0 + isb + + stmdb sp!, {r4-r8} + mrs r0, psp + + /* Store hardware saved registers on kernel stack */ + ldmia r0!, {r1-r8} + + /* Fix PC LSB not being set */ + orr r7, r7, #1 + + stmdb sp!, {r1-r8} + push {r0} + + /* Copy arguments back to the user stack */ + stmdb r0!, {r1-r4} + mov r1, r0 + ldrb r0, [r7, #-3] + + /* Prepare pseudo context */ + mov r7, #0x01000000 + ldr r6, =syscalls_dispatch + ldr r5, =_syscallend + stmdb sp!, {r0-r7} /* PSR, PC, LR, R12, R3, R2, R1, R0 */ + + /* Exit handler mode to kernel thread mode */ + ldr lr,=RET_THREAD_MSP + bx lr + +_syscallend: + pop {lr} + + ldmia sp!, {r1-r8} + mov r1, r0 /* Put result to user's r0 */ + stmdb lr!, {r1-r8} + + ldmia sp!, {r4-r8} + + /* Switch stacks */ + mov r0, #3 + msr control, r0 + isb + + ldmia sp!, {r0-r3, r12, lr} + ldr pc, [sp], #8 + +.size _syscall_dispatch, .-_syscall_dispatch +.ltorg + +.globl _exceptions_dispatch +.type _exceptions_dispatch, %function + +_exceptions_dispatch: + cpsid if + isb + + mrs r0, psp + stmdb sp!, {r0, r4-r11, lr} + + mrs r0, ipsr + mov r1, sp + b exceptions_dispatch +.size _exceptions_dispatch, .-_exceptions_dispatch +.ltorg + +.globl _pendsv +.type _pendsv, %function +_pendsv: + mov r0, #0 + msr control, r0 + isb + + mrs r0, ipsr + mrs r3, psp + sub r1, sp, #48 + stmdb sp!, {r1-r11, lr} + + ldr r5, =_cpu_nctx + ldr r6, [r5] + cmp r6, #0 + beq _intd0 + mov sp, r6 + isb + mov r6, #0 + str r6, [r5] + dmb + b _intd1 +.size _pendsv, .-_pendsv +.ltorg + +.globl _interrupts_dispatch +.type _interrupts_dispatch, %function +_interrupts_dispatch: + mov r0, #0 + msr control, r0 + isb + + mrs r0, ipsr + mrs r3, psp + sub r1, sp, #48 + stmdb sp!, {r1-r11, lr} + +_intd0: + bl interrupts_dispatch + ldr r1, [sp] + mov sp, r1 + isb +_intd1: + ldmia sp!, {r1-r11, lr} + + msr psp, r3 + isb + + /* Check if we're returning to userspace */ + and r1, lr, #4 + ror r1, r1, #2 + msr control, r1 + isb + + bx lr +.size _interrupts_dispatch, .-_interrupts_dispatch +.ltorg + + +.globl _hal_invokePendSV +.type _hal_invokePendSV, %function +_hal_invokePendSV: + mov r1, #(1 << 28) + ldr r2, =ADDR_SCB + str r1, [r2, #4] + bx lr +.size _hal_invokePendSV, .-_hal_invokePendSV +.ltorg + +.globl hal_cpuReschedule +.type hal_cpuReschedule, %function +hal_cpuReschedule: + push {r0-r2, lr} + eor r0, r0, r0 /* default return value */ + bl _hal_invokePendSV + pop {r1-r3, lr} + cmp r1, #NULL + beq hal_cpuReschedule0 + push {r3-r4} + add r1, r1, #12 + +spinlock: + ldrexb r3, [r1] + add r3, r3, #1 + dmb + strexb r4, r3, [r1] + cmp r4, #0 + bne spinlock + pop {r3-r4} + ldr r2, [r2] + msr primask, r2 +hal_cpuReschedule0: + isb + dmb + bx lr +.size hal_cpuReschedule, .-hal_cpuReschedule +.ltorg + + +.globl hal_jmp /* void hal_jmp(void *f, void *kstack, void *stack, int argc) */ +.type hal_jmp, %function +hal_jmp: + push {r0-r3} + pop {r4-r7} + + cpsid if + isb + + cmp r2, #NULL + bne hal_jmp_user + + mov sp, r5 + subs r7, #1 + bmi 1f + pop {r0} + subs r7, #1 + bmi 1f + pop {r1} + subs r7, #1 + bmi 1f + pop {r2} + subs r7, #1 + bmi 1f + pop {r3} +1: + cpsie if + isb + dmb + bx r4 + +hal_jmp_user: + cpsid if + msr msp, r5 + subs r7, #1 + bmi 2f + pop {r0} + subs r7, #1 + bmi 2f + pop {r1} + subs r7, #1 + bmi 2f + pop {r2} + subs r7, #1 + bmi 2f + pop {r3} +2: + msr psp, r6 + cpsie if + isb + mov r5, #0x3 + msr control, r5 + isb + dmb + bx r4 + +.size hal_jmp, .-hal_jmp +.ltorg diff --git a/hal/armv8m/nrf/interrupts.c b/hal/armv8m/nrf/interrupts.c new file mode 100644 index 000000000..155c0b4b2 --- /dev/null +++ b/hal/armv8m/nrf/interrupts.c @@ -0,0 +1,228 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Interrupt handling + * + * Copyright 2017, 2020, 2022 Phoenix Systems + * Author: Pawel Pisarczyk, Hubert Buczynski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "../../interrupts.h" +#include "../../spinlock.h" +#include "../../cpu.h" +#include "../armv8m.h" +#include "config.h" +#include "91/nrf91.h" + +#include "../../../proc/userintr.h" + + +#ifdef CPU_NRF91 +/* Based on INTLINESNUM value (ICTR cpu register) */ +#define SIZE_INTERRUPTS 256 +#endif + +/* Value based on other target architectures */ +#define SIZE_HANDLERS 4 + + +#define _intr_add(list, t) \ + do { \ + if (t == NULL) { \ + break; \ + } \ + if (*list == NULL) { \ + t->next = t; \ + t->prev = t; \ + (*list) = t; \ + break; \ + } \ + t->prev = (*list)->prev; \ + (*list)->prev->next = t; \ + t->next = (*list); \ + (*list)->prev = t; \ + } while (0) + + +#define _intr_remove(list, t) \ + do { \ + if (t == NULL) { \ + break; \ + } \ + if ((t->next == t) && (t->prev == t)) { \ + (*list) = NULL; \ + } \ + else { \ + t->prev->next = t->next; \ + t->next->prev = t->prev; \ + if (t == (*list)) \ + (*list) = t->next; \ + } \ + t->next = NULL; \ + t->prev = NULL; \ + } while (0) + + +static struct { + volatile u32 *nvic; + volatile u32 *scb; + spinlock_t spinlock; + intr_handler_t *handlers[SIZE_INTERRUPTS]; + unsigned int counters[SIZE_INTERRUPTS]; +} interrupts; + + +/* clang-format off */ +enum { nvic_iser = 0, nvic_icer = 32, nvic_ispr = 64, nvic_icpr = 96, nvic_iabr = 128, + nvic_ip = 192 }; +/* clang-format on */ + + +extern int threads_schedule(unsigned int n, cpu_context_t *context, void *arg); + + +void _interrupts_nvicSetIRQ(s8 irqn, u8 state) +{ + volatile u32 *ptr = interrupts.nvic + ((u8)irqn >> 5) + (state ? nvic_iser : nvic_icer); + *ptr = 1 << (irqn & 0x1F); + + hal_cpuDataSyncBarrier(); + hal_cpuInstrBarrier(); +} + + +void _interrupts_nvicSetPriority(s8 irqn, u32 priority) +{ + volatile u32 *ptr; + + ptr = ((u32 *)(interrupts.nvic + nvic_ip)) + (irqn / 4); + + /* We set only group priority field */ + *ptr = (priority << (8 * (irqn % 4) + 4)); +} + + +void _interrupts_nvicSystemReset(void) +{ + *(interrupts.scb + scb_aircr) = ((0x5fau << 16) | (*(interrupts.scb + scb_aircr) & (0x700u)) | (1u << 2)); + + hal_cpuDataSyncBarrier(); + + for (;;) { + } +} + + +void interrupts_dispatch(unsigned int n, cpu_context_t *ctx) +{ + intr_handler_t *h; + int reschedule = 0; + spinlock_ctx_t sc; + + if (n >= SIZE_INTERRUPTS) { + return; + } + + hal_spinlockSet(&interrupts.spinlock, &sc); + + interrupts.counters[n]++; + + if ((h = interrupts.handlers[n]) != NULL) { + do { + hal_cpuSetGot(h->got); + if (h->f(n, ctx, h->data)) { + reschedule = 1; + } + } while ((h = h->next) != interrupts.handlers[n]); + } + + hal_spinlockClear(&interrupts.spinlock, &sc); + + if (reschedule) + threads_schedule(n, ctx, NULL); +} + + +int hal_interruptsSetHandler(intr_handler_t *h) +{ + spinlock_ctx_t sc; + + if (h == NULL || h->f == NULL || h->n >= SIZE_INTERRUPTS) { + return -1; + } + + hal_spinlockSet(&interrupts.spinlock, &sc); + h->got = hal_cpuGetGot(); + + /* adding to interrupt handlers tree */ + _intr_add(&interrupts.handlers[h->n], h); + + if (h->n >= 0x10) { + _interrupts_nvicSetPriority(h->n - 0x10, 1); + _interrupts_nvicSetIRQ(h->n - 0x10, 1); + } + hal_spinlockClear(&interrupts.spinlock, &sc); + + return 0; +} + + +int hal_interruptsDeleteHandler(intr_handler_t *h) +{ + spinlock_ctx_t sc; + + if (h == NULL || h->f == NULL || h->n >= SIZE_INTERRUPTS) { + return -1; + } + + hal_spinlockSet(&interrupts.spinlock, &sc); + _intr_remove(&interrupts.handlers[h->n], h); + + if (h->n >= 0x10 && interrupts.handlers[h->n] == NULL) { + _interrupts_nvicSetIRQ(h->n - 0x10, 0); + } + + hal_spinlockClear(&interrupts.spinlock, &sc); + + return 0; +} + + +char *hal_interruptsFeatures(char *features, unsigned int len) +{ + hal_strncpy(features, "Using NVIC interrupt controller", len); + features[len - 1] = 0; + + return features; +} + + +__attribute__((section(".init"))) void _hal_interruptsInit(void) +{ + unsigned int n; + + for (n = 0; n < SIZE_INTERRUPTS; ++n) { + interrupts.handlers[n] = NULL; + interrupts.counters[n] = 0; + } + + interrupts.nvic = (void *)0xe000e100; + interrupts.scb = (void *)0xe000e000; + + hal_spinlockCreate(&interrupts.spinlock, "interrupts.spinlock"); + + _nrf91_scbSetPriority(SYSTICK_IRQ, 1); + _nrf91_scbSetPriority(PENDSV_IRQ, 1); + _nrf91_scbSetPriority(SVC_IRQ, 0); + + /* Set no subprorities in Interrupt Group Priority */ + _nrf91_scbSetPriorityGrouping(3); + + return; +} diff --git a/hal/armv8m/pmap.c b/hal/armv8m/pmap.c new file mode 100644 index 000000000..569c1f2aa --- /dev/null +++ b/hal/armv8m/pmap.c @@ -0,0 +1,103 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * pmap - machine dependent part of VM subsystem (ARMv8) + * + * Copyright 2017, 2020-2022 Phoenix Systems + * Author: Pawel Pisarczyk, Aleksander Kaminski, Hubert Buczynski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "../pmap.h" +#include + +/* Linker symbols */ +extern unsigned int _end; +extern unsigned int __bss_start; + +extern void *_init_vectors; + + +/* Function creates empty page table */ +int pmap_create(pmap_t *pmap, pmap_t *kpmap, page_t *p, void *vaddr) +{ + return 0; +} + + +addr_t pmap_destroy(pmap_t *pmap, int *i) +{ + return 0; +} + + +void pmap_switch(pmap_t *pmap) +{ +} + + +int pmap_enter(pmap_t *pmap, addr_t pa, void *vaddr, int attr, page_t *alloc) +{ + return 0; +} + + +int pmap_remove(pmap_t *pmap, void *vaddr) +{ + return 0; +} + + +addr_t pmap_resolve(pmap_t *pmap, void *vaddr) +{ + return (addr_t)vaddr; +} + + +int pmap_getPage(page_t *page, addr_t *addr) +{ + return 0; +} + + +char pmap_marker(page_t *p) +{ + return 0; +} + + +int _pmap_kernelSpaceExpand(pmap_t *pmap, void **start, void *end, page_t *dp) +{ + return 0; +} + + +int pmap_segment(unsigned int i, void **vaddr, size_t *size, int *prot, void **top) +{ + if (i != 0) { + return -1; + } + + /* Returns region above basic kernel's .bss section */ + *vaddr = (void *)&_end; + *size = (((size_t)(*top) + SIZE_PAGE - 1) & ~(SIZE_PAGE - 1)) - (size_t)&_end; + + return 0; +} + + +void _pmap_init(pmap_t *pmap, void **vstart, void **vend) +{ + (*vstart) = (void *)(((ptr_t)_init_vectors + 7) & ~7u); + (*vend) = (*((char **)vstart)) + SIZE_PAGE; + + pmap->start = (void *)&__bss_start; + + /* Initial size of kernel map */ + pmap->end = (void *)((addr_t)&__bss_start + 32 * 1024); +} diff --git a/hal/armv8m/spinlock.c b/hal/armv8m/spinlock.c new file mode 100644 index 000000000..55c61eef8 --- /dev/null +++ b/hal/armv8m/spinlock.c @@ -0,0 +1,120 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Spinlock + * + * Copyright 2017, 2022 Phoenix Systems + * Author: Pawel Pisarczyk, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "../spinlock.h" + +static struct { + spinlock_t spinlock; + spinlock_t *first; +} spinlocks; + + +void hal_spinlockSet(spinlock_t *spinlock, spinlock_ctx_t *sc) +{ + /* clang-format off */ + __asm__ volatile(" \ + mrs r2, primask; \ + cpsid i; \ + str r2, [%0]; \ + mov r3, #0; \ + 1: \ + ldrexb r2, [%1]; \ + cmp r2, #0; \ + beq 1b; \ + strexb r2, r3, [%1]; \ + cmp r2, #0; \ + bne 1b; \ + dmb" + : + : "r" (sc), "r" (&spinlock->lock) + : "r2", "r3", "memory", "cc"); + /* clang-format on */ +} + + +void hal_spinlockClear(spinlock_t *spinlock, spinlock_ctx_t *sc) +{ + /* clang-format off */ + __asm__ volatile (" \ + 1 : \ + ldrexb r2, [%0]; \ + add r2, r2, #1; \ + dmb; \ + strexb r3, r2, [%0]; \ + cmp r3, #0; \ + bne 1b; \ + ldr r2, [%1]; \ + msr primask, r2;" + : + : "r" (&spinlock->lock), "r" (sc) + : "r2", "r3", "memory", "cc"); + /* clang-format on */ +} + + +void _hal_spinlockCreate(spinlock_t *spinlock, const char *name) +{ + spinlock->lock = 1; + spinlock->name = name; + + if (spinlocks.first != NULL) { + spinlocks.first->prev->next = spinlock; + spinlock->prev = spinlocks.first->prev; + spinlock->next = spinlocks.first; + spinlocks.first->prev = spinlock; + } + else { + spinlocks.first = spinlock; + spinlock->next = spinlock; + spinlock->prev = spinlock; + } + return; +} + + +void hal_spinlockCreate(spinlock_t *spinlock, const char *name) +{ + spinlock_ctx_t sc; + + hal_spinlockSet(&spinlocks.spinlock, &sc); + _hal_spinlockCreate(spinlock, name); + hal_spinlockClear(&spinlocks.spinlock, &sc); +} + + +void hal_spinlockDestroy(spinlock_t *spinlock) +{ + spinlock_ctx_t sc; + + hal_spinlockSet(&spinlocks.spinlock, &sc); + + if (spinlock->next == spinlock) { + spinlocks.first = NULL; + } + else { + spinlock->prev->next = spinlock->next; + spinlock->next->prev = spinlock->prev; + } + spinlock->prev = spinlock->next = NULL; + + hal_spinlockClear(&spinlocks.spinlock, &sc); +} + + +__attribute__((section(".init"))) void _hal_spinlockInit(void) +{ + spinlocks.first = NULL; + _hal_spinlockCreate(&spinlocks.spinlock, "spinlocks.spinlock"); +} diff --git a/hal/armv8m/string.c b/hal/armv8m/string.c new file mode 100644 index 000000000..e542da8e7 --- /dev/null +++ b/hal/armv8m/string.c @@ -0,0 +1,256 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * HAL basic routines + * + * Copyright 2017, 2022 Phoenix Systems + * Copyright 2001, 2005-2006 Pawel Pisarczyk + * Author: Pawel Pisarczyk, Artur Wodejko, Aleksander Kaminski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "../string.h" + + +void hal_memcpy(void *dst, const void *src, unsigned int l) +{ + /* clang-format off */ + __asm__ volatile + (" \ + orr r3, %0, %1; \ + lsls r3, r3, #30; \ + bne 2f; \ + 1: \ + cmp %2, #4; \ + ittt hs; \ + ldrhs r3, [%1], #4; \ + strhs r3, [%0], #4; \ + subshs %2, #4; \ + bhs 1b; \ + 2: \ + cmp %2, #0; \ + ittt ne; \ + ldrbne r3, [%1], #1; \ + strbne r3, [%0], #1; \ + subsne %2, #1; \ + bne 2b" + : "+r" (dst), "+r" (src), "+r" (l) + : + : "r3", "memory", "cc"); + +} + + +int hal_memcmp(const void *ptr1, const void *ptr2, size_t num) +{ + int res = 0; + + __asm__ volatile + (" \ + 1: \ + cmp %3, #0; \ + beq 3f; \ + sub %3, #1; \ + ldrb r3, [%1], #1; \ + ldrb r4, [%2], #1; \ + cmp r3, r4; \ + beq 1b; \ + blo 2f; \ + mov %0, #1; \ + b 3f; \ + 2: \ + mov %0, #-1; \ + 3: " + : "+r" (res), "+r" (ptr1), "+r" (ptr2), "+r" (num) + : + : "r3", "r4", "memory", "cc"); + + return res; +} + + +void hal_memset(void *dst, int v, unsigned int l) +{ + unsigned int v1 = v & 0xffu; + unsigned int tmp; + + tmp = (v1 << 8) | v1; + tmp |= (tmp << 16u); + + __asm__ volatile + (" \ + lsls r3, %0, #30; \ + bne 2f; \ + 1: \ + cmp %2, #4; \ + itt hs; \ + strhs %1, [%0], #4; \ + subshs %2, #4; \ + bhs 1b; \ + 2: \ + cmp %2, #0; \ + itt ne; \ + strbne %1, [%0], #1; \ + subsne %2, #1; \ + bne 2b" + : "+r"(dst), "+r" (tmp), "+r" (l) + : + : "r3", "memory", "cc"); +} + + +unsigned int hal_strlen(const char *s) +{ + unsigned int k = 0; + + __asm__ volatile + (" \ + 1: \ + ldrb r1, [%1, %0]; \ + cbz r1, 2f; \ + add %0, #1; \ + b 1b; \ + 2:" + : "+r" (k), "+r" (s) + : + : "r1", "memory", "cc"); + + return k; +} + + +int hal_strcmp(const char *s1, const char *s2) +{ + int res = 0; + + __asm__ volatile + (" \ + 1: \ + ldrb r2, [%1], #1; \ + ldrb r3, [%2], #1; \ + cbz r2, 2f; \ + cmp r2, r3; \ + beq 1b; \ + blo 3f; \ + mov %0, #1; \ + b 4f; \ + 2: \ + cmp r3, #0; \ + beq 4f; \ + 3: \ + mov %0, #-1; \ + 4: " + : "+r" (res), "+r" (s1), "+r" (s2) + : + : "r2", "r3", "memory", "cc"); + + return res; +} + + +int hal_strncmp(const char *s1, const char *s2, unsigned int count) +{ + int res = 0; + + __asm__ volatile + (" \ + 1: \ + cmp %3, #0; \ + beq 4f; \ + sub %3, #1; \ + ldrb r3, [%1], #1; \ + ldrb r4, [%2], #1; \ + cbz r3, 2f; \ + cmp r3, r4; \ + beq 1b; \ + blo 3f; \ + mov %0, #1; \ + b 4f; \ + 2: \ + cmp r4, #0; \ + beq 4f; \ + 3: \ + mov %0, #-1; \ + 4: " + : "+r" (res), "+r" (s1), "+r" (s2), "+r" (count) + : + : "r3", "r4", "memory", "cc"); + + return res; +} + + +char *hal_strcpy(char *dest, const char *src) +{ + char *p = dest; + + __asm__ volatile + (" \ + 1: \ + ldrb r3, [%1], #1; \ + strb r3, [%0], #1; \ + cmp r3, #0; \ + bne 1b" + : "+r" (p), "+r" (src) + : + : "r3", "memory", "cc"); + + return dest; +} + + +char *hal_strncpy(char *dest, const char *src, size_t n) +{ + char *p = dest; + + __asm__ volatile + (" \ + cmp %2, #0; \ + beq 2f; \ + 1: \ + ldrb r3, [%1], #1; \ + strb r3, [%0], #1; \ + cbz r3, 2f; \ + subs %2, #1; \ + bne 1b; \ + 2:" + : "+r" (p), "+r" (src), "+r" (n) + : + : "r3", "memory", "cc"); + /* clang-format on */ + + return dest; +} + + +unsigned long hal_i2s(char *prefix, char *s, unsigned long i, unsigned char b, char zero) +{ + static const char digits[] = "0123456789abcdef"; + char c; + unsigned long l, k, m; + + m = hal_strlen(prefix); + hal_memcpy(s, prefix, m); + + for (k = m, l = (unsigned long)-1; l; i /= b, l /= b) { + if (!zero && !i) { + break; + } + s[k++] = digits[i % b]; + } + + l = k--; + + while (k > m) { + c = s[m]; + s[m++] = s[k]; + s[k--] = c; + } + + return l; +} diff --git a/include/arch/nrf9160.h b/include/arch/nrf9160.h new file mode 100644 index 000000000..c2c3e523b --- /dev/null +++ b/include/arch/nrf9160.h @@ -0,0 +1,31 @@ +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * Macros and enums for NRF9160 related code + * + * Copyright 2022 Phoenix Systems + * Author: Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _PHOENIX_ARCH_NRF9160_H_ +#define _PHOENIX_ARCH_NRF9160_H_ + + +/* clang-format off */ +/* nRF9160 peripheral id's - same as irq numbers */ +enum { spu_irq = 3, regulators_irq, clock_irq = 5, power_irq = 5, ctrlapperi_irq, spi0_irq = 8, twi0_irq = 8, uarte0_irq = 8, +spi1_irq = 9, twi1_irq = 9, uarte1_irq = 9, spi2_irq = 10, twi2_irq = 10, uarte2_irq = 10, spi3_irq = 11, twi3_irq = 11, uarte3_irq = 11, +gpiote0_irq = 13, saadc_irq, timer0_irq, timer1_irq, timer2_irq, rtc0_irq = 20, rtc1_irq, ddpic_irq = 23, wdt_irq, +egu0_irq = 27, egu1_irq, egu2_irq, egu3_irq, egu4_irq, egu5_irq, pwm0_irq, pwm1_irq, pwm2_irq, pwm3_irq, pdm_irq = 38, +i2s_irq = 40, ipc_irq = 42, fpu_irq = 44, gpiote1_irq = 49, kmu_irq = 57, nvmc_irq = 57, vmc_irq, cc_host_rgf_irq = 64, +cryptocell_irq = 64, gpio_irq = 66 }; +/* clang-format on */ + + +#endif diff --git a/include/arch/syspage-nrf91.h b/include/arch/syspage-nrf91.h new file mode 100644 index 000000000..021c98b2d --- /dev/null +++ b/include/arch/syspage-nrf91.h @@ -0,0 +1,33 @@ + +/* + * Phoenix-RTOS + * + * Operating system kernel + * + * HAL syspage for NRF91 boards + * + * Copyright 2021, 2022 Phoenix Systems + * Authors: Hubert Buczynski, Damian Loewnau + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _PHOENIX_SYSPAGE_NRF91_H_ +#define _PHOENIX_SYSPAGE_NRF91_H_ + + +typedef struct { + struct { + unsigned int type; + unsigned int allocCnt; + struct { + unsigned int rbar; + unsigned int rlar; + } table[16] __attribute__((aligned(8))); + unsigned int map[16]; /* ((unsigned int)-1) = map is not assigned */ + } __attribute__((packed)) mpu; +} __attribute__((packed)) hal_syspage_t; + +#endif From 63ff14648b64bf6a60c38d0f16cda9d15072db41 Mon Sep 17 00:00:00 2001 From: Damian Date: Wed, 12 Jul 2023 23:26:12 +0200 Subject: [PATCH 2/2] hal: update armv8m33-nrf9160 port JIRA: RTOS-283 --- hal/armv8m/arch/cpu.h | 29 ++++++++++++++-------- hal/armv8m/arch/exceptions.h | 10 ++------ hal/armv8m/cpu.c | 48 ++++++++++++++++++++---------------- hal/armv8m/exceptions.c | 43 +++++++++++++++++++------------- hal/armv8m/nrf/91/nrf91.c | 6 ++--- hal/armv8m/nrf/91/nrf91.h | 5 +--- hal/armv8m/nrf/_init.S | 8 ++++++ hal/armv8m/nrf/interrupts.c | 15 ++++++----- hal/armv8m/spinlock.c | 2 +- 9 files changed, 96 insertions(+), 70 deletions(-) diff --git a/hal/armv8m/arch/cpu.h b/hal/armv8m/arch/cpu.h index 2b21c335a..fbba70806 100644 --- a/hal/armv8m/arch/cpu.h +++ b/hal/armv8m/arch/cpu.h @@ -17,7 +17,7 @@ #define _HAL_ARMV8M_CPU_H_ -#if defined(CPU_NRF9160) +#if defined(__CPU_NRF9160) #define CPU_NRF91 #endif @@ -60,6 +60,19 @@ ustack += (sizeof(t) + 3) & ~0x3u; \ } while (0) + +typedef struct { + u32 r0; + u32 r1; + u32 r2; + u32 r3; + u32 r12; + u32 lr; + u32 pc; + u32 psr; +} cpu_hwContext_t; + + typedef struct _cpu_context_t { u32 savesp_s; u32 padding; @@ -77,14 +90,7 @@ typedef struct _cpu_context_t { u32 irq_ret; /* Saved by hardware */ - u32 r0; - u32 r1; - u32 r2; - u32 r3; - u32 r12; - u32 lr; - u32 pc; - u32 psr; + cpu_hwContext_t hwctx; } cpu_context_t; @@ -103,6 +109,9 @@ static inline void hal_cpuEnableInterrupts(void) static inline void hal_cpuHalt(void) { + __asm__ volatile("\ + wfi; \ + nop; "); } @@ -163,7 +172,7 @@ static inline void hal_cpuRestore(cpu_context_t *curr, cpu_context_t *next) static inline void hal_cpuSetReturnValue(cpu_context_t *ctx, int retval) { - ctx->r0 = retval; + ctx->hwctx.r0 = retval; } diff --git a/hal/armv8m/arch/exceptions.h b/hal/armv8m/arch/exceptions.h index c1066448d..05ebec370 100644 --- a/hal/armv8m/arch/exceptions.h +++ b/hal/armv8m/arch/exceptions.h @@ -17,6 +17,7 @@ #define _HAL_ARMV8M_EXCEPTIONS_H_ #include "types.h" +#include "cpu.h" #define EXC_DEFAULT 128 @@ -39,14 +40,7 @@ typedef struct _exc_context_t { u32 excret; /* Saved by hardware */ - u32 r0; - u32 r1; - u32 r2; - u32 r3; - u32 r12; - u32 lr; - u32 pc; - u32 psr; + cpu_hwContext_t mspctx; } exc_context_t; #endif diff --git a/hal/armv8m/cpu.c b/hal/armv8m/cpu.c index f4afb3581..13f33e5d7 100644 --- a/hal/armv8m/cpu.c +++ b/hal/armv8m/cpu.c @@ -71,11 +71,12 @@ void hal_cpuSetDevBusy(int s) hal_spinlockClear(&cpu_common.busySp, &scp); } - -int hal_cpuCreateContext(cpu_context_t **nctx, void *start, void *kstack, size_t kstacksz, void *ustack, void *arg) +int hal_cpuCreateContext(cpu_context_t **nctx, void *start, void *kstack, size_t kstacksz, void *ustack, void *arg, hal_tls_t *tls) { cpu_context_t *ctx; + (void)tls; + *nctx = 0; if (kstack == NULL) { return -1; @@ -105,25 +106,26 @@ int hal_cpuCreateContext(cpu_context_t **nctx, void *start, void *kstack, size_t ctx->r11 = 0xbbbbbbbbu; if (ustack != NULL) { - ((u32 *)ctx->psp)[0] = (u32)arg; /* r0 */ - ((u32 *)ctx->psp)[1] = 0x11111111u; /* r1 */ - ((u32 *)ctx->psp)[2] = 0x22222222u; /* r2 */ - ((u32 *)ctx->psp)[3] = 0x33333333u; /* r3 */ - ((u32 *)ctx->psp)[4] = 0xccccccccu; /* r12 */ - ((u32 *)ctx->psp)[5] = 0xeeeeeeeeu; /* lr */ - ((u32 *)ctx->psp)[6] = (u32)start; /* pc */ - ((u32 *)ctx->psp)[7] = 0x01000000u; /* psr */ + ((cpu_hwContext_t *)ctx->psp)->r0 = (u32)arg; + ((cpu_hwContext_t *)ctx->psp)->r1 = 0x11111111; + ((cpu_hwContext_t *)ctx->psp)->r2 = 0x22222222; + ((cpu_hwContext_t *)ctx->psp)->r3 = 0x33333333; + ((cpu_hwContext_t *)ctx->psp)->r12 = 0xcccccccc; + ((cpu_hwContext_t *)ctx->psp)->lr = 0xeeeeeeee; + ((cpu_hwContext_t *)ctx->psp)->pc = (u32)start; + ((cpu_hwContext_t *)ctx->psp)->psr = 0x01000000; ctx->irq_ret = RET_THREAD_PSP; } else { - ctx->r0 = (u32)arg; - ctx->r1 = 0x11111111u; - ctx->r2 = 0x22222222u; - ctx->r3 = 0x33333333u; - ctx->r12 = 0xccccccccu; - ctx->lr = 0xeeeeeeeeu; - ctx->pc = (u32)start; - ctx->psr = 0x01000000u; + ctx->hwctx.r0 = (u32)arg; + ctx->hwctx.r1 = 0x11111111u; + ctx->hwctx.r2 = 0x22222222u; + ctx->hwctx.r3 = 0x33333333u; + ctx->hwctx.r12 = 0xccccccccu; + ctx->hwctx.lr = 0xeeeeeeeeu; + ctx->hwctx.pc = (u32)start; + ctx->hwctx.psr = 0x01000000u; + ctx->irq_ret = RET_THREAD_MSP; } @@ -225,6 +227,12 @@ void hal_wdgReload(void) } +void hal_cpuReboot(void) +{ + _interrupts_nvicSystemReset(); +} + + /* TODO: add implementation */ void hal_cleanDCache(ptr_t start, size_t len) { @@ -238,9 +246,7 @@ void _hal_cpuInit(void) hal_spinlockCreate(&cpu_common.busySp, "devBusy"); -#ifdef CPU_NRF91 - _nrf91_platformInit(); -#endif + _hal_platformInit(); } diff --git a/hal/armv8m/exceptions.c b/hal/armv8m/exceptions.c index 32af88a35..94565edc0 100644 --- a/hal/armv8m/exceptions.c +++ b/hal/armv8m/exceptions.c @@ -34,7 +34,7 @@ void hal_exceptionsDumpContext(char *buff, exc_context_t *ctx, int n) cpu_hwContext_t *hwctx; /* If we came from userspace HW ctx in on psp stack (according to EXC_RETURN) */ - if (ctx->excret | (1u << 2)) { + if ((ctx->excret & (1u << 2)) != 0) { hwctx = (void *)ctx->psp; msp -= sizeof(cpu_hwContext_t); psp += sizeof(cpu_hwContext_t); @@ -50,10 +50,10 @@ void hal_exceptionsDumpContext(char *buff, exc_context_t *ctx, int n) hal_strcpy(&buff[i], mnemonics[n]); i += hal_strlen(mnemonics[n]); - i += hal_i2s("\n r0=", &buff[i], ctx->r0, 16, 1); - i += hal_i2s(" r1=", &buff[i], ctx->r1, 16, 1); - i += hal_i2s(" r2=", &buff[i], ctx->r2, 16, 1); - i += hal_i2s(" r3=", &buff[i], ctx->r3, 16, 1); + i += hal_i2s("\n r0=", &buff[i], hwctx->r0, 16, 1); + i += hal_i2s(" r1=", &buff[i], hwctx->r1, 16, 1); + i += hal_i2s(" r2=", &buff[i], hwctx->r2, 16, 1); + i += hal_i2s(" r3=", &buff[i], hwctx->r3, 16, 1); i += hal_i2s("\n r4=", &buff[i], ctx->r4, 16, 1); i += hal_i2s(" r5=", &buff[i], ctx->r5, 16, 1); @@ -65,13 +65,13 @@ void hal_exceptionsDumpContext(char *buff, exc_context_t *ctx, int n) i += hal_i2s(" r10=", &buff[i], ctx->r10, 16, 1); i += hal_i2s(" r11=", &buff[i], ctx->r11, 16, 1); - i += hal_i2s("\nr12=", &buff[i], ctx->r12, 16, 1); - i += hal_i2s(" sp=", &buff[i], (u32)ctx - 17 * 4, 16, 1); - i += hal_i2s(" lr=", &buff[i], ctx->lr, 16, 1); - i += hal_i2s(" pc=", &buff[i], ctx->pc, 16, 1); + i += hal_i2s("\nr12=", &buff[i], hwctx->r12, 16, 1); + i += hal_i2s(" psr=", &buff[i], hwctx->psr, 16, 1); + i += hal_i2s(" lr=", &buff[i], hwctx->lr, 16, 1); + i += hal_i2s(" pc=", &buff[i], hwctx->pc, 16, 1); - i += hal_i2s("\npsp_s=", &buff[i], ctx->psp_s, 16, 1); - i += hal_i2s(" psr=", &buff[i], ctx->psr, 16, 1); + i += hal_i2s("\npsp=", &buff[i], psp, 16, 1); + i += hal_i2s(" msp=", &buff[i], msp, 16, 1); i += hal_i2s(" exr=", &buff[i], ctx->excret, 16, 1); i += hal_i2s(" bfa=", &buff[i], *(u32 *)0xe000ed38, 16, 1); @@ -91,18 +91,27 @@ void exceptions_dispatch(unsigned int n, exc_context_t *ctx) hal_consolePrint(ATTR_BOLD, buff); #ifdef NDEBUG -#ifdef CPU_NRF91 - _interrupts_nvicSystemReset(); -#endif -#else - hal_cpuHalt(); + hal_cpuReboot(); #endif + + for (;;) { + hal_cpuHalt(); + } } ptr_t hal_exceptionsPC(exc_context_t *ctx) { - return ctx->pc; + cpu_hwContext_t *hwctx; + + if ((ctx->excret & (1u << 2)) != 0) { + hwctx = (void *)ctx->psp; + } + else { + hwctx = &ctx->mspctx; + } + + return hwctx->pc; } diff --git a/hal/armv8m/nrf/91/nrf91.c b/hal/armv8m/nrf/91/nrf91.c index a6808b388..2f3dc401f 100644 --- a/hal/armv8m/nrf/91/nrf91.c +++ b/hal/armv8m/nrf/91/nrf91.c @@ -57,7 +57,7 @@ int hal_platformctl(void *ptr) } -void _nrf91_platformInit(void) +void _hal_platformInit(void) { hal_spinlockCreate(&nrf91_common.pltctlSp, "pltctl"); } @@ -103,7 +103,7 @@ int _nrf91_gpioConfig(u8 pin, u8 dir, u8 pull) *(nrf91_common.gpio + gpio_cnf + pin) &= ~0x2; } - if (pull) { + if (pull != 0) { *(nrf91_common.gpio + gpio_cnf + pin) = (pull << 2); } @@ -201,7 +201,7 @@ void _nrf91_init(void) *(nrf91_common.power + power_intenclr) = 0x64u; /* Disable all clock interrupts */ - *(nrf91_common.power + power_intenclr) = 0x3u; + *(nrf91_common.power + clock_intenclr) = 0x3u; hal_cpuDataMemoryBarrier(); diff --git a/hal/armv8m/nrf/91/nrf91.h b/hal/armv8m/nrf/91/nrf91.h index 748539392..d3de407e0 100644 --- a/hal/armv8m/nrf/91/nrf91.h +++ b/hal/armv8m/nrf/91/nrf91.h @@ -33,13 +33,10 @@ enum { scb_actlr = 2, scb_cpuid = 832, scb_icsr, scb_vtor, scb_aircr, scb_scr, s /* clang-format on */ -extern void _nrf91_platformInit(void); - - extern int hal_platformctl(void *); -extern void _nrf91_platformInit(void); +extern void _hal_platformInit(void); extern int _nrf91_systickInit(u32 interval); diff --git a/hal/armv8m/nrf/_init.S b/hal/armv8m/nrf/_init.S index b9c04e0d1..0d48ee30f 100644 --- a/hal/armv8m/nrf/_init.S +++ b/hal/armv8m/nrf/_init.S @@ -77,6 +77,13 @@ _start: str r1, [r0] isb dmb + + /* Init MSP to a first value in _init_vectors (.bss end + 1024 + 256) */ + ldr r0, [r1] + bic r0, 7 + msr msp, r0 + isb + bl _nrf91_init bl main @@ -151,6 +158,7 @@ _exceptions_dispatch: mrs r0, ipsr mov r1, sp + b exceptions_dispatch .size _exceptions_dispatch, .-_exceptions_dispatch .ltorg diff --git a/hal/armv8m/nrf/interrupts.c b/hal/armv8m/nrf/interrupts.c index 155c0b4b2..35e8ab223 100644 --- a/hal/armv8m/nrf/interrupts.c +++ b/hal/armv8m/nrf/interrupts.c @@ -89,8 +89,8 @@ extern int threads_schedule(unsigned int n, cpu_context_t *context, void *arg); void _interrupts_nvicSetIRQ(s8 irqn, u8 state) { - volatile u32 *ptr = interrupts.nvic + ((u8)irqn >> 5) + (state ? nvic_iser : nvic_icer); - *ptr = 1 << (irqn & 0x1F); + volatile u32 *ptr = interrupts.nvic + ((u8)irqn >> 5) + ((state != 0) ? nvic_iser : nvic_icer); + *ptr = 1u << (irqn & 0x1f); hal_cpuDataSyncBarrier(); hal_cpuInstrBarrier(); @@ -133,19 +133,22 @@ void interrupts_dispatch(unsigned int n, cpu_context_t *ctx) interrupts.counters[n]++; - if ((h = interrupts.handlers[n]) != NULL) { + h = interrupts.handlers[n]; + if (h != NULL) { do { hal_cpuSetGot(h->got); - if (h->f(n, ctx, h->data)) { + if (h->f(n, ctx, h->data) != 0) { reschedule = 1; } - } while ((h = h->next) != interrupts.handlers[n]); + h = h->next; + } while (h != interrupts.handlers[n]); } hal_spinlockClear(&interrupts.spinlock, &sc); - if (reschedule) + if (reschedule != 0) { threads_schedule(n, ctx, NULL); + } } diff --git a/hal/armv8m/spinlock.c b/hal/armv8m/spinlock.c index 55c61eef8..9f63df548 100644 --- a/hal/armv8m/spinlock.c +++ b/hal/armv8m/spinlock.c @@ -66,7 +66,7 @@ void hal_spinlockClear(spinlock_t *spinlock, spinlock_ctx_t *sc) void _hal_spinlockCreate(spinlock_t *spinlock, const char *name) { - spinlock->lock = 1; + spinlock->lock = 1u; spinlock->name = name; if (spinlocks.first != NULL) {