| 1 | /* |
| 2 | * Virtio features helpers |
| 3 | * |
| 4 | * Copyright 2025 Red Hat, Inc. |
| 5 | * |
| 6 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 7 | */ |
| 8 | |
| 9 | #ifndef QEMU_VIRTIO_FEATURES_H |
| 10 | #define QEMU_VIRTIO_FEATURES_H |
| 11 | |
| 12 | #include "qemu/bitops.h" |
| 13 | |
| 14 | #define VIRTIO_FEATURES_FMT "%016"PRIx64"%016"PRIx64 |
| 15 | #define VIRTIO_FEATURES_PR(f) (f)[1], (f)[0] |
| 16 | |
| 17 | #define VIRTIO_FEATURES_MAX 128 |
| 18 | #define VIRTIO_FEATURES_BIT(b) BIT_ULL((b) % 64) |
| 19 | #define VIRTIO_FEATURES_U64(b) ((b) / 64) |
| 20 | #define VIRTIO_FEATURES_NU32S (VIRTIO_FEATURES_MAX / 32) |
| 21 | #define VIRTIO_FEATURES_NU64S (VIRTIO_FEATURES_MAX / 64) |
| 22 | |
| 23 | #define VIRTIO_DECLARE_FEATURES(name) \ |
| 24 | union { \ |
| 25 | uint64_t name; \ |
| 26 | uint64_t name##_ex[VIRTIO_FEATURES_NU64S]; \ |
| 27 | } |
| 28 | |
| 29 | #define VIRTIO_DEFINE_PROP_FEATURE(_name, _state, _field, _bit, _defval) \ |
| 30 | DEFINE_PROP_BIT64(_name, _state, _field[VIRTIO_FEATURES_U64(_bit)], \ |
| 31 | (_bit) % 64, _defval) |
| 32 | |
| 33 | static inline void virtio_features_clear(uint64_t *features) |
| 34 | { |
| 35 | memset(features, 0, sizeof(features[0]) * VIRTIO_FEATURES_NU64S); |
| 36 | } |
| 37 | |
| 38 | static inline void virtio_features_from_u64(uint64_t *features, uint64_t from) |
| 39 | { |
| 40 | virtio_features_clear(features); |
| 41 | features[0] = from; |
| 42 | } |
| 43 | |
| 44 | static inline bool virtio_has_feature_ex(const uint64_t *features, |
| 45 | unsigned int fbit) |
| 46 | { |
| 47 | assert(fbit < VIRTIO_FEATURES_MAX); |
| 48 | return features[VIRTIO_FEATURES_U64(fbit)] & VIRTIO_FEATURES_BIT(fbit); |
| 49 | } |
| 50 | |
| 51 | static inline void virtio_add_feature_ex(uint64_t *features, |
| 52 | unsigned int fbit) |
| 53 | { |
| 54 | assert(fbit < VIRTIO_FEATURES_MAX); |
| 55 | features[VIRTIO_FEATURES_U64(fbit)] |= VIRTIO_FEATURES_BIT(fbit); |
| 56 | } |
| 57 | |
| 58 | static inline void virtio_clear_feature_ex(uint64_t *features, |
| 59 | unsigned int fbit) |
| 60 | { |
| 61 | assert(fbit < VIRTIO_FEATURES_MAX); |
| 62 | features[VIRTIO_FEATURES_U64(fbit)] &= ~VIRTIO_FEATURES_BIT(fbit); |
| 63 | } |
| 64 | |
| 65 | static inline bool virtio_features_equal(const uint64_t *f1, |
| 66 | const uint64_t *f2) |
| 67 | { |
| 68 | return !memcmp(f1, f2, sizeof(uint64_t) * VIRTIO_FEATURES_NU64S); |
| 69 | } |
| 70 | |
| 71 | static inline bool virtio_features_use_ex(const uint64_t *features) |
| 72 | { |
| 73 | int i; |
| 74 | |
| 75 | for (i = 1; i < VIRTIO_FEATURES_NU64S; ++i) { |
| 76 | if (features[i]) { |
| 77 | return true; |
| 78 | } |
| 79 | } |
| 80 | return false; |
| 81 | } |
| 82 | |
| 83 | static inline bool virtio_features_empty(const uint64_t *features) |
| 84 | { |
| 85 | return !virtio_features_use_ex(features) && !features[0]; |
| 86 | } |
| 87 | |
| 88 | static inline void virtio_features_copy(uint64_t *to, const uint64_t *from) |
| 89 | { |
| 90 | memcpy(to, from, sizeof(to[0]) * VIRTIO_FEATURES_NU64S); |
| 91 | } |
| 92 | |
| 93 | static inline bool virtio_features_andnot(uint64_t *to, const uint64_t *f1, |
| 94 | const uint64_t *f2) |
| 95 | { |
| 96 | uint64_t diff = 0; |
| 97 | int i; |
| 98 | |
| 99 | for (i = 0; i < VIRTIO_FEATURES_NU64S; i++) { |
| 100 | to[i] = f1[i] & ~f2[i]; |
| 101 | diff |= to[i]; |
| 102 | } |
| 103 | return diff; |
| 104 | } |
| 105 | |
| 106 | static inline void virtio_features_and(uint64_t *to, const uint64_t *f1, |
| 107 | const uint64_t *f2) |
| 108 | { |
| 109 | int i; |
| 110 | |
| 111 | for (i = 0; i < VIRTIO_FEATURES_NU64S; i++) { |
| 112 | to[i] = f1[i] & f2[i]; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | static inline void virtio_features_or(uint64_t *to, const uint64_t *f1, |
| 117 | const uint64_t *f2) |
| 118 | { |
| 119 | int i; |
| 120 | |
| 121 | for (i = 0; i < VIRTIO_FEATURES_NU64S; i++) { |
| 122 | to[i] = f1[i] | f2[i]; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | #endif |