rpmb: add virtio rpmb support
The RPMB partition cannot be accessed via standard block layer, but by a set of specific commands: WRITE, READ, GET_WRITE_COUNTER, and PROGRAM_KEY. Such a partition provides authenticated and replay protected access, hence suitable as a secure storage. Signed-off-by: wanggang26 <wanggang26@xiaomi.com>
This commit is contained in:
parent
f150699d7a
commit
0e7e7c4ee6
@ -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
|
||||
|
@ -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
|
||||
|
276
drivers/virtio/virtio-rpmb.c
Normal file
276
drivers/virtio/virtio-rpmb.c
Normal file
@ -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 <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/mmcsd.h>
|
||||
#include <nuttx/virtio/virtio.h>
|
||||
|
||||
#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);
|
||||
}
|
130
drivers/virtio/virtio-rpmb.h
Normal file
130
drivers/virtio/virtio-rpmb.h
Normal file
@ -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 <nuttx/config.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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 */
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user