Statistics
| Branch: | Revision:

root / backends / rng-egd.c @ feature-archipelago

History | View | Annotate | Download (5.2 kB)

1 1da2738f Anthony Liguori
/*
2 1da2738f Anthony Liguori
 * QEMU Random Number Generator Backend
3 1da2738f Anthony Liguori
 *
4 1da2738f Anthony Liguori
 * Copyright IBM, Corp. 2012
5 1da2738f Anthony Liguori
 *
6 1da2738f Anthony Liguori
 * Authors:
7 1da2738f Anthony Liguori
 *  Anthony Liguori   <aliguori@us.ibm.com>
8 1da2738f Anthony Liguori
 *
9 1da2738f Anthony Liguori
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 1da2738f Anthony Liguori
 * See the COPYING file in the top-level directory.
11 1da2738f Anthony Liguori
 */
12 1da2738f Anthony Liguori
13 dccfcd0e Paolo Bonzini
#include "sysemu/rng.h"
14 dccfcd0e Paolo Bonzini
#include "sysemu/char.h"
15 7b1b5d19 Paolo Bonzini
#include "qapi/qmp/qerror.h"
16 1da2738f Anthony Liguori
#include "hw/qdev.h" /* just for DEFINE_PROP_CHR */
17 1da2738f Anthony Liguori
18 1da2738f Anthony Liguori
#define TYPE_RNG_EGD "rng-egd"
19 1da2738f Anthony Liguori
#define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
20 1da2738f Anthony Liguori
21 1da2738f Anthony Liguori
typedef struct RngEgd
22 1da2738f Anthony Liguori
{
23 1da2738f Anthony Liguori
    RngBackend parent;
24 1da2738f Anthony Liguori
25 1da2738f Anthony Liguori
    CharDriverState *chr;
26 1da2738f Anthony Liguori
    char *chr_name;
27 1da2738f Anthony Liguori
28 1da2738f Anthony Liguori
    GSList *requests;
29 1da2738f Anthony Liguori
} RngEgd;
30 1da2738f Anthony Liguori
31 1da2738f Anthony Liguori
typedef struct RngRequest
32 1da2738f Anthony Liguori
{
33 1da2738f Anthony Liguori
    EntropyReceiveFunc *receive_entropy;
34 1da2738f Anthony Liguori
    uint8_t *data;
35 1da2738f Anthony Liguori
    void *opaque;
36 1da2738f Anthony Liguori
    size_t offset;
37 1da2738f Anthony Liguori
    size_t size;
38 1da2738f Anthony Liguori
} RngRequest;
39 1da2738f Anthony Liguori
40 1da2738f Anthony Liguori
static void rng_egd_request_entropy(RngBackend *b, size_t size,
41 1da2738f Anthony Liguori
                                    EntropyReceiveFunc *receive_entropy,
42 1da2738f Anthony Liguori
                                    void *opaque)
