From: "Alex Bennée" <alex.bennee@linaro.org> To: qemu-devel@nongnu.org, maxim.uvarov@linaro.org, joakim.bech@linaro.org, ilias.apalodimas@linaro.org, tomas.winkler@intel.com, yang.huang@intel.com, bing.zhu@intel.com, Matti.Moell@opensynergy.com, hmo@opensynergy.com Cc: jean-philippe@linaro.org, takahiro.akashi@linaro.org, virtualization@lists.linuxfoundation.org, "Alex Bennée" <alex.bennee@linaro.org>, arnd@linaro.org, stratos-dev@op-lists.linaro.org Subject: [RFC PATCH 13/19] tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake Date: Fri, 25 Sep 2020 13:51:41 +0100 [thread overview] Message-ID: <20200925125147.26943-14-alex.bennee@linaro.org> (raw) In-Reply-To: <20200925125147.26943-1-alex.bennee@linaro.org> This implements the first handshake of the device initialisation which is the programming of the device key. This can only be done once per-device. Currently there is no persistence for the device key and other metadata such as the write count. This will be added later. [TODO: clarify the spec if we should respond immediately or on request] Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tools/vhost-user-rpmb/main.c | 299 +++++++++++++++++++++++++++++++++-- 1 file changed, 286 insertions(+), 13 deletions(-) diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c index 64bd7e79f573..9c98f6916f6f 100644 --- a/tools/vhost-user-rpmb/main.c +++ b/tools/vhost-user-rpmb/main.c @@ -22,10 +22,14 @@ #include <sys/stat.h> #include <sys/mman.h> #include <unistd.h> +#include <endian.h> +#include <assert.h> #include "contrib/libvhost-user/libvhost-user-glib.h" #include "contrib/libvhost-user/libvhost-user.h" +#include "hmac_sha256.h" + #ifndef container_of #define container_of(ptr, type, member) ({ \ const typeof(((type *) 0)->member) *__mptr = (ptr); \ @@ -57,6 +61,31 @@ enum { /* These structures are defined in the specification */ #define KiB (1UL << 10) #define MAX_RPMB_SIZE (KiB * 128 * 256) +#define RPMB_KEY_MAC_SIZE 32 + +/* 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 */ +#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 struct virtio_rpmb_config { uint8_t capacity; @@ -64,9 +93,13 @@ struct virtio_rpmb_config { uint8_t max_rd_cnt; }; +/* + * This is based on the JDEC standard and not the currently not + * up-streamed NVME standard. + */ struct virtio_rpmb_frame { uint8_t stuff[196]; - uint8_t key_mac[32]; + uint8_t key_mac[RPMB_KEY_MAC_SIZE]; uint8_t data[256]; uint8_t nonce[16]; /* remaining fields are big-endian */ @@ -75,7 +108,7 @@ struct virtio_rpmb_frame { uint16_t block_count; uint16_t result; uint16_t req_resp; -}; +} __attribute__((packed)); /* * Structure to track internal state of RPMB Device @@ -87,15 +120,63 @@ typedef struct VuRpmb { GMainLoop *loop; int flash_fd; void *flash_map; + uint8_t *key; + uint16_t last_result; + uint16_t last_reqresp; } VuRpmb; -struct virtio_rpmb_ctrl_command { - VuVirtqElement elem; - VuVirtq *vq; - struct virtio_rpmb_frame frame; - uint32_t error; - bool finished; -}; +/* refer to util/iov.c */ +static size_t vrpmb_iov_size(const struct iovec *iov, + const unsigned int iov_cnt) +{ + size_t len; + unsigned int i; + + len = 0; + for (i = 0; i < iov_cnt; i++) { + len += iov[i].iov_len; + } + return len; +} + + +static size_t vrpmb_iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt, + size_t offset, void *buf, size_t bytes) +{ + size_t done; + unsigned int i; + for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { + if (offset < iov[i].iov_len) { + size_t len = MIN(iov[i].iov_len - offset, bytes - done); + memcpy(buf + done, iov[i].iov_base + offset, len); + done += len; + offset = 0; + } else { + offset -= iov[i].iov_len; + } + } + assert(offset == 0); + return done; +} + +static size_t vrpmb_iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, + size_t offset, const void *buf, size_t bytes) +{ + size_t done; + unsigned int i; + for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { + if (offset < iov[i].iov_len) { + size_t len = MIN(iov[i].iov_len - offset, bytes - done); + memcpy(iov[i].iov_base + offset, buf + done, len); + done += len; + offset = 0; + } else { + offset -= iov[i].iov_len; + } + } + assert(offset == 0); + return done; +} static void vrpmb_panic(VuDev *dev, const char *msg) { @@ -142,19 +223,211 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data, return 0; } +/* + * vrpmb_update_mac_in_frame: + * + * From the spec: + * The MAC is calculated using HMAC SHA-256. It takes + * as input a key and a message. The key used for the MAC calculation + * is always the 256-bit RPMB authentication key. The message used as + * input to the MAC calculation is the concatenation of the fields in + * the RPMB frames excluding stuff bytes and the MAC itself. + * + * The code to do this has been lifted from the optee supplicant code + * which itself uses a 3 clause BSD chunk of code. + */ + +static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm) +{ + hmac_sha256_ctx ctx; + static const int dlen = (sizeof(struct virtio_rpmb_frame) - + offsetof(struct virtio_rpmb_frame, data)); + + hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE); + hmac_sha256_update(&ctx, frm->data, dlen); + hmac_sha256_final(&ctx, &frm->key_mac[0], 32); +} + +/* + * Handlers for individual control messages + */ + +/* + * vrpmb_handle_program_key: + * + * Program the device with our key. The spec is a little hazzy on if + * we respond straight away or we wait for the user to send a + * VIRTIO_RPMB_REQ_RESULT_READ request. + */ +static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame) +{ + VuRpmb *r = container_of(dev, VuRpmb, dev.parent); + + /* + * Run the checks from: + * 5.12.6.1.1 Device Requirements: Device Operation: Program Key + */ + r->last_reqresp = VIRTIO_RPMB_RESP_PROGRAM_KEY; + + /* Fail if already programmed */ + if (r->key) { + g_debug("key already programmed"); + r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE; + } else if (be16toh(frame->block_count) != 1) { + g_debug("weird block counts (%d)", frame->block_count); + r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE; + } else { + r->key = g_memdup(&frame->key_mac[0], RPMB_KEY_MAC_SIZE); + r->last_result = VIRTIO_RPMB_RES_OK; + } + + g_info("%s: req_resp = %x, result = %x", __func__, + r->last_reqresp, r->last_result); + return; +} + +/* + * Return the result of the last message. This is only valid if the + * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or + * VIRTIO_RPMB_REQ_DATA_WRITE. + * + * The frame should be freed once sent. + */ +static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev) +{ + VuRpmb *r = container_of(dev, VuRpmb, dev.parent); + struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1); + + if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY || + r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) { + resp->result = htobe16(r->last_result); + resp->req_resp = htobe16(r->last_reqresp); + } else { + resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE); + } + + /* calculate HMAC */ + if (!r->key) { + resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE); + } else { + vrpmb_update_mac_in_frame(r, resp); + } + + g_info("%s: result = %x req_resp = %x", __func__, + be16toh(resp->result), + be16toh(resp->req_resp)); + return resp; +} + +static void fmt_bytes(GString *s, uint8_t *bytes, int len) +{ + int i; + for (i = 0; i < len; i++) { + if (i % 16 == 0) { + g_string_append_c(s, '\n'); + } + g_string_append_printf(s, "%x ", bytes[i]); + } +} + +static void vrpmb_dump_frame(struct virtio_rpmb_frame *frame) +{ + g_autoptr(GString) s = g_string_new("frame: "); + + g_string_append_printf(s, " %p\n", frame); + g_string_append_printf(s, "key_mac:"); + fmt_bytes(s, (uint8_t *) &frame->key_mac[0], 32); + g_string_append_printf(s, "\ndata:"); + fmt_bytes(s, (uint8_t *) &frame->data, 256); + g_string_append_printf(s, "\nnonce:"); + fmt_bytes(s, (uint8_t *) &frame->nonce, 16); + g_string_append_printf(s, "\nwrite_counter: %d\n", + be32toh(frame->write_counter)); + g_string_append_printf(s, "address: %#04x\n", be16toh(frame->address)); + g_string_append_printf(s, "block_count: %d\n", be16toh(frame->block_count)); + g_string_append_printf(s, "result: %d\n", be16toh(frame->result)); + g_string_append_printf(s, "req_resp: %d\n", be16toh(frame->req_resp)); + + g_debug("%s: %s\n", __func__, s->str); +} + static void vrpmb_handle_ctrl(VuDev *dev, int qidx) { VuVirtq *vq = vu_get_queue(dev, qidx); - struct virtio_rpmb_ctrl_command *cmd = NULL; + struct virtio_rpmb_frame *frames = NULL; for (;;) { - cmd = vu_queue_pop(dev, vq, sizeof(struct virtio_rpmb_ctrl_command)); - if (!cmd) { + VuVirtqElement *elem; + size_t len, frame_sz = sizeof(struct virtio_rpmb_frame); + int n; + + elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { break; } + g_debug("%s: got queue (in %d, out %d)", __func__, + elem->in_num, elem->out_num); - g_debug("un-handled cmd: %p", cmd); + len = vrpmb_iov_size(elem->out_sg, elem->out_num); + frames = g_realloc(frames, len); + vrpmb_iov_to_buf(elem->out_sg, elem->out_num, 0, frames, len); + + if (len % frame_sz != 0) { + g_warning("%s: incomplete frames %zu/%zu != 0\n", + __func__, len, frame_sz); + } + + for (n = 0; n < len / frame_sz; n++) { + struct virtio_rpmb_frame *f = &frames[n]; + struct virtio_rpmb_frame *resp = NULL; + uint16_t req_resp = be16toh(f->req_resp); + bool responded = false; + + if (debug) { + g_info("req_resp=%x", req_resp); + vrpmb_dump_frame(f); + } + + switch (req_resp) { + case VIRTIO_RPMB_REQ_PROGRAM_KEY: + vrpmb_handle_program_key(dev, f); + break; + case VIRTIO_RPMB_REQ_RESULT_READ: + if (!responded) { + resp = vrpmb_handle_result_read(dev); + } else { + g_warning("%s: already sent a response in this set of frames", + __func__); + } + break; + default: + g_debug("un-handled request: %x", f->req_resp); + break; + } + + /* + * Do we have a frame to send back? + */ + if (resp) { + g_debug("sending response frame: %p", resp); + if (debug) { + vrpmb_dump_frame(resp); + } + len = vrpmb_iov_from_buf(elem->in_sg, + elem->in_num, 0, resp, sizeof(*resp)); + if (len != sizeof(*resp)) { + g_critical("%s: response size incorrect %zu vs %zu", + __func__, len, sizeof(*resp)); + } else { + vu_queue_push(dev, vq, elem, len); + vu_queue_notify(dev, vq); + responded = true; + } + + g_free(resp); + } + } } } -- 2.20.1
WARNING: multiple messages have this Message-ID (diff)
From: "Alex Bennée" <alex.bennee@linaro.org> To: qemu-devel@nongnu.org, maxim.uvarov@linaro.org, joakim.bech@linaro.org, ilias.apalodimas@linaro.org, tomas.winkler@intel.com, yang.huang@intel.com, bing.zhu@intel.com, Matti.Moell@opensynergy.com, hmo@opensynergy.com Cc: jean-philippe@linaro.org, takahiro.akashi@linaro.org, virtualization@lists.linuxfoundation.org, arnd@linaro.org, stratos-dev@op-lists.linaro.org Subject: [RFC PATCH 13/19] tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake Date: Fri, 25 Sep 2020 13:51:41 +0100 [thread overview] Message-ID: <20200925125147.26943-14-alex.bennee@linaro.org> (raw) In-Reply-To: <20200925125147.26943-1-alex.bennee@linaro.org> This implements the first handshake of the device initialisation which is the programming of the device key. This can only be done once per-device. Currently there is no persistence for the device key and other metadata such as the write count. This will be added later. [TODO: clarify the spec if we should respond immediately or on request] Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- tools/vhost-user-rpmb/main.c | 299 +++++++++++++++++++++++++++++++++-- 1 file changed, 286 insertions(+), 13 deletions(-) diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c index 64bd7e79f573..9c98f6916f6f 100644 --- a/tools/vhost-user-rpmb/main.c +++ b/tools/vhost-user-rpmb/main.c @@ -22,10 +22,14 @@ #include <sys/stat.h> #include <sys/mman.h> #include <unistd.h> +#include <endian.h> +#include <assert.h> #include "contrib/libvhost-user/libvhost-user-glib.h" #include "contrib/libvhost-user/libvhost-user.h" +#include "hmac_sha256.h" + #ifndef container_of #define container_of(ptr, type, member) ({ \ const typeof(((type *) 0)->member) *__mptr = (ptr); \ @@ -57,6 +61,31 @@ enum { /* These structures are defined in the specification */ #define KiB (1UL << 10) #define MAX_RPMB_SIZE (KiB * 128 * 256) +#define RPMB_KEY_MAC_SIZE 32 + +/* 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 */ +#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 struct virtio_rpmb_config { uint8_t capacity; @@ -64,9 +93,13 @@ struct virtio_rpmb_config { uint8_t max_rd_cnt; }; +/* + * This is based on the JDEC standard and not the currently not + * up-streamed NVME standard. + */ struct virtio_rpmb_frame { uint8_t stuff[196]; - uint8_t key_mac[32]; + uint8_t key_mac[RPMB_KEY_MAC_SIZE]; uint8_t data[256]; uint8_t nonce[16]; /* remaining fields are big-endian */ @@ -75,7 +108,7 @@ struct virtio_rpmb_frame { uint16_t block_count; uint16_t result; uint16_t req_resp; -}; +} __attribute__((packed)); /* * Structure to track internal state of RPMB Device @@ -87,15 +120,63 @@ typedef struct VuRpmb { GMainLoop *loop; int flash_fd; void *flash_map; + uint8_t *key; + uint16_t last_result; + uint16_t last_reqresp; } VuRpmb; -struct virtio_rpmb_ctrl_command { - VuVirtqElement elem; - VuVirtq *vq; - struct virtio_rpmb_frame frame; - uint32_t error; - bool finished; -}; +/* refer to util/iov.c */ +static size_t vrpmb_iov_size(const struct iovec *iov, + const unsigned int iov_cnt) +{ + size_t len; + unsigned int i; + + len = 0; + for (i = 0; i < iov_cnt; i++) { + len += iov[i].iov_len; + } + return len; +} + + +static size_t vrpmb_iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt, + size_t offset, void *buf, size_t bytes) +{ + size_t done; + unsigned int i; + for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { + if (offset < iov[i].iov_len) { + size_t len = MIN(iov[i].iov_len - offset, bytes - done); + memcpy(buf + done, iov[i].iov_base + offset, len); + done += len; + offset = 0; + } else { + offset -= iov[i].iov_len; + } + } + assert(offset == 0); + return done; +} + +static size_t vrpmb_iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, + size_t offset, const void *buf, size_t bytes) +{ + size_t done; + unsigned int i; + for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) { + if (offset < iov[i].iov_len) { + size_t len = MIN(iov[i].iov_len - offset, bytes - done); + memcpy(iov[i].iov_base + offset, buf + done, len); + done += len; + offset = 0; + } else { + offset -= iov[i].iov_len; + } + } + assert(offset == 0); + return done; +} static void vrpmb_panic(VuDev *dev, const char *msg) { @@ -142,19 +223,211 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data, return 0; } +/* + * vrpmb_update_mac_in_frame: + * + * From the spec: + * The MAC is calculated using HMAC SHA-256. It takes + * as input a key and a message. The key used for the MAC calculation + * is always the 256-bit RPMB authentication key. The message used as + * input to the MAC calculation is the concatenation of the fields in + * the RPMB frames excluding stuff bytes and the MAC itself. + * + * The code to do this has been lifted from the optee supplicant code + * which itself uses a 3 clause BSD chunk of code. + */ + +static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm) +{ + hmac_sha256_ctx ctx; + static const int dlen = (sizeof(struct virtio_rpmb_frame) - + offsetof(struct virtio_rpmb_frame, data)); + + hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE); + hmac_sha256_update(&ctx, frm->data, dlen); + hmac_sha256_final(&ctx, &frm->key_mac[0], 32); +} + +/* + * Handlers for individual control messages + */ + +/* + * vrpmb_handle_program_key: + * + * Program the device with our key. The spec is a little hazzy on if + * we respond straight away or we wait for the user to send a + * VIRTIO_RPMB_REQ_RESULT_READ request. + */ +static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame) +{ + VuRpmb *r = container_of(dev, VuRpmb, dev.parent); + + /* + * Run the checks from: + * 5.12.6.1.1 Device Requirements: Device Operation: Program Key + */ + r->last_reqresp = VIRTIO_RPMB_RESP_PROGRAM_KEY; + + /* Fail if already programmed */ + if (r->key) { + g_debug("key already programmed"); + r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE; + } else if (be16toh(frame->block_count) != 1) { + g_debug("weird block counts (%d)", frame->block_count); + r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE; + } else { + r->key = g_memdup(&frame->key_mac[0], RPMB_KEY_MAC_SIZE); + r->last_result = VIRTIO_RPMB_RES_OK; + } + + g_info("%s: req_resp = %x, result = %x", __func__, + r->last_reqresp, r->last_result); + return; +} + +/* + * Return the result of the last message. This is only valid if the + * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or + * VIRTIO_RPMB_REQ_DATA_WRITE. + * + * The frame should be freed once sent. + */ +static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev) +{ + VuRpmb *r = container_of(dev, VuRpmb, dev.parent); + struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1); + + if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY || + r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) { + resp->result = htobe16(r->last_result); + resp->req_resp = htobe16(r->last_reqresp); + } else { + resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE); + } + + /* calculate HMAC */ + if (!r->key) { + resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE); + } else { + vrpmb_update_mac_in_frame(r, resp); + } + + g_info("%s: result = %x req_resp = %x", __func__, + be16toh(resp->result), + be16toh(resp->req_resp)); + return resp; +} + +static void fmt_bytes(GString *s, uint8_t *bytes, int len) +{ + int i; + for (i = 0; i < len; i++) { + if (i % 16 == 0) { + g_string_append_c(s, '\n'); + } + g_string_append_printf(s, "%x ", bytes[i]); + } +} + +static void vrpmb_dump_frame(struct virtio_rpmb_frame *frame) +{ + g_autoptr(GString) s = g_string_new("frame: "); + + g_string_append_printf(s, " %p\n", frame); + g_string_append_printf(s, "key_mac:"); + fmt_bytes(s, (uint8_t *) &frame->key_mac[0], 32); + g_string_append_printf(s, "\ndata:"); + fmt_bytes(s, (uint8_t *) &frame->data, 256); + g_string_append_printf(s, "\nnonce:"); + fmt_bytes(s, (uint8_t *) &frame->nonce, 16); + g_string_append_printf(s, "\nwrite_counter: %d\n", + be32toh(frame->write_counter)); + g_string_append_printf(s, "address: %#04x\n", be16toh(frame->address)); + g_string_append_printf(s, "block_count: %d\n", be16toh(frame->block_count)); + g_string_append_printf(s, "result: %d\n", be16toh(frame->result)); + g_string_append_printf(s, "req_resp: %d\n", be16toh(frame->req_resp)); + + g_debug("%s: %s\n", __func__, s->str); +} + static void vrpmb_handle_ctrl(VuDev *dev, int qidx) { VuVirtq *vq = vu_get_queue(dev, qidx); - struct virtio_rpmb_ctrl_command *cmd = NULL; + struct virtio_rpmb_frame *frames = NULL; for (;;) { - cmd = vu_queue_pop(dev, vq, sizeof(struct virtio_rpmb_ctrl_command)); - if (!cmd) { + VuVirtqElement *elem; + size_t len, frame_sz = sizeof(struct virtio_rpmb_frame); + int n; + + elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { break; } + g_debug("%s: got queue (in %d, out %d)", __func__, + elem->in_num, elem->out_num); - g_debug("un-handled cmd: %p", cmd); + len = vrpmb_iov_size(elem->out_sg, elem->out_num); + frames = g_realloc(frames, len); + vrpmb_iov_to_buf(elem->out_sg, elem->out_num, 0, frames, len); + + if (len % frame_sz != 0) { + g_warning("%s: incomplete frames %zu/%zu != 0\n", + __func__, len, frame_sz); + } + + for (n = 0; n < len / frame_sz; n++) { + struct virtio_rpmb_frame *f = &frames[n]; + struct virtio_rpmb_frame *resp = NULL; + uint16_t req_resp = be16toh(f->req_resp); + bool responded = false; + + if (debug) { + g_info("req_resp=%x", req_resp); + vrpmb_dump_frame(f); + } + + switch (req_resp) { + case VIRTIO_RPMB_REQ_PROGRAM_KEY: + vrpmb_handle_program_key(dev, f); + break; + case VIRTIO_RPMB_REQ_RESULT_READ: + if (!responded) { + resp = vrpmb_handle_result_read(dev); + } else { + g_warning("%s: already sent a response in this set of frames", + __func__); + } + break; + default: + g_debug("un-handled request: %x", f->req_resp); + break; + } + + /* + * Do we have a frame to send back? + */ + if (resp) { + g_debug("sending response frame: %p", resp); + if (debug) { + vrpmb_dump_frame(resp); + } + len = vrpmb_iov_from_buf(elem->in_sg, + elem->in_num, 0, resp, sizeof(*resp)); + if (len != sizeof(*resp)) { + g_critical("%s: response size incorrect %zu vs %zu", + __func__, len, sizeof(*resp)); + } else { + vu_queue_push(dev, vq, elem, len); + vu_queue_notify(dev, vq); + responded = true; + } + + g_free(resp); + } + } } } -- 2.20.1 _______________________________________________ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
next prev parent reply other threads:[~2020-09-25 13:08 UTC|newest] Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-09-25 12:51 [RFC PATCH 00/19] vhost-user-rpmb (Replay Protected Memory Block) Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 01/19] tools/virtiofsd: add support for --socket-group Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-10-07 10:48 ` Dr. David Alan Gilbert 2020-10-07 10:48 ` Dr. David Alan Gilbert 2020-09-25 12:51 ` [RFC PATCH 02/19] hw/block: add boilerplate for vhost-user-rpmb device Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 03/19] hw/virtio: move virtio-pci.h into shared include space Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 04/19] hw/block: add vhost-user-rpmb-pci boilerplate Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 05/19] virtio-pci: add notification trace points Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 13:06 ` Philippe Mathieu-Daudé 2020-09-25 12:51 ` [RFC PATCH 06/19] tools/vhost-user-rpmb: add boilerplate and initial main Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 07/19] tools/vhost-user-rpmb: implement --print-capabilities Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 08/19] tools/vhost-user-rpmb: connect to fd and instantiate basic run loop Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 09/19] tools/vhost-user-rpmb: add a --verbose/debug flags for logging Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 10/19] tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 11/19] tools/vhost-user-rpmb: add --flash-path for backing store Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 12/19] tools/vhost-user-rpmb: import hmac_sha256 functions Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` Alex Bennée [this message] 2020-09-25 12:51 ` [RFC PATCH 13/19] tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 14/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-28 13:52 ` Joakim Bech 2020-09-28 14:56 ` Alex Bennée 2020-09-28 14:56 ` Alex Bennée 2020-09-28 15:18 ` Joakim Bech 2020-09-25 12:51 ` [RFC PATCH 16/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 17/19] tools/vhost-user-rpmb: add key persistence Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 18/19] tools/vhost-user-rpmb: allow setting of the write_count Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 12:51 ` [RFC PATCH 19/19] docs: add a man page for vhost-user-rpmb Alex Bennée 2020-09-25 12:51 ` Alex Bennée 2020-09-25 14:07 ` [RFC PATCH 00/19] vhost-user-rpmb (Replay Protected Memory Block) no-reply
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20200925125147.26943-14-alex.bennee@linaro.org \ --to=alex.bennee@linaro.org \ --cc=Matti.Moell@opensynergy.com \ --cc=arnd@linaro.org \ --cc=bing.zhu@intel.com \ --cc=hmo@opensynergy.com \ --cc=ilias.apalodimas@linaro.org \ --cc=jean-philippe@linaro.org \ --cc=joakim.bech@linaro.org \ --cc=maxim.uvarov@linaro.org \ --cc=qemu-devel@nongnu.org \ --cc=stratos-dev@op-lists.linaro.org \ --cc=takahiro.akashi@linaro.org \ --cc=tomas.winkler@intel.com \ --cc=virtualization@lists.linuxfoundation.org \ --cc=yang.huang@intel.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.