Skip to content

Commit

Permalink
devices: implement RTT pipe driver for debug probe
Browse files Browse the repository at this point in the history
Implements driver for Real Time Transfer (RTT) which is a pipe
interface based on basic memory reads and writes to transfer data
bidirectionally between target and host. It uses debug probe
JTAG or SWD (openocd, segger). Every target that supports so called
"background memory access", which means that the target memory can
be accessed by the debugger while the target is running, can be used.
It is faster than semi hosting.

JIRA: RTOS-531 NIL-462
  • Loading branch information
gerard5 committed Jan 22, 2024
1 parent c530081 commit a8408b1
Show file tree
Hide file tree
Showing 29 changed files with 604 additions and 66 deletions.
4 changes: 2 additions & 2 deletions cmds/erase.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* Erase sectors or all data from flash device
*
* Copyright 2022 Phoenix Systems
* Copyright 2022-2024 Phoenix Systems
* Author: Gerard Swiderski
*
* This file is part of Phoenix-RTOS.
Expand Down Expand Up @@ -60,7 +60,7 @@ static int cmd_erase(int argc, char *argv[])
return res;
}

res = lib_promptConfirm("\nWARNING!\nSerious risk of data loss, type %s to proceed.\n", "YES!");
res = lib_promptConfirm("\nWARNING!\nSerious risk of data loss, type %s to proceed.\n", "YES!", 10 * 1000);
if (res != 1) {
lib_printf("Aborted.\n");
return EOK;
Expand Down
4 changes: 2 additions & 2 deletions devices/devs.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* Device Interface
*
* Copyright 2021-2022 Phoenix Systems
* Copyright 2021-2024 Phoenix Systems
* Author: Hubert Buczynski, Gerard Swiderski
*
* This file is part of Phoenix-RTOS.
Expand All @@ -17,7 +17,7 @@

#include <lib/errno.h>

#define SIZE_MAJOR 8
#define SIZE_MAJOR 9
#define SIZE_MINOR 16


Expand Down
3 changes: 2 additions & 1 deletion devices/devs.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*
* Devices Interface
*
* Copyright 2021-2022 Phoenix Systems
* Copyright 2021-2024 Phoenix Systems
* Author: Hubert Buczynski, Gerard Swiderski
*
* This file is part of Phoenix-RTOS.
Expand All @@ -26,6 +26,7 @@
#define DEV_NAND_DATA 5
#define DEV_NAND_META 6
#define DEV_NAND_RAW 7
#define DEV_PIPE 8


/* clang-format off */
Expand Down
9 changes: 9 additions & 0 deletions devices/pipe-rtt/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#
# Makefile for pipe-rtt
#
# Copyright 2023-2024 Phoenix Systems
#
# %LICENSE%
#

OBJS += $(addprefix $(PREFIX_O)devices/pipe-rtt/, rtt.o device.o)
97 changes: 97 additions & 0 deletions devices/pipe-rtt/device.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Phoenix-RTOS
*
* Operating system loader
*
* RTT pipes: communication through debug probe (device)
*
* Copyright 2023-2024 Phoenix Systems
* Author: Gerard Swiderski
*
* This file is part of Phoenix-RTOS.
*
* %LICENSE%
*/

#include <devices/devs.h>
#include <hal/hal.h>
#include <lib/lib.h>

#include "rtt.h"

static ssize_t pipe_read(unsigned int minor, addr_t offs, void *buff, size_t len, time_t timeout)
{
(void)offs;
(void)timeout;

return rtt_read(minor + 1, buff, len);
}


static ssize_t pipe_write(unsigned int minor, addr_t offs, const void *buff, size_t len)
{
(void)offs;

return rtt_write(minor + 1, buff, len);
}


static int pipe_done(unsigned int minor)
{
return rtt_check(minor + 1);
}


static int pipe_sync(unsigned int minor)
{
return rtt_check(minor + 1);
}


static int pipe_map(unsigned int minor, addr_t addr, size_t sz, int mode, addr_t memaddr, size_t memsz, int memmode, addr_t *a)
{
(void)addr;
(void)sz;
(void)memaddr;
(void)memsz;
(void)a;

if (rtt_check(minor + 1) < 0) {
return -ENODEV;
}

/* mode cannot be higher than map mode to copy data */
if ((mode & memmode) != mode) {
return -EINVAL;
}

/* is not mappable to any region */
return dev_isNotMappable;
}


static int pipe_init(unsigned int minor)
{
int res = rtt_check(minor + 1);
if (res == 0) {
lib_printf("\ndev/pipe: Initialized rtt channel(%d.%d)", DEV_PIPE, minor);
}

return res;
}


__attribute__((constructor)) static void pipe_reg(void)
{
static const dev_handler_t h = {
.init = pipe_init,
.done = pipe_done,
.read = pipe_read,
.write = pipe_write,
.erase = NULL,
.sync = pipe_sync,
.map = pipe_map,
};

devs_register(DEV_PIPE, 1, &h);
}
207 changes: 207 additions & 0 deletions devices/pipe-rtt/rtt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
* Phoenix-RTOS
*
* Operating system loader
*
* RTT pipes: communication through debug probe (driver)
*
* Copyright 2023-2024 Phoenix Systems
* Author: Gerard Swiderski
*
* This file is part of Phoenix-RTOS.
*
* %LICENSE%
*/

#include <hal/hal.h>
#include <lib/lib.h>


#define RTT_TXCHANNELS 2
#define RTT_RXCHANNELS 2

/*
* Note: RTT_TAG needs to be backward written string. This tag is used by
* the RTT remote side e.g. openocd to find descriptor location during memory
* scan, so as not to mislead the descriptor scan procedure, this tag needs
* to be simply hidden before it is copied into RAM together with initialized
* descriptors, that's why it is written backwards.
* - Default RTT_TAG_REVERSED="EPIP TTR", which corresponds to "RTT PIPE"
*/

#ifndef RTT_TAG_BACKWARD
#define RTT_TAG_BACKWARD "EPIP TTR"
#endif


struct rtt_pipe {
const char *name;
unsigned char *ptr;
unsigned int sz;
volatile unsigned int wr;
volatile unsigned int rd;
unsigned int flags;
};


struct rtt_desc {
char tag[16];
unsigned int txChannels;
unsigned int rxChannels;
struct rtt_pipe txChannel[RTT_TXCHANNELS];
struct rtt_pipe rxChannel[RTT_RXCHANNELS];
};


static struct {
/* NOTE: each buffer must be aligned to cache line */
unsigned char bytes[1024] __attribute__((aligned(32)));
} rttBufferPool[RTT_TXCHANNELS + RTT_RXCHANNELS];


static const char rtt_tagBackward[] = RTT_TAG_BACKWARD;
static const char *const rtt_txName[RTT_TXCHANNELS] = { "Console TX", "phoenixd TX" };
static const char *const rtt_rxName[RTT_RXCHANNELS] = { "Console RX", "phoenixd RX" };
static volatile struct rtt_desc *rtt = NULL;


int rtt_check(int chan)
{
if ((rtt == NULL) || (chan < 0) || (chan >= RTT_TXCHANNELS)) {
return -ENODEV;
}

return 0;
}


ssize_t rtt_read(int chan, void *buf, size_t count)
{
if (rtt_check(chan) < 0) {
return -ENODEV;
}

hal_cpuDataMemoryBarrier();

unsigned char *srcBuf = (unsigned char *)rtt->rxChannel[chan].ptr;
unsigned char *dstBuf = (unsigned char *)buf;
unsigned int rd = rtt->rxChannel[chan].rd;
unsigned int wr = rtt->rxChannel[chan].wr;
unsigned int sz = rtt->rxChannel[chan].sz;
size_t todo = count;

while ((todo != 0) && (rd != wr)) {
*dstBuf++ = srcBuf[rd];
rd = (rd + 1) % sz;
todo--;
}

rtt->rxChannel[chan].rd = rd;

hal_cpuDataMemoryBarrier();

return count - todo;
}


ssize_t rtt_write(int chan, const void *buf, size_t count)
{
if (rtt_check(chan) < 0) {
return -ENODEV;
}

hal_cpuDataMemoryBarrier();

const unsigned char *srcBuf = (const unsigned char *)buf;
unsigned char *dstBuf = (unsigned char *)rtt->txChannel[chan].ptr;
unsigned int sz = rtt->txChannel[chan].sz;
unsigned int rd = (rtt->txChannel[chan].rd + sz - 1) % sz;
unsigned int wr = rtt->txChannel[chan].wr;
size_t todo = count;

while ((todo != 0) && (rd != wr)) {
dstBuf[wr] = *srcBuf++;
wr = (wr + 1) % sz;
todo--;
}

rtt->txChannel[chan].wr = wr;

hal_cpuDataMemoryBarrier();

return count - todo;
}


static ssize_t rtt_writeBlocking(int chan, const void *buf, size_t count)
{
const unsigned char *ptr = buf;
size_t todo = count;
time_t start = hal_timerGet();

while (todo > 0) {
if ((hal_timerGet() - start) >= 100) {
rtt->txChannel[chan].wr = rtt->txChannel[chan].rd;
return -ETIME;
}

ssize_t len = rtt_write(chan, ptr, todo);
if (len < 0) {
return len;
}
todo -= len;
ptr += len;
}

return 0;
}


void rtt_init(void *addr)
{
unsigned int n, m;

if (rtt != NULL) {
return;
}

rtt = (volatile struct rtt_desc *)addr;
hal_memset((void *)rtt, 0, sizeof(*rtt));

rtt->txChannels = RTT_TXCHANNELS;
rtt->rxChannels = RTT_RXCHANNELS;

m = 0;
for (n = 0; n < rtt->txChannels; n++) {
rtt->txChannel[n].name = rtt_txName[n];
rtt->txChannel[n].ptr = rttBufferPool[m].bytes;
rtt->txChannel[n].sz = sizeof(rttBufferPool[m].bytes);
m++;
}

for (n = 0; n < rtt->rxChannels; n++) {
rtt->rxChannel[n].name = rtt_rxName[n];
rtt->rxChannel[n].ptr = rttBufferPool[m].bytes;
rtt->rxChannel[n].sz = sizeof(rttBufferPool[m].bytes);
m++;
}

n = 0;
m = sizeof(rtt_tagBackward) - 1;
while (n < sizeof(rtt->tag) && m > 0) {
rtt->tag[n++] = rtt_tagBackward[--m];
}

hal_consoleSetHooks(rtt_write);
lib_consoleSetHooks(rtt_read, rtt_writeBlocking);
}


void rtt_done(void)
{
if (rtt != NULL) {
lib_consoleSetHooks(NULL, NULL);
hal_memset((void *)rtt, 0, sizeof(*rtt));
rtt = NULL;
}
}
29 changes: 29 additions & 0 deletions devices/pipe-rtt/rtt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Phoenix-RTOS
*
* Operating system loader
*
* RTT pipes: communication through debug probe (driver)
*
* Copyright 2023-2024 Phoenix Systems
* Author: Gerard Swiderski
*
* This file is part of Phoenix-RTOS.
*
* %LICENSE%
*/

#ifndef _RTT_H_
#define _RTT_H_


int rtt_check(int chan);


ssize_t rtt_read(int chan, void *buf, size_t count);


ssize_t rtt_write(int chan, const void *buf, size_t count);


#endif /* end of _RTT_H_ */
Loading

0 comments on commit a8408b1

Please sign in to comment.