qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

rng-egd.c (4150B)


      1 /*
      2  * QEMU Random Number Generator Backend
      3  *
      4  * Copyright IBM, Corp. 2012
      5  *
      6  * Authors:
      7  *  Anthony Liguori   <aliguori@us.ibm.com>
      8  *
      9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10  * See the COPYING file in the top-level directory.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "sysemu/rng.h"
     15 #include "chardev/char-fe.h"
     16 #include "qapi/error.h"
     17 #include "qapi/qmp/qerror.h"
     18 #include "qemu/module.h"
     19 #include "qom/object.h"
     20 
     21 #define TYPE_RNG_EGD "rng-egd"
     22 OBJECT_DECLARE_SIMPLE_TYPE(RngEgd, RNG_EGD)
     23 
     24 struct RngEgd {
     25     RngBackend parent;
     26 
     27     CharBackend chr;
     28     char *chr_name;
     29 };
     30 
     31 static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
     32 {
     33     RngEgd *s = RNG_EGD(b);
     34     size_t size = req->size;
     35 
     36     while (size > 0) {
     37         uint8_t header[2];
     38         uint8_t len = MIN(size, 255);
     39 
     40         /* synchronous entropy request */
     41         header[0] = 0x02;
     42         header[1] = len;
     43 
     44         /* XXX this blocks entire thread. Rewrite to use
     45          * qemu_chr_fe_write and background I/O callbacks */
     46         qemu_chr_fe_write_all(&s->chr, header, sizeof(header));
     47 
     48         size -= len;
     49     }
     50 }
     51 
     52 static int rng_egd_chr_can_read(void *opaque)
     53 {
     54     RngEgd *s = RNG_EGD(opaque);
     55     RngRequest *req;
     56     int size = 0;
     57 
     58     QSIMPLEQ_FOREACH(req, &s->parent.requests, next) {
     59         size += req->size - req->offset;
     60     }
     61 
     62     return size;
     63 }
     64 
     65 static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
     66 {
     67     RngEgd *s = RNG_EGD(opaque);
     68     size_t buf_offset = 0;
     69 
     70     while (size > 0 && !QSIMPLEQ_EMPTY(&s->parent.requests)) {
     71         RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests);
     72         int len = MIN(size, req->size - req->offset);
     73 
     74         memcpy(req->data + req->offset, buf + buf_offset, len);
     75         buf_offset += len;
     76         req->offset += len;
     77         size -= len;
     78 
     79         if (req->offset == req->size) {
     80             req->receive_entropy(req->opaque, req->data, req->size);
     81 
     82             rng_backend_finalize_request(&s->parent, req);
     83         }
     84     }
     85 }
     86 
     87 static void rng_egd_opened(RngBackend *b, Error **errp)
     88 {
     89     RngEgd *s = RNG_EGD(b);
     90     Chardev *chr;
     91 
     92     if (s->chr_name == NULL) {
     93         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
     94                    "chardev", "a valid character device");
     95         return;
     96     }
     97 
     98     chr = qemu_chr_find(s->chr_name);
     99     if (chr == NULL) {
    100         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
    101                   "Device '%s' not found", s->chr_name);
    102         return;
    103     }
    104     if (!qemu_chr_fe_init(&s->chr, chr, errp)) {
    105         return;
    106     }
    107 
    108     /* FIXME we should resubmit pending requests when the CDS reconnects. */
    109     qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read,
    110                              rng_egd_chr_read, NULL, NULL, s, NULL, true);
    111 }
    112 
    113 static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
    114 {
    115     RngBackend *b = RNG_BACKEND(obj);
    116     RngEgd *s = RNG_EGD(b);
    117 
    118     if (b->opened) {
    119         error_setg(errp, "Property 'chardev' can no longer be set");
    120     } else {
    121         g_free(s->chr_name);
    122         s->chr_name = g_strdup(value);
    123     }
    124 }
    125 
    126 static char *rng_egd_get_chardev(Object *obj, Error **errp)
    127 {
    128     RngEgd *s = RNG_EGD(obj);
    129     Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
    130 
    131     if (chr && chr->label) {
    132         return g_strdup(chr->label);
    133     }
    134 
    135     return NULL;
    136 }
    137 
    138 static void rng_egd_finalize(Object *obj)
    139 {
    140     RngEgd *s = RNG_EGD(obj);
    141 
    142     qemu_chr_fe_deinit(&s->chr, false);
    143     g_free(s->chr_name);
    144 }
    145 
    146 static void rng_egd_class_init(ObjectClass *klass, void *data)
    147 {
    148     RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
    149 
    150     rbc->request_entropy = rng_egd_request_entropy;
    151     rbc->opened = rng_egd_opened;
    152     object_class_property_add_str(klass, "chardev",
    153                                   rng_egd_get_chardev, rng_egd_set_chardev);
    154 }
    155 
    156 static const TypeInfo rng_egd_info = {
    157     .name = TYPE_RNG_EGD,
    158     .parent = TYPE_RNG_BACKEND,
    159     .instance_size = sizeof(RngEgd),
    160     .class_init = rng_egd_class_init,
    161     .instance_finalize = rng_egd_finalize,
    162 };
    163 
    164 static void register_types(void)
    165 {
    166     type_register_static(&rng_egd_info);
    167 }
    168 
    169 type_init(register_types);