qemu

Форк
0
/
nrf51_rng.c 
266 строк · 6.5 Кб
1
/*
2
 * nRF51 Random Number Generator
3
 *
4
 * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf
5
 *
6
 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
7
 *
8
 * This code is licensed under the GPL version 2 or later.  See
9
 * the COPYING file in the top-level directory.
10
 */
11

12
#include "qemu/osdep.h"
13
#include "qemu/log.h"
14
#include "qemu/module.h"
15
#include "qapi/error.h"
16
#include "hw/arm/nrf51.h"
17
#include "hw/irq.h"
18
#include "hw/misc/nrf51_rng.h"
19
#include "hw/qdev-properties.h"
20
#include "migration/vmstate.h"
21
#include "qemu/guest-random.h"
22

23
static void update_irq(NRF51RNGState *s)
24
{
25
    bool irq = s->interrupt_enabled && s->event_valrdy;
26
    qemu_set_irq(s->irq, irq);
27
}
28

29
static uint64_t rng_read(void *opaque, hwaddr offset, unsigned int size)
30
{
31
    NRF51RNGState *s = NRF51_RNG(opaque);
32
    uint64_t r = 0;
33

34
    switch (offset) {
35
    case NRF51_RNG_EVENT_VALRDY:
36
        r = s->event_valrdy;
37
        break;
38
    case NRF51_RNG_REG_SHORTS:
39
        r = s->shortcut_stop_on_valrdy;
40
        break;
41
    case NRF51_RNG_REG_INTEN:
42
    case NRF51_RNG_REG_INTENSET:
43
    case NRF51_RNG_REG_INTENCLR:
44
        r = s->interrupt_enabled;
45
        break;
46
    case NRF51_RNG_REG_CONFIG:
47
        r = s->filter_enabled;
48
        break;
49
    case NRF51_RNG_REG_VALUE:
50
        r = s->value;
51
        break;
52

53
    default:
54
        qemu_log_mask(LOG_GUEST_ERROR,
55
                      "%s: bad read offset 0x%" HWADDR_PRIx "\n",
56
                      __func__, offset);
57
    }
58

59
    return r;
60
}
61

62
static int64_t calc_next_timeout(NRF51RNGState *s)
63
{
64
    int64_t timeout = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
65
    if (s->filter_enabled) {
66
        timeout += s->period_filtered_us;
67
    } else {
68
        timeout += s->period_unfiltered_us;
69
    }
70

71
    return timeout;
72
}
73

74

75
static void rng_update_timer(NRF51RNGState *s)
76
{
77
    if (s->active) {
78
        timer_mod(&s->timer, calc_next_timeout(s));
79
    } else {
80
        timer_del(&s->timer);
81
    }
82
}
83

84

85
static void rng_write(void *opaque, hwaddr offset,
86
                       uint64_t value, unsigned int size)
