Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imx6ull: rngb driver #329

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _targets/Makefile.armv7a7-imx6ull
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# Copyright 2019 Phoenix Systems
#

DEFAULT_COMPONENTS := imx6ull-sdma imx6ull-gpio libimx6ull-ecspi libimx6ull-qspi
DEFAULT_COMPONENTS := imx6ull-sdma imx6ull-gpio imx6ull-rngb libimx6ull-ecspi libimx6ull-qspi
DEFAULT_COMPONENTS += imx6ull-flash
DEFAULT_COMPONENTS += imx6ull-flashnor
DEFAULT_COMPONENTS += libusbclient cdc-demo
Expand Down
10 changes: 10 additions & 0 deletions random/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#
# Makefile for Phoenix-RTOS rngb
#
# Copyright 2023 Phoenix Systems
#

NAME := imx6ull-rngb
LOCAL_SRCS := imx6ull-rngb.c

include $(binary.mk)
305 changes: 305 additions & 0 deletions random/imx6ull-rngb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
/*
* Phoenix-RTOS
*
* i.MX 6ULL RNGB driver
*
* Copyright 2023 Phoenix Systems
* Author: Dawid Szpejna
*
* This file is part of Phoenix-RTOS.
*
* %LICENSE%
*/

#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <posix/utils.h>
#include <sys/debug.h>
#include <sys/platform.h>
#include <sys/interrupt.h>
#include <sys/threads.h>
#include <sys/mman.h>
#include <sys/msg.h>


enum { rng_ver = 0,
rng_cmd,
rng_cr,
rng_sr,
rng_esr,
rng_out };


#define RNGB_START_ADDRESS 0x02284000
#define RNGB_IRQ (6 + 32)


#define SELF_TEST_DONE 1U
#define SEED_DONE 2U
#define ERROR_OCCURRED 4U
#define MMAP_SIZE 4096


/* intr_st indicates status of interrupts */
static struct {
volatile uint32_t *base;
volatile uint32_t intr_st;
uint32_t port;

handle_t lock;
handle_t cond;
} common_rngb;


static int rngb_intr(unsigned int n, void *arg)
{
uint32_t status = *(common_rngb.base + rng_sr);

/* Self tests are done */
if ((status & 0x10) != 0) {
common_rngb.intr_st |= SELF_TEST_DONE;
}

/* Seeding is done*/
if ((status & 0x20) != 0) {
common_rngb.intr_st |= SEED_DONE;
}

/* An error occurred*/
if ((status & (1 << 16)) != 0) {
common_rngb.intr_st |= ERROR_OCCURRED;
}

/* Clear interrupt */
*(common_rngb.base + rng_cmd) = 0x20;
return 1;
}


static void systemCleanup(int level)
ziemleszcz marked this conversation as resolved.
Show resolved Hide resolved
{
if (level > 3) {
resourceDestroy(common_rngb.cond);
}

if (level > 2) {
resourceDestroy(common_rngb.lock);
}

if (level > 1) {
portDestroy(common_rngb.port);
}

if (level > 0) {
munmap((void *)common_rngb.base, MMAP_SIZE);
}
}


static int systemInit(void)
{
const char devpath[] = "random";
int err;
oid_t dev;

common_rngb.base = mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_DEVICE, OID_PHYSMEM, RNGB_START_ADDRESS);
if (common_rngb.base == MAP_FAILED) {
printf("rngb: could not map addr\n");
return -1;
}

err = portCreate(&common_rngb.port);
if (err != EOK) {
printf("rngb: could not create port\n");
systemCleanup(1);
return -1;
}

dev.port = common_rngb.port;
dev.id = 0;

err = mutexCreate(&common_rngb.lock);
if (err != EOK) {
printf("rngb: could not create mutex for rngb\n");
systemCleanup(2);
return -1;
}

err = condCreate(&common_rngb.cond);
if (err != EOK) {
printf("rngb: could not create cond for rngb\n");
systemCleanup(3);
return -1;
}

err = create_dev(&dev, devpath);
if (err != EOK) {
printf("rngb: could not create port file %s (err %d)\n", devpath, err);
systemCleanup(4);
return -1;
}

return 0;
}


