qemu

Форк
0
/
imx7_snvs.c 
167 строк · 4.2 Кб
1
/*
2
 * IMX7 Secure Non-Volatile Storage
3
 *
4
 * Copyright (c) 2018, Impinj, Inc.
5
 *
6
 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
7
 *
8
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9
 * See the COPYING file in the top-level directory.
10
 *
11
 * Bare minimum emulation code needed to support being able to shut
12
 * down linux guest gracefully.
13
 */
14

15
#include "qemu/osdep.h"
16
#include "qemu/bitops.h"
17
#include "qemu/timer.h"
18
#include "migration/vmstate.h"
19
#include "hw/misc/imx7_snvs.h"
20
#include "qemu/cutils.h"
21
#include "qemu/module.h"
22
#include "sysemu/sysemu.h"
23
#include "sysemu/rtc.h"
24
#include "sysemu/runstate.h"
25
#include "trace.h"
26

27
#define RTC_FREQ    32768ULL
28

29
static const VMStateDescription vmstate_imx7_snvs = {
30
    .name = TYPE_IMX7_SNVS,
31
    .version_id = 1,
32
    .minimum_version_id = 1,
33
    .fields = (const VMStateField[]) {
34
        VMSTATE_UINT64(tick_offset, IMX7SNVSState),
35
        VMSTATE_UINT64(lpcr, IMX7SNVSState),
36
        VMSTATE_END_OF_LIST()
37
    }
38
};
39

40
static uint64_t imx7_snvs_get_count(IMX7SNVSState *s)
41
{
42
    uint64_t ticks = muldiv64(qemu_clock_get_ns(rtc_clock), RTC_FREQ,
43
                              NANOSECONDS_PER_SECOND);
44
    return s->tick_offset + ticks;
45
}
46

47
static uint64_t imx7_snvs_read(void *opaque, hwaddr offset, unsigned size)
48
{
49
    IMX7SNVSState *s = IMX7_SNVS(opaque);
50
    uint64_t ret = 0;
51

52
    switch (offset) {
53
    case SNVS_LPSRTCMR:
54
        ret = extract64(imx7_snvs_get_count(s), 32, 15);
55
        break;
56
    case SNVS_LPSRTCLR:
57
        ret = extract64(imx7_snvs_get_count(s), 0, 32);
58
        break;
59
    case SNVS_LPCR:
60
        ret = s->lpcr;
61
        break;
62
    }
63

64
    trace_imx7_snvs_read(offset, ret, size);
65

66
    return ret;
67
}
68

69
static void imx7_snvs_reset(DeviceState *dev)
70
{
71
    IMX7SNVSState *s = IMX7_SNVS(dev);
72

73
    s->lpcr = 0;
74
}
75

76
static void imx7_snvs_write(void *opaque, hwaddr offset,
77
                            uint64_t v, unsigned size)
78
{
79
    trace_imx7_snvs_write(offset, v, size);
80

81
    IMX7SNVSState *s = IMX7_SNVS(opaque);
82

83
    uint64_t new_value = 0, snvs_count = 0;
84

85
    if (offset == SNVS_LPSRTCMR || offset == SNVS_LPSRTCLR) {
86
        snvs_count = imx7_snvs_get_count(s);
87
    }
88

89
    switch (offset) {
90
    case SNVS_LPSRTCMR:
91
        new_value = deposit64(snvs_count, 32, 32, v);
92
        break;
93
    case SNVS_LPSRTCLR:
94
        new_value = deposit64(snvs_count, 0, 32, v);
95
        break;
96
    case SNVS_LPCR: {
97
        s->lpcr = v;
98

99
        const uint32_t mask  = SNVS_LPCR_TOP | SNVS_LPCR_DP_EN;
100

101
        if ((v & mask) == mask) {
102
            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
103
        }
104
        break;
105
    }
106
    }
107

108
    if (offset == SNVS_LPSRTCMR || offset == SNVS_LPSRTCLR) {
109
        s->tick_offset += new_value - snvs_count;
110
    }
111
}
112

113
static const struct MemoryRegionOps imx7_snvs_ops = {
114
    .read = imx7_snvs_read,
115
    .write = imx7_snvs_write,
116
    .endianness = DEVICE_NATIVE_ENDIAN,
117
    .impl = {
118
        /*
119
         * Our device would not work correctly if the guest was doing
120
         * unaligned access. This might not be a limitation on the real
121
         * device but in practice there is no reason for a guest to access
122
         * this device unaligned.
123
         */
124
        .min_access_size = 4,
125
        .max_access_size = 4,
126
        .unaligned = false,
127
    },
128
};
129

130
static void imx7_snvs_init(Object *obj)
131
{
132
    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
133
    IMX7SNVSState *s = IMX7_SNVS(obj);
134
    struct tm tm;
135

136
    memory_region_init_io(&s->mmio, obj, &imx7_snvs_ops, s,
137
                          TYPE_IMX7_SNVS, 0x1000);
138

139
    sysbus_init_mmio(sd, &s->mmio);
140

141
    qemu_get_timedate(&tm, 0);
142
    s->tick_offset = mktimegm(&tm) -
143
        qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
144
}
145

146
static void imx7_snvs_class_init(ObjectClass *klass, void *data)
147
{
148
    DeviceClass *dc = DEVICE_CLASS(klass);
149

150
    dc->reset = imx7_snvs_reset;
151
    dc->vmsd = &vmstate_imx7_snvs;
152
    dc->desc  = "i.MX7 Secure Non-Volatile Storage Module";
153
}
154

155
static const TypeInfo imx7_snvs_info = {
156
    .name          = TYPE_IMX7_SNVS,
157
    .parent        = TYPE_SYS_BUS_DEVICE,
158
    .instance_size = sizeof(IMX7SNVSState),
159
    .instance_init = imx7_snvs_init,
160
    .class_init    = imx7_snvs_class_init,
161
};
162

163
static void imx7_snvs_register_type(void)
164
{
165
    type_register_static(&imx7_snvs_info);
166
}
167
type_init(imx7_snvs_register_type)
168

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

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

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

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