43 1da2738f Anthony Liguori
{
44 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(b);
45 1da2738f Anthony Liguori
    RngRequest *req;
46 1da2738f Anthony Liguori
47 1da2738f Anthony Liguori
    req = g_malloc(sizeof(*req));
48 1da2738f Anthony Liguori
49 1da2738f Anthony Liguori
    req->offset = 0;
50 1da2738f Anthony Liguori
    req->size = size;
51 1da2738f Anthony Liguori
    req->receive_entropy = receive_entropy;
52 1da2738f Anthony Liguori
    req->opaque = opaque;
53 1da2738f Anthony Liguori
    req->data = g_malloc(req->size);
54 1da2738f Anthony Liguori
55 1da2738f Anthony Liguori
    while (size > 0) {
56 1da2738f Anthony Liguori
        uint8_t header[2];
57 1da2738f Anthony Liguori
        uint8_t len = MIN(size, 255);
58 1da2738f Anthony Liguori
59 1da2738f Anthony Liguori
        /* synchronous entropy request */
60 1da2738f Anthony Liguori
        header[0] = 0x02;
61 1da2738f Anthony Liguori
        header[1] = len;
62 1da2738f Anthony Liguori
63 1da2738f Anthony Liguori
        qemu_chr_fe_write(s->chr, header, sizeof(header));
64 1da2738f Anthony Liguori
65 1da2738f Anthony Liguori
        size -= len;
66 1da2738f Anthony Liguori
    }
67 1da2738f Anthony Liguori
68 1da2738f Anthony Liguori
    s->requests = g_slist_append(s->requests, req);
69 1da2738f Anthony Liguori
}
70 1da2738f Anthony Liguori
71 1da2738f Anthony Liguori
static void rng_egd_free_request(RngRequest *req)
72 1da2738f Anthony Liguori
{
73 1da2738f Anthony Liguori
    g_free(req->data);
74 1da2738f Anthony Liguori
    g_free(req);
75 1da2738f Anthony Liguori
}
76 1da2738f Anthony Liguori
77 1da2738f Anthony Liguori
static int rng_egd_chr_can_read(void *opaque)
78 1da2738f Anthony Liguori
{
79 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(opaque);
80 1da2738f Anthony Liguori
    GSList *i;
81 1da2738f Anthony Liguori
    int size = 0;
82 1da2738f Anthony Liguori
83 1da2738f Anthony Liguori
    for (i = s->requests; i; i = i->next) {
84 1da2738f Anthony Liguori
        RngRequest *req = i->data;
85 1da2738f Anthony Liguori
        size += req->size - req->offset;
86 1da2738f Anthony Liguori
    }
87 1da2738f Anthony Liguori
88 1da2738f Anthony Liguori
    return size;
89 1da2738f Anthony Liguori
}
90 1da2738f Anthony Liguori
91 1da2738f Anthony Liguori
static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
92 1da2738f Anthony Liguori
{
93 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(opaque);
94 1eb1bd9e Amos Kong
    size_t buf_offset = 0;
95 1da2738f Anthony Liguori
96 1da2738f Anthony Liguori
    while (size > 0 && s->requests) {
97 1da2738f Anthony Liguori
        RngRequest *req = s->requests->data;
98 1da2738f Anthony Liguori
        int len = MIN(size, req->size - req->offset);
99 1da2738f Anthony Liguori
100 1eb1bd9e Amos Kong
        memcpy(req->data + req->offset, buf + buf_offset, len);
101 1eb1bd9e Amos Kong
        buf_offset += len;
102 1da2738f Anthony Liguori
        req->offset += len;
103 1da2738f Anthony Liguori
        size -= len;
104 1da2738f Anthony Liguori
105 1da2738f Anthony Liguori
        if (req->offset == req->size) {
106 1da2738f Anthony Liguori
            s->requests = g_slist_remove_link(s->requests, s->requests);
107 1da2738f Anthony Liguori
108 1da2738f Anthony Liguori
            req->receive_entropy(req->opaque, req->data, req->size);
109 1da2738f Anthony Liguori
110 1da2738f Anthony Liguori
            rng_egd_free_request(req);
111 1da2738f Anthony Liguori
        }
112 1da2738f Anthony Liguori
    }
113 1da2738f Anthony Liguori
}
114 1da2738f Anthony Liguori
115 9cb535fe Anthony Liguori
static void rng_egd_free_requests(RngEgd *s)
116 9cb535fe Anthony Liguori
{
117 9cb535fe Anthony Liguori
    GSList *i;
118 9cb535fe Anthony Liguori
119 9cb535fe Anthony Liguori
    for (i = s->requests; i; i = i->next) {
120 9cb535fe Anthony Liguori
        rng_egd_free_request(i->data);
121 9cb535fe Anthony Liguori
    }
122 9cb535fe Anthony Liguori
123 9cb535fe Anthony Liguori
    g_slist_free(s->requests);
124 9cb535fe Anthony Liguori
    s->requests = NULL;
125 9cb535fe Anthony Liguori
}
126 9cb535fe Anthony Liguori
127 1da2738f Anthony Liguori
static void rng_egd_cancel_requests(RngBackend *b)
128 1da2738f Anthony Liguori
{
129 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(b);
130 1da2738f Anthony Liguori
131 1da2738f Anthony Liguori
    /* We simply delete the list of pending requests.  If there is data in the 
132 1da2738f Anthony Liguori
     * queue waiting to be read, this is okay, because there will always be
133 1da2738f Anthony Liguori
     * more data than we requested originally
134 1da2738f Anthony Liguori
     */
135 9cb535fe Anthony Liguori
    rng_egd_free_requests(s);
136 1da2738f Anthony Liguori
}
137 1da2738f Anthony Liguori
138 1da2738f Anthony Liguori
static void rng_egd_opened(RngBackend *b, Error **errp)
139 1da2738f Anthony Liguori
{
140 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(b);
141 1da2738f Anthony Liguori
142 1da2738f Anthony Liguori
    if (s->chr_name == NULL) {
143 1da2738f Anthony Liguori
        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
144 1da2738f Anthony Liguori
                  "chardev", "a valid character device");
145 1da2738f Anthony Liguori
        return;
146 1da2738f Anthony Liguori
    }
147 1da2738f Anthony Liguori
148 1da2738f Anthony Liguori
    s->chr = qemu_chr_find(s->chr_name);
149 1da2738f Anthony Liguori
    if (s->chr == NULL) {
150 1da2738f Anthony Liguori
        error_set(errp, QERR_DEVICE_NOT_FOUND, s->chr_name);
151 1da2738f Anthony Liguori
        return;
152 1da2738f Anthony Liguori
    }
