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 typedef struct RngEgd RngEgd; 23 DECLARE_INSTANCE_CHECKER(RngEgd, RNG_EGD, 24 TYPE_RNG_EGD) 25 26 struct RngEgd { 27 RngBackend parent; 28 29 CharBackend chr; 30 char *chr_name; 31 }; 32 33 static void rng_egd_request_entropy(RngBackend *b, RngRequest *req) 34 { 35 RngEgd *s = RNG_EGD(b); 36 size_t size = req->size; 37 38 while (size > 0) { 39 uint8_t header[2]; 40 uint8_t len = MIN(size, 255); 41 42 /* synchronous entropy request */ 43 header[0] = 0x02; 44 header[1] = len; 45 46 /* XXX this blocks entire thread. Rewrite to use 47 * qemu_chr_fe_write and background I/O callbacks */ 48 qemu_chr_fe_write_all(&s->chr, header, sizeof(header)); 49 50 size -= len; 51 } 52 } 53 54 static int rng_egd_chr_can_read(void *opaque) 55 { 56 RngEgd *s = RNG_EGD(opaque); 57 RngRequest *req; 58 int size = 0; 59 60 QSIMPLEQ_FOREACH(req, &s->parent.requests, next) { 61 size += req->size - req->offset; 62 } 63 64 return size; 65 } 66 67 static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size) 68 { 69 RngEgd *s = RNG_EGD(opaque); 70 size_t buf_offset = 0; 71 72 while (size > 0 && !QSIMPLEQ_EMPTY(&s->parent.requests)) { 73 RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests); 74 int len = MIN(size, req->size - req->offset); 75 76 memcpy(req->data + req->offset, buf + buf_offset, len); 77 buf_offset += len; 78 req->offset += len; 79 size -= len; 80 81 if (req->offset == req->size) { 82 req->receive_entropy(req->opaque, req->data, req->size); 83 84 rng_backend_finalize_request(&s->parent, req); 85 } 86 } 87 } 88 89 static void rng_egd_opened(RngBackend *b, Error **errp) 90 { 91 RngEgd *s = RNG_EGD(b); 92 Chardev *chr; 93 94 if (s->chr_name == NULL) { 95 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 96 "chardev", "a valid character device"); 97 return; 98 } 99 100 chr = qemu_chr_find(s->chr_name); 101 if (chr == NULL) { 102 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 103 "Device '%s' not found", s->chr_name); 104 return; 105 } 106 if (!qemu_chr_fe_init(&s->chr, chr, errp)) { 107 return; 108 } 109 110 /* FIXME we should resubmit pending requests when the CDS reconnects. */ 111 qemu_chr_fe_set_handlers(&s->chr, rng_egd_chr_can_read, 112 rng_egd_chr_read, NULL, NULL, s, NULL, true); 113 } 114 115 static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp) 116 { 117 RngBackend *b = RNG_BACKEND(obj); 118 RngEgd *s = RNG_EGD(b); 119 120 if (b->opened) { 121 error_setg(errp, QERR_PERMISSION_DENIED); 122 } else { 123 g_free(s->chr_name); 124 s->chr_name = g_strdup(value); 125 } 126 } 127 128 static char *rng_egd_get_chardev(Object *obj, Error **errp) 129 { 130 RngEgd *s = RNG_EGD(obj); 131 Chardev *chr = qemu_chr_fe_get_driver(&s->chr); 132 133 if (chr && chr->label) { 134 return g_strdup(chr->label); 135 } 136 137 return NULL; 138 } 139 140 static void rng_egd_init(Object *obj) 141 { 142 object_property_add_str(obj, "chardev", 143 rng_egd_get_chardev, rng_egd_set_chardev); 144 } 145 146 static void rng_egd_finalize(Object *obj) 147 { 148 RngEgd *s = RNG_EGD(obj); 149 150 qemu_chr_fe_deinit(&s->chr, false); 151 g_free(s->chr_name); 152 } 153 154 static void rng_egd_class_init(ObjectClass *klass, void *data) 155 { 156 RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); 157 158 rbc->request_entropy = rng_egd_request_entropy; 159 rbc->opened = rng_egd_opened; 160 } 161 162 static const TypeInfo rng_egd_info = { 163 .name = TYPE_RNG_EGD, 164 .parent = TYPE_RNG_BACKEND, 165 .instance_size = sizeof(RngEgd), 166 .class_init = rng_egd_class_init, 167 .instance_init = rng_egd_init, 168 .instance_finalize = rng_egd_finalize, 169 }; 170 171 static void register_types(void) 172 { 173 type_register_static(&rng_egd_info); 174 } 175 176 type_init(register_types); 177