87
{
88
    NRF51RNGState *s = NRF51_RNG(opaque);
89

90
    switch (offset) {
91
    case NRF51_RNG_TASK_START:
92
        if (value == NRF51_TRIGGER_TASK) {
93
            s->active = 1;
94
            rng_update_timer(s);
95
        }
96
        break;
97
    case NRF51_RNG_TASK_STOP:
98
        if (value == NRF51_TRIGGER_TASK) {
99
            s->active = 0;
100
            rng_update_timer(s);
101
        }
102
        break;
103
    case NRF51_RNG_EVENT_VALRDY:
104
        if (value == NRF51_EVENT_CLEAR) {
105
            s->event_valrdy = 0;
106
        }
107
        break;
108
    case NRF51_RNG_REG_SHORTS:
109
        s->shortcut_stop_on_valrdy =
110
                (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
111
        break;
112
    case NRF51_RNG_REG_INTEN:
113
        s->interrupt_enabled =
114
                (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
115
        break;
116
    case NRF51_RNG_REG_INTENSET:
117
        if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
118
            s->interrupt_enabled = 1;
119
        }
120
        break;
121
    case NRF51_RNG_REG_INTENCLR:
122
        if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
123
            s->interrupt_enabled = 0;
124
        }
125
        break;
126
    case NRF51_RNG_REG_CONFIG:
127
        s->filter_enabled =
128
                      (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
129
        break;
130

131
    default:
132
        qemu_log_mask(LOG_GUEST_ERROR,
133
                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
134
                      __func__, offset);
135
    }
136

137
    update_irq(s);
138
}
139

140
static const MemoryRegionOps rng_ops = {
141
    .read =  rng_read,
142
    .write = rng_write,
143
    .endianness = DEVICE_LITTLE_ENDIAN,
144
    .impl.min_access_size = 4,
145
    .impl.max_access_size = 4
146
};
147

148
static void nrf51_rng_timer_expire(void *opaque)
149
{
150
    NRF51RNGState *s = NRF51_RNG(opaque);
151

152
    qemu_guest_getrandom_nofail(&s->value, 1);
153

154
    s->event_valrdy = 1;
155
    qemu_set_irq(s->eep_valrdy, 1);
156

157
    if (s->shortcut_stop_on_valrdy) {
158
        s->active = 0;
159
    }
160

161
    rng_update_timer(s);
162
    update_irq(s);
163
}
164

165
static void nrf51_rng_tep_start(void *opaque, int n, int level)
166
{
167
    NRF51RNGState *s = NRF51_RNG(opaque);
168

169
    if (level) {
170
        s->active = 1;
171
        rng_update_timer(s);
172
    }
173
}
174

175
static void nrf51_rng_tep_stop(void *opaque, int n, int level)
176
{
177
    NRF51RNGState *s = NRF51_RNG(opaque);
178

179
    if (level) {
180
        s->active = 0;
181
        rng_update_timer(s);
182
    }
183
}
184

185

186
static void nrf51_rng_init(Object *obj)
187
{
188
    NRF51RNGState *s = NRF51_RNG(obj);
189
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
190

191
    memory_region_init_io(&s->mmio, obj, &rng_ops, s,
192
            TYPE_NRF51_RNG, NRF51_RNG_SIZE);
193
    sysbus_init_mmio(sbd, &s->mmio);
194

195
    timer_init_us(&s->timer, QEMU_CLOCK_VIRTUAL, nrf51_rng_timer_expire, s);
196

197
    sysbus_init_irq(sbd, &s->irq);
198

199
    /* Tasks */
200
    qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_start, "tep_start", 1);
201
    qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_stop, "tep_stop", 1);
202

203
    /* Events */
204
    qdev_init_gpio_out_named(DEVICE(s), &s->eep_valrdy, "eep_valrdy", 1);
205
}
206

207
static void nrf51_rng_reset(DeviceState *dev)
208
{
209
    NRF51RNGState *s = NRF51_RNG(dev);
210

211
    s->value = 0;
212
    s->active = 0;
213
    s->event_valrdy = 0;
214
    s->shortcut_stop_on_valrdy = 0;
215
    s->interrupt_enabled = 0;
216
    s->filter_enabled = 0;
217

218
    rng_update_timer(s);
219
}
220

221

222
static Property nrf51_rng_properties[] = {
223
    DEFINE_PROP_UINT16("period_unfiltered_us", NRF51RNGState,
224
            period_unfiltered_us, 167),
225
    DEFINE_PROP_UINT16("period_filtered_us", NRF51RNGState,
226
            period_filtered_us, 660),
227
    DEFINE_PROP_END_OF_LIST(),
228
};
229

230
static const VMStateDescription vmstate_rng = {
231
    .name = "nrf51_soc.rng",
232
    .version_id = 1,
233
    .minimum_version_id = 1,
234
    .fields = (const VMStateField[]) {
235
        VMSTATE_UINT32(active, NRF51RNGState),
236
        VMSTATE_UINT32(event_valrdy, NRF51RNGState),
237
        VMSTATE_UINT32(shortcut_stop_on_valrdy, NRF51RNGState),
238
        VMSTATE_UINT32(interrupt_enabled, NRF51RNGState),
239
        VMSTATE_UINT32(filter_enabled, NRF51RNGState),
240
        VMSTATE_END_OF_LIST()
241
    }
242
};
243

244
static void nrf51_rng_class_init(ObjectClass *klass, void *data)
245
{
246
    DeviceClass *dc = DEVICE_CLASS(klass);
247

248
    device_class_set_props(dc, nrf51_rng_properties);
249
    dc->vmsd = &vmstate_rng;
250
    dc->reset = nrf51_rng_reset;
251
}
252

253
static const TypeInfo nrf51_rng_info = {
254
    .name = TYPE_NRF51_RNG,
255
    .parent = TYPE_SYS_BUS_DEVICE,
256
    .instance_size = sizeof(NRF51RNGState),
257
    .instance_init = nrf51_rng_init,
258
    .class_init = nrf51_rng_class_init
259
};
260

261
static void nrf51_rng_register_types(void)
262
{
263
    type_register_static(&nrf51_rng_info);
264
}
265

266
type_init(nrf51_rng_register_types)
267

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.