diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 36fed53416..b70060a6eb 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -59,6 +59,10 @@ config DRIVERS_VIRTIO_RNG default n select ARCH_HAVE_RNG +config DRIVERS_VIRTIO_RPMB + bool "Virtio RPMB support" + default n + config DRIVERS_VIRTIO_SERIAL bool "Virtio serial support" depends on SERIAL diff --git a/drivers/virtio/Make.defs b/drivers/virtio/Make.defs index fc7bd8f4a7..d1444e1099 100644 --- a/drivers/virtio/Make.defs +++ b/drivers/virtio/Make.defs @@ -48,6 +48,10 @@ ifeq ($(CONFIG_DRIVERS_VIRTIO_RNG),y) CSRCS += virtio-rng.c endif +ifeq ($(CONFIG_DRIVERS_VIRTIO_RPMB),y) + CSRCS += virtio-rpmb.c +endif + ifeq ($(CONFIG_DRIVERS_VIRTIO_SERIAL),y) CSRCS += virtio-serial.c endif @@ -55,6 +59,7 @@ endif ifeq ($(CONFIG_DRIVERS_VIRTIO_SOUND),y) CSRCS += virtio-snd.c endif + # Include build support DEPPATH += --dep-path virtio diff --git a/drivers/virtio/virtio-rpmb.c b/drivers/virtio/virtio-rpmb.c new file mode 100644 index 0000000000..d944875d02 --- /dev/null +++ b/drivers/virtio/virtio-rpmb.c @@ -0,0 +1,276 @@ +/**************************************************************************** + * drivers/virtio/virtio-rpmb.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "virtio-rpmb.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define VIRTIO_RPMB_DEVNAME "/dev/rpmb" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct virtio_rpmb_priv_s +{ + /* The virtio device we're associated with */ + + FAR struct virtio_device *vdev; +}; + +struct virtio_rpmb_cookie_s +{ + sem_t sem; + size_t len; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int virtio_rpmb_probe(FAR struct virtio_device *vdev); +static void virtio_rpmb_remove(FAR struct virtio_device *vdev); +static int virtio_rpmb_ioctl(FAR struct file *, int, unsigned long); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct virtio_driver g_virtio_rpmb_driver = +{ + LIST_INITIAL_VALUE(g_virtio_rpmb_driver.node), /* node */ + VIRTIO_ID_RPMB, /* device id */ + virtio_rpmb_probe, /* probe */ + virtio_rpmb_remove, /* remove */ +}; + +static const struct file_operations g_virtio_rpmb_ops = +{ + NULL, /* open */ + NULL, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + virtio_rpmb_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL, /* poll */ +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + NULL, /* unlink */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* virtio_rpmb_done() - virtual queue completion callback */ + +static void virtio_rpmb_done(FAR struct virtqueue *vq) +{ + FAR struct virtio_rpmb_cookie_s *cookie; + uint32_t len; + + cookie = virtqueue_get_buffer(vq, &len, NULL); + if (cookie != NULL) + { + /* Assign the return length */ + + cookie->len = len; + + /* Read completed, post the sem */ + + nxsem_post(&cookie->sem); + } +} + +/* This is just a simple helper for processing the virtqueue buf. It will + * block until the resp arrives. Returns number of bytes written back + * or negative if it failed. + */ + +static int virtio_rpmb_transact(FAR struct virtio_rpmb_priv_s *priv, + FAR struct virtqueue_buf *vb, + int out, int in) +{ + FAR struct virtqueue *vq = priv->vdev->vrings_info[0].vq; + struct virtio_rpmb_cookie_s cookie; + int ret; + + /* Init the cookie */ + + cookie.len = 0; + nxsem_init(&cookie.sem, 0, 0); + + /* Add the input buffer to the virtqueue, and the cookie as the virtqueue + * cookie. (virtqueue_get_buffer() will return cookie). + */ + + ret = virtqueue_add_buffer(vq, vb, out, in, &cookie); + if (ret < 0) + { + return ret; + } + + /* Notify the other side to process the added virtqueue buffer */ + + virtqueue_kick(vq); + + /* Wait fot completion */ + + nxsem_wait_uninterruptible(&cookie.sem); + return cookie.len; +} + +/**************************************************************************** + * Name: virtio_blk_ioctl + ****************************************************************************/ + +static int virtio_rpmb_ioctl(FAR struct file *filep, int cmd, + unsigned long arg) +{ + FAR struct virtio_rpmb_priv_s *priv; + FAR struct mmc_ioc_multi_cmd *mioc = (FAR struct mmc_ioc_multi_cmd *)arg; + struct virtqueue_buf vb[mioc->num_of_cmds]; + int ret; + int i; + + priv = (FAR struct virtio_rpmb_priv_s *)filep->f_inode->i_private; + + for (i = 0; i < mioc->num_of_cmds; i++) + { + vb[i].buf = (FAR void *)mioc->cmds[i].data_ptr; + vb[i].len = mioc->cmds[i].blocks * mioc->cmds[i].blksz; + } + + ret = virtio_rpmb_transact(priv, vb, mioc->num_of_cmds - 1, 1); + return ret < 0 ? ret : 0; +} + +static int virtio_rpmb_init(FAR struct virtio_rpmb_priv_s *priv, + FAR struct virtio_device *vdev) +{ + FAR const char *vqname[1]; + vq_callback callback[1]; + int ret; + + priv->vdev = vdev; + vdev->priv = priv; + + /* Initialize the virtio device */ + + virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER); + virtio_set_features(vdev, 0); + virtio_set_status(vdev, VIRTIO_CONFIG_FEATURES_OK); + + vqname[0] = "virtio_rpmb_vq"; + callback[0] = virtio_rpmb_done; + ret = virtio_create_virtqueues(vdev, 0, 1, vqname, callback); + if (ret < 0) + { + vrterr("virtio_device_create_virtqueue failed, ret=%d\n", ret); + goto err_with_lock; + } + + virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER_OK); + virtqueue_enable_cb(vdev->vrings_info[0].vq); + return OK; + +err_with_lock: + return ret; +} + +static void virtio_rpmb_uninit(FAR struct virtio_rpmb_priv_s *priv) +{ + FAR struct virtio_device *vdev = priv->vdev; + + virtio_reset_device(vdev); + virtio_delete_virtqueues(vdev); +} + +static int virtio_rpmb_probe(FAR struct virtio_device *vdev) +{ + FAR struct virtio_rpmb_priv_s *priv; + int ret; + + /* Alloc the virtio block driver private data */ + + priv = kmm_zalloc(sizeof(*priv)); + if (priv == NULL) + { + vrterr("No enough memory\n"); + return -ENOMEM; + } + + /* Init the virtio block driver */ + + ret = virtio_rpmb_init(priv, vdev); + if (ret < 0) + { + vrterr("virtio_rpmb_init failed, ret=%d\n", ret); + goto err_with_priv; + } + + ret = register_driver(VIRTIO_RPMB_DEVNAME, &g_virtio_rpmb_ops, 0666, + priv); + if (ret < 0) + { + vrterr("Register NuttX driver failed, ret=%d\n", ret); + goto err_with_init; + } + + return ret; + +err_with_init: + virtio_rpmb_uninit(priv); +err_with_priv: + kmm_free(priv); + return ret; +} + +static void virtio_rpmb_remove(FAR struct virtio_device *vdev) +{ + FAR struct virtio_rpmb_priv_s *priv = vdev->priv; + + unregister_driver(VIRTIO_RPMB_DEVNAME); + virtio_rpmb_uninit(priv); + kmm_free(priv); +} + +int virtio_register_rpmb_driver(void) +{ + return virtio_register_driver(&g_virtio_rpmb_driver); +} diff --git a/drivers/virtio/virtio-rpmb.h b/drivers/virtio/virtio-rpmb.h new file mode 100644 index 0000000000..4cc14f920d --- /dev/null +++ b/drivers/virtio/virtio-rpmb.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * drivers/virtio/virtio-rpmb.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __DRIVERS_VIRTIO_VIRTIO_RPMB_H +#define __DRIVERS_VIRTIO_VIRTIO_RPMB_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifdef CONFIG_DRIVERS_VIRTIO_RPMB + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* RPMB Request Types */ + +#define VIRTIO_RPMB_REQ_PROGRAM_KEY 0x0001 +#define VIRTIO_RPMB_REQ_GET_WRITE_COUNTER 0x0002 +#define VIRTIO_RPMB_REQ_DATA_WRITE 0x0003 +#define VIRTIO_RPMB_REQ_DATA_READ 0x0004 +#define VIRTIO_RPMB_REQ_RESULT_READ 0x0005 + +/* RPMB Response Types */ + +#define VIRTIO_RPMB_RESP_PROGRAM_KEY 0x0100 +#define VIRTIO_RPMB_RESP_GET_COUNTER 0x0200 +#define VIRTIO_RPMB_RESP_DATA_WRITE 0x0300 +#define VIRTIO_RPMB_RESP_DATA_READ 0x0400 + +/* RPMB Operation Results + * VIRTIO_RPMB_RES_OK : Operation successful + * VIRTIO_RPMB_RES_GENERAL_FAILURE : General failure + * VIRTIO_RPMB_RES_AUTH_FAILURE : Mac doesn't match or calculation + * failure + * VIRTIO_RPMB_RES_COUNT_FAILURE : Counter doesn't match or counter + * increment failure + * VIRTIO_RPMB_RES_ADDR_FAILURE : Address out of range or wrong + * address alignment + * VIRTIO_RPMB_RES_WRITE_FAILURE : Data, counter, or result write failure + * VIRTIO_RPMB_RES_READ_FAILURE : Data, counter, or result read failure + * VIRTIO_RPMB_RES_NO_AUTH_KEY : Authentication key not yet programmed + * VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED: Counter expired + */ + +#define VIRTIO_RPMB_RES_OK 0x0000 +#define VIRTIO_RPMB_RES_GENERAL_FAILURE 0x0001 +#define VIRTIO_RPMB_RES_AUTH_FAILURE 0x0002 +#define VIRTIO_RPMB_RES_COUNT_FAILURE 0x0003 +#define VIRTIO_RPMB_RES_ADDR_FAILURE 0x0004 +#define VIRTIO_RPMB_RES_WRITE_FAILURE 0x0005 +#define VIRTIO_RPMB_RES_READ_FAILURE 0x0006 +#define VIRTIO_RPMB_RES_NO_AUTH_KEY 0x0007 +#define VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED 0x0080 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct virtio_rpmb_config_s +{ + uint8_t capacity; + uint8_t max_wr_cnt; + uint8_t max_rd_cnt; +}; + +struct virtio_rpmb_frame +{ + uint8_t stuff[196]; + uint8_t key_mac[32]; + uint8_t data[256]; + uint8_t nonce[16]; + uint32_t write_counter; + uint16_t addr; + uint16_t block_count; + uint16_t result; + uint16_t req_resp; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int virtio_register_rpmb_driver(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_DRIVERS_VIRTIO_RPMB */ + +#endif /* __DRIVERS_VIRTIO_VIRTIO_RPMB_H */ diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 85b218d077..e01a776880 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -33,6 +33,7 @@ #include "virtio-input.h" #include "virtio-net.h" #include "virtio-rng.h" +#include "virtio-rpmb.h" #include "virtio-serial.h" #include "virtio-snd.h" @@ -176,6 +177,14 @@ void virtio_register_drivers(void) } #endif +#ifdef CONFIG_DRIVERS_VIRTIO_RPMB + ret = virtio_register_rpmb_driver(); + if (ret < 0) + { + vrterr("virtio_register_rpmb_driver failed, ret=%d\n", ret); + } +#endif + UNUSED(ret); }