153 1da2738f Anthony Liguori
154 456d6069 Hans de Goede
    if (qemu_chr_fe_claim(s->chr) != 0) {
155 456d6069 Hans de Goede
        error_set(errp, QERR_DEVICE_IN_USE, s->chr_name);
156 456d6069 Hans de Goede
        return;
157 456d6069 Hans de Goede
    }
158 456d6069 Hans de Goede
159 1da2738f Anthony Liguori
    /* FIXME we should resubmit pending requests when the CDS reconnects. */
160 1da2738f Anthony Liguori
    qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read,
161 1da2738f Anthony Liguori
                          NULL, s);
162 1da2738f Anthony Liguori
}
163 1da2738f Anthony Liguori
164 1da2738f Anthony Liguori
static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
165 1da2738f Anthony Liguori
{
166 1da2738f Anthony Liguori
    RngBackend *b = RNG_BACKEND(obj);
167 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(b);
168 1da2738f Anthony Liguori
169 1da2738f Anthony Liguori
    if (b->opened) {
170 1da2738f Anthony Liguori
        error_set(errp, QERR_PERMISSION_DENIED);
171 1da2738f Anthony Liguori
    } else {
172 1da2738f Anthony Liguori
        s->chr_name = g_strdup(value);
173 1da2738f Anthony Liguori
    }
174 1da2738f Anthony Liguori
}
175 1da2738f Anthony Liguori
176 1da2738f Anthony Liguori
static char *rng_egd_get_chardev(Object *obj, Error **errp)
177 1da2738f Anthony Liguori
{
178 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(obj);
179 1da2738f Anthony Liguori
180 1da2738f Anthony Liguori
    if (s->chr && s->chr->label) {
181 1da2738f Anthony Liguori
        return g_strdup(s->chr->label);
182 1da2738f Anthony Liguori
    }
183 1da2738f Anthony Liguori
184 1da2738f Anthony Liguori
    return NULL;
185 1da2738f Anthony Liguori
}
186 1da2738f Anthony Liguori
187 1da2738f Anthony Liguori
static void rng_egd_init(Object *obj)
188 1da2738f Anthony Liguori
{
189 1da2738f Anthony Liguori
    object_property_add_str(obj, "chardev",
190 1da2738f Anthony Liguori
                            rng_egd_get_chardev, rng_egd_set_chardev,
191 1da2738f Anthony Liguori
                            NULL);
192 1da2738f Anthony Liguori
}
193 1da2738f Anthony Liguori
194 1da2738f Anthony Liguori
static void rng_egd_finalize(Object *obj)
195 1da2738f Anthony Liguori
{
196 1da2738f Anthony Liguori
    RngEgd *s = RNG_EGD(obj);
197 1da2738f Anthony Liguori
198 1da2738f Anthony Liguori
    if (s->chr) {
199 1da2738f Anthony Liguori
        qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
200 456d6069 Hans de Goede
        qemu_chr_fe_release(s->chr);
201 1da2738f Anthony Liguori
    }
202 1da2738f Anthony Liguori
203 1da2738f Anthony Liguori
    g_free(s->chr_name);
204 1da2738f Anthony Liguori
205 9cb535fe Anthony Liguori
    rng_egd_free_requests(s);
206 1da2738f Anthony Liguori
}
207 1da2738f Anthony Liguori
208 1da2738f Anthony Liguori
static void rng_egd_class_init(ObjectClass *klass, void *data)
209 1da2738f Anthony Liguori
{
210 1da2738f Anthony Liguori
    RngBackendClass *rbc = RNG_BACKEND_CLASS(klass);
211 1da2738f Anthony Liguori
212 1da2738f Anthony Liguori
    rbc->request_entropy = rng_egd_request_entropy;
213 1da2738f Anthony Liguori
    rbc->cancel_requests = rng_egd_cancel_requests;
214 1da2738f Anthony Liguori
    rbc->opened = rng_egd_opened;
215 1da2738f Anthony Liguori
}
216 1da2738f Anthony Liguori
217 8c43a6f0 Andreas Färber
static const TypeInfo rng_egd_info = {
218 1da2738f Anthony Liguori
    .name = TYPE_RNG_EGD,
219 1da2738f Anthony Liguori
    .parent = TYPE_RNG_BACKEND,
220 1da2738f Anthony Liguori
    .instance_size = sizeof(RngEgd),
221 1da2738f Anthony Liguori
    .class_init = rng_egd_class_init,
222 1da2738f Anthony Liguori
    .instance_init = rng_egd_init,
223 1da2738f Anthony Liguori
    .instance_finalize = rng_egd_finalize,
224 1da2738f Anthony Liguori
};
225 1da2738f Anthony Liguori
226 1da2738f Anthony Liguori
static void register_types(void)
227 1da2738f Anthony Liguori
{
228 1da2738f Anthony Liguori
    type_register_static(&rng_egd_info);
229 1da2738f Anthony Liguori
}
230 1da2738f Anthony Liguori
231 1da2738f Anthony Liguori
type_init(register_types);