aboutsummaryrefslogtreecommitdiff
path: root/include/hw/virtio/virtio-access.h
blob: 2e92074bd1c2975d96eff4169ca82160221953c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*
 * Virtio Accessor Support: In case your target can change endian.
 *
 * Copyright IBM, Corp. 2013
 *
 * Authors:
 *  Rusty Russell   <rusty@au.ibm.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 */

#ifndef QEMU_VIRTIO_ACCESS_H
#define QEMU_VIRTIO_ACCESS_H

#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-bus.h"
#include "exec/address-spaces.h"

#if defined(TARGET_PPC64) || defined(TARGET_ARM)
#define LEGACY_VIRTIO_IS_BIENDIAN 1
#endif

static inline bool virtio_access_is_big_endian(VirtIODevice *vdev)
{
#if defined(LEGACY_VIRTIO_IS_BIENDIAN)
    return virtio_is_big_endian(vdev);
#elif defined(TARGET_WORDS_BIGENDIAN)
    if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
        /* Devices conforming to VIRTIO 1.0 or later are always LE. */
        return false;
    }
    return true;
#else
    return false;
#endif
}

static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa)
{
    AddressSpace *dma_as = vdev->dma_as;

    if (virtio_access_is_big_endian(vdev)) {
        return lduw_be_phys(dma_as, pa);
    }
    return lduw_le_phys(dma_as, pa);
}

static inline uint32_t virtio_ldl_phys(VirtIODevice *vdev, hwaddr pa)
{
    AddressSpace *dma_as = vdev->dma_as;

    if (virtio_access_is_big_endian(vdev)) {
        return ldl_be_phys(dma_as, pa);
    }
    return ldl_le_phys(dma_as, pa);
}

static inline uint64_t virtio_ldq_phys(VirtIODevice *vdev, hwaddr pa)
{
    AddressSpace *dma_as = vdev->dma_as;

    if (virtio_access_is_big_endian(vdev)) {
        return ldq_be_phys(dma_as, pa);
    }
    return ldq_le_phys(dma_as, pa);
}

static inline void virtio_stw_phys(VirtIODevice *vdev, hwaddr pa,
                                   uint16_t value)
{
    AddressSpace *dma_as = vdev->dma_as;

    if (virtio_access_is_big_endian(vdev)) {
        stw_be_phys(dma_as, pa, value);
    } else {
        stw_le_phys(dma_as, pa, value);
    }
}

static inline void virtio_stl_phys(VirtIODevice *vdev, hwaddr pa,
                                   uint32_t value)
{
    AddressSpace *dma_as = vdev->dma_as;

    if (virtio_access_is_big_endian(vdev)) {
        stl_be_phys(dma_as, pa, value);
    } else {
        stl_le_phys(dma_as, pa, value);
    }
}

static inline void virtio_stw_p(VirtIODevice *vdev, void *ptr, uint16_t v)
{
    if (virtio_access_is_big_endian(vdev)) {
        stw_be_p(ptr, v);
    } else {
        stw_le_p(ptr, v);
    }
}

static inline void virtio_stl_p(VirtIODevice *vdev, void *ptr, uint32_t v)
{
    if (virtio_access_is_big_endian(vdev)) {
        stl_be_p(ptr, v);
    } else {
        stl_le_p(ptr, v);
    }
}

static inline void virtio_stq_p(VirtIODevice *vdev, void *ptr, uint64_t v)
{
    if (virtio_access_is_big_endian(vdev)) {
        stq_be_p(ptr, v);
    } else {
        stq_le_p(ptr, v);
    }
}

static inline int virtio_lduw_p(VirtIODevice *vdev, const void *ptr)
{
    if (virtio_access_is_big_endian(vdev)) {
        return lduw_be_p(ptr);
    } else {
        return lduw_le_p(ptr);
    }
}

static inline int virtio_ldl_p(VirtIODevice *vdev, const void *ptr)
{
    if (virtio_access_is_big_endian(vdev)) {
        return ldl_be_p(ptr);
    } else {
        return ldl_le_p(ptr);
    }
}

static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
{
    if (virtio_access_is_big_endian(vdev)) {
        return ldq_be_p(ptr);
    } else {
        return ldq_le_p(ptr);
    }
}

static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
{
#ifdef HOST_WORDS_BIGENDIAN
    return virtio_access_is_big_endian(vdev) ? s : bswap16(s);
#else
    return virtio_access_is_big_endian(vdev) ? bswap16(s) : s;
#endif
}

static inline uint16_t virtio_lduw_phys_cached(VirtIODevice *vdev,
                                               MemoryRegionCache *cache,
                                               hwaddr pa)
{
    if (virtio_access_is_big_endian(vdev)) {
        return lduw_be_phys_cached(cache, pa);
    }
    return lduw_le_phys_cached(cache, pa);
}

static inline uint32_t virtio_ldl_phys_cached(VirtIODevice *vdev,
                                              MemoryRegionCache *cache,
                                              hwaddr pa)
{
    if (virtio_access_is_big_endian(vdev)) {
        return ldl_be_phys_cached(cache, pa);
    }
    return ldl_le_phys_cached(cache, pa);
}

static inline uint64_t virtio_ldq_phys_cached(VirtIODevice *vdev,
                                              MemoryRegionCache *cache,
                                              hwaddr pa)
{
    if (virtio_access_is_big_endian(vdev)) {
        return ldq_be_phys_cached(cache, pa);
    }
    return ldq_le_phys_cached(cache, pa);
}

static inline void virtio_stw_phys_cached(VirtIODevice *vdev,
                                          MemoryRegionCache *cache,
                                          hwaddr pa, uint16_t value)
{
    if (virtio_access_is_big_endian(vdev)) {
        stw_be_phys_cached(cache, pa, value);
    } else {
        stw_le_phys_cached(cache, pa, value);
    }
}

static inline void virtio_stl_phys_cached(VirtIODevice *vdev,
                                          MemoryRegionCache *cache,
                                          hwaddr pa, uint32_t value)
{
    if (virtio_access_is_big_endian(vdev)) {
        stl_be_phys_cached(cache, pa, value);
    } else {
        stl_le_phys_cached(cache, pa, value);
    }
}

static inline void virtio_tswap16s(VirtIODevice *vdev, uint16_t *s)
{
    *s = virtio_tswap16(vdev, *s);
}

static inline uint32_t virtio_tswap32(VirtIODevice *vdev, uint32_t s)
{
#ifdef HOST_WORDS_BIGENDIAN
    return virtio_access_is_big_endian(vdev) ? s : bswap32(s);
#else
    return virtio_access_is_big_endian(vdev) ? bswap32(s) : s;
#endif
}

static inline void virtio_tswap32s(VirtIODevice *vdev, uint32_t *s)
{
    *s = virtio_tswap32(vdev, *s);
}

static inline uint64_t virtio_tswap64(VirtIODevice *vdev, uint64_t s)
{
#ifdef HOST_WORDS_BIGENDIAN
    return virtio_access_is_big_endian(vdev) ? s : bswap64(s);
#else
    return virtio_access_is_big_endian(vdev) ? bswap64(s) : s;
#endif
}

static inline void virtio_tswap64s(VirtIODevice *vdev, uint64_t *s)
{
    *s = virtio_tswap64(vdev, *s);
}
#endif /* QEMU_VIRTIO_ACCESS_H */