static int hardwareInit(void)
{
int err;

/* Reset and wait until rngb is sleeping */
*(common_rngb.base + rng_cmd) = 0x40;
do {
err = *(common_rngb.base + rng_sr) & 0x4;
} while (err == 0);

interrupt(RNGB_IRQ, rngb_intr, NULL, common_rngb.cond, NULL);

/* Run self test */
*(common_rngb.base + rng_cmd) = 0x1;
mutexLock(common_rngb.lock);
while (common_rngb.intr_st == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are waiting for whether the self-test has finished or failed and not for all statuses, so shouldn't it be?

Suggested change
while (common_rngb.intr_st == 0) {
while ((common_rngb.intr_st & (SELF_TEST_DONE | ERROR_OCCURRED)) == 0) {

condWait(common_rngb.cond, common_rngb.lock, 3000);
}
mutexUnlock(common_rngb.lock);

if ((common_rngb.intr_st & ERROR_OCCURRED) != 0) {
printf("rngb: self-test failed\n");

systemCleanup(4);
return -1;
}

common_rngb.intr_st = 0;

/* Run seeding */
*(common_rngb.base + rng_cmd) = 0x2;
mutexLock(common_rngb.lock);
while (common_rngb.intr_st == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are waiting for whether the seeding has finished or failed and not for all statuses, so shouldn't it be?

Suggested change
while (common_rngb.intr_st == 0) {
while ((common_rngb.intr_st & (SEED_DONE | ERROR_OCCURRED)) == 0) {

condWait(common_rngb.cond, common_rngb.lock, 3000);
}
mutexUnlock(common_rngb.lock);

if ((common_rngb.intr_st & ERROR_OCCURRED) != 0) {
printf("rngb: error after generating seed\n");

systemCleanup(4);
return -1;
}

common_rngb.intr_st = 0;

/* Enable automatic seeding */
*(common_rngb.base + rng_cr) = 0x10;

printf("imx6ull-rngb: initialized\n");

return 0;
}


static int readRandoms(char *buff, size_t size, unsigned mode)
{
union {
uint32_t val32;
char val8[sizeof(uint32_t)];
} reg;
unsigned int i;
int status;

if (size == 0) {
return 0;
}

mutexLock(common_rngb.lock);
i = 0;
while (i < size) {
if ((i % sizeof(uint32_t)) == 0) {
status = *(common_rngb.base + rng_sr);
if (((status >> 16) & 1U) == 1) {
mutexUnlock(common_rngb.lock);
return -EIO;
}
if (((status >> 8) & 0xf) == 0) {
if ((mode & O_NONBLOCK) != 0) {
break;
}
/* wait for new values in FIFO */
continue;
ziemleszcz marked this conversation as resolved.
Show resolved Hide resolved
}
reg.val32 = *(common_rngb.base + rng_out);
}
buff[i] = reg.val8[i % sizeof(uint32_t)];
i++;
}
mutexUnlock(common_rngb.lock);

return i == 0 ? -EAGAIN : i;
}


static void handleMsg(void *arg)
{
msg_t msg;
unsigned long int rid;
int err;

while (1) {
err = msgRecv(common_rngb.port, &msg, &rid);
if (err < 0) {
if (err == -EINTR) {
continue;
}
else {
printf("rngb: msgRecv returned error: %s\n", strerror(-err));
break;
}
}

switch (msg.type) {
case mtClose:
case mtOpen:
msg.o.io.err = msg.i.openclose.oid.id != 0 ? -ENOENT : EOK;
break;

case mtRead:
if (msg.o.data != NULL) {
msg.o.io.err = readRandoms(msg.o.data, msg.o.size > 512 ? 512 : msg.o.size, msg.i.io.mode);
}
else {
msg.o.io.err = -EINVAL;
}
break;

default:
msg.o.io.err = -EINVAL;
break;
}

msgRespond(common_rngb.port, &msg, rid);
}
}


int main(int argc, char **argv)
{
oid_t root;
(void)argc;
(void)argv;

while (lookup("/", NULL, &root) < 0) {
usleep(10000);
}

if (systemInit() || hardwareInit()) {
return EIO;
}

handleMsg(NULL);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

System cleanup is missing, any required resources freeing - if handleMsg() returns on msgRecv() error, also return 0 is misleading if handleMsg() terminates.

return 0;
}
Loading