first commit

This commit is contained in:
2022-08-24 08:41:00 +02:00
commit 5765dbd675
2497 changed files with 2244854 additions and 0 deletions
@@ -0,0 +1,76 @@
//
// This file is part of the µOS++ III distribution.
// Copyright (c) 2014 Liviu Ionescu.
//
// ----------------------------------------------------------------------------
#if defined(TRACE)
#include <stdio.h>
#include <stdarg.h>
#include "diag/Trace.h"
#include "string.h"
#ifndef OS_INTEGER_TRACE_PRINTF_TMP_ARRAY_SIZE
#define OS_INTEGER_TRACE_PRINTF_TMP_ARRAY_SIZE (128)
#endif
// ----------------------------------------------------------------------------
int
trace_printf(const char* format, ...)
{
int ret;
va_list ap;
va_start (ap, format);
// TODO: rewrite it to no longer use newlib, it is way too heavy
static char buf[OS_INTEGER_TRACE_PRINTF_TMP_ARRAY_SIZE];
// Print to the local buffer
ret = vsnprintf (buf, sizeof(buf), format, ap);
if (ret > 0)
{
// Transfer the buffer to the device
ret = trace_write (buf, (size_t)ret);
}
va_end (ap);
return ret;
}
int
trace_puts(const char *s)
{
trace_write(s, strlen(s));
return trace_write("\n", 1);
}
int
trace_putchar(int c)
{
trace_write((const char*)&c, 1);
return c;
}
void
trace_dump_args(int argc, char* argv[])
{
trace_printf("main(argc=%d, argv=[", argc);
for (int i = 0; i < argc; ++i)
{
if (i != 0)
{
trace_printf(", ");
}
trace_printf("\"%s\"", argv[i]);
}
trace_printf("]);\n");
}
// ----------------------------------------------------------------------------
#endif // TRACE
@@ -0,0 +1,146 @@
//
// This file is part of the µOS++ III distribution.
// Copyright (c) 2014 Liviu Ionescu.
//
#ifndef DIAG_TRACE_H_
#define DIAG_TRACE_H_
// ----------------------------------------------------------------------------
#include <unistd.h>
// ----------------------------------------------------------------------------
// The trace device is an independent output channel, intended for debug
// purposes.
//
// The API is simple, and mimics the standard output calls:
// - trace_printf()
// - trace_puts()
// - trace_putchar();
//
// The implementation is done in
// - trace_write()
//
// Trace support is enabled by adding the TRACE definition.
// By default the trace messages are forwarded to the ITM output,
// but can be rerouted via any device or completely suppressed by
// changing the definitions required in system/src/diag/trace_impl.c
// (currently OS_USE_TRACE_ITM, OS_USE_TRACE_SEMIHOSTING_DEBUG/_STDOUT).
//
// When TRACE is not defined, all functions are inlined to empty bodies.
// This has the advantage that the trace call do not need to be conditionally
// compiled with #ifdef TRACE/#endif
#if defined(TRACE)
#if defined(__cplusplus)
extern "C"
{
#endif
void
trace_initialize(void);
// Implementation dependent
ssize_t
trace_write(const char* buf, size_t nbyte);
// ----- Portable -----
int
trace_printf(const char* format, ...);
int
trace_puts(const char *s);
int
trace_putchar(int c);
void
trace_dump_args(int argc, char* argv[]);
#if defined(__cplusplus)
}
#endif
#else // !defined(TRACE)
#if defined(__cplusplus)
extern "C"
{
#endif
inline void
trace_initialize(void);
// Implementation dependent
inline ssize_t
trace_write(const char* buf, size_t nbyte);
inline int
trace_printf(const char* format, ...);
inline int
trace_puts(const char *s);
inline int
trace_putchar(int c);
inline void
trace_dump_args(int argc, char* argv[]);
#if defined(__cplusplus)
}
#endif
inline void
__attribute__((always_inline))
trace_initialize(void)
{
}
// Empty definitions when trace is not defined
inline ssize_t
__attribute__((always_inline))
trace_write(const char* buf __attribute__((unused)),
size_t nbyte __attribute__((unused)))
{
return 0;
}
inline int
__attribute__((always_inline))
trace_printf(const char* format __attribute__((unused)), ...)
{
return 0;
}
inline int
__attribute__((always_inline))
trace_puts(const char *s __attribute__((unused)))
{
return 0;
}
inline int
__attribute__((always_inline))
trace_putchar(int c)
{
return c;
}
inline void
__attribute__((always_inline))
trace_dump_args(int argc __attribute__((unused)),
char* argv[] __attribute__((unused)))
{
}
#endif // defined(TRACE)
// ----------------------------------------------------------------------------
#endif // DIAG_TRACE_H_
@@ -0,0 +1,120 @@
//
// This file is part of the µOS++ III distribution.
// Copyright (c) 2014 Liviu Ionescu.
//
#ifndef ARM_SEMIHOSTING_H_
#define ARM_SEMIHOSTING_H_
// ----------------------------------------------------------------------------
// Semihosting operations.
enum OperationNumber
{
// Regular operations
SEMIHOSTING_EnterSVC = 0x17,
SEMIHOSTING_ReportException = 0x18,
SEMIHOSTING_SYS_CLOSE = 0x02,
SEMIHOSTING_SYS_CLOCK = 0x10,
SEMIHOSTING_SYS_ELAPSED = 0x30,
SEMIHOSTING_SYS_ERRNO = 0x13,
SEMIHOSTING_SYS_FLEN = 0x0C,
SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
SEMIHOSTING_SYS_HEAPINFO = 0x16,
SEMIHOSTING_SYS_ISERROR = 0x08,
SEMIHOSTING_SYS_ISTTY = 0x09,
SEMIHOSTING_SYS_OPEN = 0x01,
SEMIHOSTING_SYS_READ = 0x06,
SEMIHOSTING_SYS_READC = 0x07,
SEMIHOSTING_SYS_REMOVE = 0x0E,
SEMIHOSTING_SYS_RENAME = 0x0F,
SEMIHOSTING_SYS_SEEK = 0x0A,
SEMIHOSTING_SYS_SYSTEM = 0x12,
SEMIHOSTING_SYS_TICKFREQ = 0x31,
SEMIHOSTING_SYS_TIME = 0x11,
SEMIHOSTING_SYS_TMPNAM = 0x0D,
SEMIHOSTING_SYS_WRITE = 0x05,
SEMIHOSTING_SYS_WRITEC = 0x03,
SEMIHOSTING_SYS_WRITE0 = 0x04,
// Codes returned by SEMIHOSTING_ReportException
ADP_Stopped_ApplicationExit = ((2 << 16) + 38),
ADP_Stopped_RunTimeError = ((2 << 16) + 35),
};
// ----------------------------------------------------------------------------
// SWI numbers and reason codes for RDI (Angel) monitors.
#define AngelSWI_ARM 0x123456
#ifdef __thumb__
#define AngelSWI 0xAB
#else
#define AngelSWI AngelSWI_ARM
#endif
// For thumb only architectures use the BKPT instruction instead of SWI.
#if defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7EM__) \
|| defined(__ARM_ARCH_6M__)
#define AngelSWIInsn "bkpt"
#define AngelSWIAsm bkpt
#else
#define AngelSWIInsn "swi"
#define AngelSWIAsm swi
#endif
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
// Testing the local semihosting handler cannot use another BKPT, since this
// configuration cannot trigger HaedFault exceptions while the debugger is
// connected, so we use an illegal op code, that will trigger an
// UsageFault exception.
#define AngelSWITestFault "setend be"
#define AngelSWITestFaultOpCode (0xB658)
#endif
static inline int
__attribute__ ((always_inline))
call_host (int reason, void* arg)
{
int value;
asm volatile (
" mov r0, %[rsn] \n"
" mov r1, %[arg] \n"
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
" " AngelSWITestFault " \n"
#else
" " AngelSWIInsn " %[swi] \n"
#endif
" mov %[val], r0"
: [val] "=r" (value) /* Outputs */
: [rsn] "r" (reason), [arg] "r" (arg), [swi] "i" (AngelSWI) /* Inputs */
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"
// Clobbers r0 and r1, and lr if in supervisor mode
);
// Accordingly to page 13-77 of ARM DUI 0040D other registers
// can also be clobbered. Some memory positions may also be
// changed by a system call, so they should not be kept in
// registers. Note: we are assuming the manual is right and
// Angel is respecting the APCS.
return value;
}
// ----------------------------------------------------------------------------
// Function used in _exit() to return the status code as Angel exception.
static inline void
__attribute__ ((always_inline,noreturn))
report_exception (int reason)
{
call_host (SEMIHOSTING_ReportException, (void*) reason);
for (;;)
;
}
// ----------------------------------------------------------------------------
#endif // ARM_SEMIHOSTING_H_
@@ -0,0 +1,252 @@
//
// This file is part of the µOS++ III distribution.
// Copyright (c) 2014 Liviu Ionescu.
//
// ----------------------------------------------------------------------------
#if defined(TRACE)
#include "cmsis_device.h"
#include "diag/Trace.h"
// ----------------------------------------------------------------------------
// One of these definitions must be passed via the compiler command line
// Note: small Cortex-M0/M0+ might implement a simplified debug interface.
//#define OS_USE_TRACE_ITM
//#define OS_USE_TRACE_SEMIHOSTING_DEBUG
//#define OS_USE_TRACE_SEMIHOSTING_STDOUT
#if !(defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__))
#if defined(OS_USE_TRACE_ITM)
#undef OS_USE_TRACE_ITM
#warning "ITM unavailable"
#endif // defined(OS_USE_TRACE_ITM)
#endif // !(defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__))
#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
#if defined(OS_USE_TRACE_SEMIHOSTING_STDOUT) || defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
#error "Cannot debug semihosting using semihosting trace; use OS_USE_TRACE_ITM"
#endif
#endif
// ----------------------------------------------------------------------------
// Forward definitions.
#if defined(OS_USE_TRACE_ITM)
static ssize_t
_trace_write_itm (const char* buf, size_t nbyte);
#endif
#if defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
static ssize_t
_trace_write_semihosting_stdout(const char* buf, size_t nbyte);
#endif
#if defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
static ssize_t
_trace_write_semihosting_debug(const char* buf, size_t nbyte);
#endif
// ----------------------------------------------------------------------------
void
trace_initialize(void)
{
// For regular ITM / semihosting, no inits required.
}
// ----------------------------------------------------------------------------
// This function is called from _write() for fd==1 or fd==2 and from some
// of the trace_* functions.
ssize_t
trace_write (const char* buf __attribute__((unused)),
size_t nbyte __attribute__((unused)))
{
#if defined(OS_USE_TRACE_ITM)
return _trace_write_itm (buf, nbyte);
#elif defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
return _trace_write_semihosting_stdout(buf, nbyte);
#elif defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
return _trace_write_semihosting_debug(buf, nbyte);
#endif
return -1;
}
// ----------------------------------------------------------------------------
#if defined(OS_USE_TRACE_ITM)
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
// ITM is the ARM standard mechanism, running over SWD/SWO on Cortex-M3/M4
// devices, and is the recommended setting, if available.
//
// The JLink probe and the GDB server fully support SWD/SWO
// and the JLink Debugging plug-in enables it by default.
// The current OpenOCD does not include support to parse the SWO stream,
// so this configuration will not work on OpenOCD (will not crash, but
// nothing will be displayed in the output console).
#if !defined(OS_INTEGER_TRACE_ITM_STIMULUS_PORT)
#define OS_INTEGER_TRACE_ITM_STIMULUS_PORT (0)
#endif
static ssize_t
_trace_write_itm (const char* buf, size_t nbyte)
{
for (size_t i = 0; i < nbyte; i++)
{
// Check if ITM or the stimulus port are not enabled
if (((ITM->TCR & ITM_TCR_ITMENA_Msk) == 0)
|| ((ITM->TER & (1UL << OS_INTEGER_TRACE_ITM_STIMULUS_PORT)) == 0))
{
return (ssize_t)i; // return the number of sent characters (may be 0)
}
// Wait until STIMx is ready...
while (ITM->PORT[OS_INTEGER_TRACE_ITM_STIMULUS_PORT].u32 == 0)
;
// then send data, one byte at a time
ITM->PORT[OS_INTEGER_TRACE_ITM_STIMULUS_PORT].u8 = (uint8_t) (*buf++);
}
return (ssize_t)nbyte; // all characters successfully sent
}
#endif // defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#endif // OS_USE_TRACE_ITM
// ----------------------------------------------------------------------------
#if defined(OS_USE_TRACE_SEMIHOSTING_DEBUG) || defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
#include "arm/semihosting.h"
// Semihosting is the other output channel that can be used for the trace
// messages. It comes in two flavours: STDOUT and DEBUG. The STDOUT channel
// is the equivalent of the stdout in POSIX and in most cases it is forwarded
// to the GDB server stdout stream. The debug channel is a separate
// channel. STDOUT is buffered, so nothing is displayed until a \n;
// DEBUG is not buffered, but can be slow.
//
// Choosing between semihosting stdout and debug depends on the capabilities
// of your GDB server, and also on specific needs. It is recommended to test
// DEBUG first, and if too slow, try STDOUT.
//
// The JLink GDB server fully support semihosting, and both configurations
// are available; to activate it, use "monitor semihosting enable" or check
// the corresponding button in the JLink Debugging plug-in.
// In OpenOCD, support for semihosting can be enabled using
// "monitor arm semihosting enable".
//
// Note: Applications built with semihosting output active normally cannot
// be executed without the debugger connected and active, since they use
// BKPT to communicate with the host. However, with a carefully written
// HardFault_Handler, the semihosting BKPT calls can be processed, making
// possible to run semihosting applications as standalone, without being
// terminated with hardware faults.
#endif // OS_USE_TRACE_SEMIHOSTING_DEBUG_*
// ----------------------------------------------------------------------------
#if defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
static ssize_t
_trace_write_semihosting_stdout (const char* buf, size_t nbyte)
{
static int handle;
void* block[3];
int ret;
if (handle == 0)
{
// On the first call get the file handle from the host
block[0] = ":tt"; // special filename to be used for stdin/out/err
block[1] = (void*) 4; // mode "w"
// length of ":tt", except null terminator
block[2] = (void*) (sizeof(":tt") - 1);
ret = call_host (SEMIHOSTING_SYS_OPEN, (void*) block);
if (ret == -1)
return -1;
handle = ret;
}
block[0] = (void*) handle;
block[1] = (void*) buf;
block[2] = (void*) nbyte;
// send character array to host file/device
ret = call_host (SEMIHOSTING_SYS_WRITE, (void*) block);
// this call returns the number of bytes NOT written (0 if all ok)
// -1 is not a legal value, but SEGGER seems to return it
if (ret == -1)
return -1;
// The compliant way of returning errors
if (ret == (int) nbyte)
return -1;
// Return the number of bytes written
return (ssize_t) (nbyte) - (ssize_t) ret;
}
#endif // OS_USE_TRACE_SEMIHOSTING_STDOUT
// ----------------------------------------------------------------------------
#if defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
#define OS_INTEGER_TRACE_TMP_ARRAY_SIZE (16)
static ssize_t
_trace_write_semihosting_debug (const char* buf, size_t nbyte)
{
// Since the single character debug channel is quite slow, try to
// optimise and send a null terminated string, if possible.
if (buf[nbyte] == '\0')
{
// send string
call_host (SEMIHOSTING_SYS_WRITE0, (void*) buf);
}
else
{
// If not, use a local buffer to speed things up
char tmp[OS_INTEGER_TRACE_TMP_ARRAY_SIZE];
size_t togo = nbyte;
while (togo > 0)
{
unsigned int n = ((togo < sizeof(tmp)) ? togo : sizeof(tmp));
unsigned int i = 0;
for (; i < n; ++i, ++buf)
{
tmp[i] = *buf;
}
tmp[i] = '\0';
call_host (SEMIHOSTING_SYS_WRITE0, (void*) tmp);
togo -= n;
}
}
// All bytes written
return (ssize_t) nbyte;
}
#endif // OS_USE_TRACE_SEMIHOSTING_DEBUG
#endif // TRACE
// ----------------------------------------------------------------------------