xref: /qemu/hw/ppc/spapr_ovec.c (revision fe93e3e6ec1b1bf4a4c9d4bf55f8776318da6847)
1b20b7b7aSMichael Roth /*
2b20b7b7aSMichael Roth  * QEMU SPAPR Architecture Option Vector Helper Functions
3b20b7b7aSMichael Roth  *
4b20b7b7aSMichael Roth  * Copyright IBM Corp. 2016
5b20b7b7aSMichael Roth  *
6b20b7b7aSMichael Roth  * Authors:
7b20b7b7aSMichael Roth  *  Bharata B Rao     <bharata@linux.vnet.ibm.com>
8b20b7b7aSMichael Roth  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
9b20b7b7aSMichael Roth  *
10b20b7b7aSMichael Roth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11b20b7b7aSMichael Roth  * See the COPYING file in the top-level directory.
12b20b7b7aSMichael Roth  */
13b20b7b7aSMichael Roth 
14b20b7b7aSMichael Roth #include "qemu/osdep.h"
15b20b7b7aSMichael Roth #include "hw/ppc/spapr_ovec.h"
16b20b7b7aSMichael Roth #include "qemu/bitmap.h"
17b20b7b7aSMichael Roth #include "exec/address-spaces.h"
18b20b7b7aSMichael Roth #include "qemu/error-report.h"
19b20b7b7aSMichael Roth #include <libfdt.h>
20b20b7b7aSMichael Roth 
21b20b7b7aSMichael Roth /* #define DEBUG_SPAPR_OVEC */
22b20b7b7aSMichael Roth 
23b20b7b7aSMichael Roth #ifdef DEBUG_SPAPR_OVEC
24b20b7b7aSMichael Roth #define DPRINTFN(fmt, ...) \
25b20b7b7aSMichael Roth     do { fprintf(stderr, fmt "\n", ## __VA_ARGS__); } while (0)
26b20b7b7aSMichael Roth #else
27b20b7b7aSMichael Roth #define DPRINTFN(fmt, ...) \
28b20b7b7aSMichael Roth     do { } while (0)
29b20b7b7aSMichael Roth #endif
30b20b7b7aSMichael Roth 
31b20b7b7aSMichael Roth #define OV_MAXBYTES 256 /* not including length byte */
32b20b7b7aSMichael Roth #define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE)
33b20b7b7aSMichael Roth 
34b20b7b7aSMichael Roth /* we *could* work with bitmaps directly, but handling the bitmap privately
35b20b7b7aSMichael Roth  * allows us to more safely make assumptions about the bitmap size and
36b20b7b7aSMichael Roth  * simplify the calling code somewhat
37b20b7b7aSMichael Roth  */
38b20b7b7aSMichael Roth struct sPAPROptionVector {
39b20b7b7aSMichael Roth     unsigned long *bitmap;
4062ef3760SMichael Roth     int32_t bitmap_size; /* only used for migration */
4162ef3760SMichael Roth };
4262ef3760SMichael Roth 
4362ef3760SMichael Roth const VMStateDescription vmstate_spapr_ovec = {
4462ef3760SMichael Roth     .name = "spapr_option_vector",
4562ef3760SMichael Roth     .version_id = 1,
4662ef3760SMichael Roth     .minimum_version_id = 1,
4762ef3760SMichael Roth     .fields = (VMStateField[]) {
4862ef3760SMichael Roth         VMSTATE_BITMAP(bitmap, sPAPROptionVector, 1, bitmap_size),
4962ef3760SMichael Roth         VMSTATE_END_OF_LIST()
5062ef3760SMichael Roth     }
51b20b7b7aSMichael Roth };
52b20b7b7aSMichael Roth 
53b20b7b7aSMichael Roth sPAPROptionVector *spapr_ovec_new(void)
54b20b7b7aSMichael Roth {
55b20b7b7aSMichael Roth     sPAPROptionVector *ov;
56b20b7b7aSMichael Roth 
57b20b7b7aSMichael Roth     ov = g_new0(sPAPROptionVector, 1);
58b20b7b7aSMichael Roth     ov->bitmap = bitmap_new(OV_MAXBITS);
5962ef3760SMichael Roth     ov->bitmap_size = OV_MAXBITS;
60b20b7b7aSMichael Roth 
61b20b7b7aSMichael Roth     return ov;
62b20b7b7aSMichael Roth }
63b20b7b7aSMichael Roth 
64b20b7b7aSMichael Roth sPAPROptionVector *spapr_ovec_clone(sPAPROptionVector *ov_orig)
65b20b7b7aSMichael Roth {
66b20b7b7aSMichael Roth     sPAPROptionVector *ov;
67b20b7b7aSMichael Roth 
68b20b7b7aSMichael Roth     g_assert(ov_orig);
69b20b7b7aSMichael Roth 
70b20b7b7aSMichael Roth     ov = spapr_ovec_new();
71b20b7b7aSMichael Roth     bitmap_copy(ov->bitmap, ov_orig->bitmap, OV_MAXBITS);
72b20b7b7aSMichael Roth 
73b20b7b7aSMichael Roth     return ov;
74b20b7b7aSMichael Roth }
75b20b7b7aSMichael Roth 
76b20b7b7aSMichael Roth void spapr_ovec_intersect(sPAPROptionVector *ov,
77b20b7b7aSMichael Roth                           sPAPROptionVector *ov1,
78b20b7b7aSMichael Roth                           sPAPROptionVector *ov2)
79b20b7b7aSMichael Roth {
80b20b7b7aSMichael Roth     g_assert(ov);
81b20b7b7aSMichael Roth     g_assert(ov1);
82b20b7b7aSMichael Roth     g_assert(ov2);
83b20b7b7aSMichael Roth 
84b20b7b7aSMichael Roth     bitmap_and(ov->bitmap, ov1->bitmap, ov2->bitmap, OV_MAXBITS);
85b20b7b7aSMichael Roth }
86b20b7b7aSMichael Roth 
87b20b7b7aSMichael Roth /* returns true if options bits were removed, false otherwise */
88b20b7b7aSMichael Roth bool spapr_ovec_diff(sPAPROptionVector *ov,
89b20b7b7aSMichael Roth                      sPAPROptionVector *ov_old,
90b20b7b7aSMichael Roth                      sPAPROptionVector *ov_new)
91b20b7b7aSMichael Roth {
92b20b7b7aSMichael Roth     unsigned long *change_mask = bitmap_new(OV_MAXBITS);
93b20b7b7aSMichael Roth     unsigned long *removed_bits = bitmap_new(OV_MAXBITS);
94b20b7b7aSMichael Roth     bool bits_were_removed = false;
95b20b7b7aSMichael Roth 
96b20b7b7aSMichael Roth     g_assert(ov);
97b20b7b7aSMichael Roth     g_assert(ov_old);
98b20b7b7aSMichael Roth     g_assert(ov_new);
99b20b7b7aSMichael Roth 
100b20b7b7aSMichael Roth     bitmap_xor(change_mask, ov_old->bitmap, ov_new->bitmap, OV_MAXBITS);
101b20b7b7aSMichael Roth     bitmap_and(ov->bitmap, ov_new->bitmap, change_mask, OV_MAXBITS);
102b20b7b7aSMichael Roth     bitmap_and(removed_bits, ov_old->bitmap, change_mask, OV_MAXBITS);
103b20b7b7aSMichael Roth 
104b20b7b7aSMichael Roth     if (!bitmap_empty(removed_bits, OV_MAXBITS)) {
105b20b7b7aSMichael Roth         bits_were_removed = true;
106b20b7b7aSMichael Roth     }
107b20b7b7aSMichael Roth 
108b20b7b7aSMichael Roth     g_free(change_mask);
109b20b7b7aSMichael Roth     g_free(removed_bits);
110b20b7b7aSMichael Roth 
111b20b7b7aSMichael Roth     return bits_were_removed;
112b20b7b7aSMichael Roth }
113b20b7b7aSMichael Roth 
114b20b7b7aSMichael Roth void spapr_ovec_cleanup(sPAPROptionVector *ov)
115b20b7b7aSMichael Roth {
116b20b7b7aSMichael Roth     if (ov) {
117b20b7b7aSMichael Roth         g_free(ov->bitmap);
118b20b7b7aSMichael Roth         g_free(ov);
119b20b7b7aSMichael Roth     }
120b20b7b7aSMichael Roth }
121b20b7b7aSMichael Roth 
122b20b7b7aSMichael Roth void spapr_ovec_set(sPAPROptionVector *ov, long bitnr)
123b20b7b7aSMichael Roth {
124b20b7b7aSMichael Roth     g_assert(ov);
125b20b7b7aSMichael Roth     g_assert_cmpint(bitnr, <, OV_MAXBITS);
126b20b7b7aSMichael Roth 
127b20b7b7aSMichael Roth     set_bit(bitnr, ov->bitmap);
128b20b7b7aSMichael Roth }
129b20b7b7aSMichael Roth 
130b20b7b7aSMichael Roth void spapr_ovec_clear(sPAPROptionVector *ov, long bitnr)
131b20b7b7aSMichael Roth {
132b20b7b7aSMichael Roth     g_assert(ov);
133b20b7b7aSMichael Roth     g_assert_cmpint(bitnr, <, OV_MAXBITS);
134b20b7b7aSMichael Roth 
135b20b7b7aSMichael Roth     clear_bit(bitnr, ov->bitmap);
136b20b7b7aSMichael Roth }
137b20b7b7aSMichael Roth 
138b20b7b7aSMichael Roth bool spapr_ovec_test(sPAPROptionVector *ov, long bitnr)
139b20b7b7aSMichael Roth {
140b20b7b7aSMichael Roth     g_assert(ov);
141b20b7b7aSMichael Roth     g_assert_cmpint(bitnr, <, OV_MAXBITS);
142b20b7b7aSMichael Roth 
143b20b7b7aSMichael Roth     return test_bit(bitnr, ov->bitmap) ? true : false;
144b20b7b7aSMichael Roth }
145b20b7b7aSMichael Roth 
146b20b7b7aSMichael Roth static void guest_byte_to_bitmap(uint8_t entry, unsigned long *bitmap,
147b20b7b7aSMichael Roth                                  long bitmap_offset)
148b20b7b7aSMichael Roth {
149b20b7b7aSMichael Roth     int i;
150b20b7b7aSMichael Roth 
151b20b7b7aSMichael Roth     for (i = 0; i < BITS_PER_BYTE; i++) {
152b20b7b7aSMichael Roth         if (entry & (1 << (BITS_PER_BYTE - 1 - i))) {
153b20b7b7aSMichael Roth             bitmap_set(bitmap, bitmap_offset + i, 1);
154b20b7b7aSMichael Roth         }
155b20b7b7aSMichael Roth     }
156b20b7b7aSMichael Roth }
157b20b7b7aSMichael Roth 
158b20b7b7aSMichael Roth static uint8_t guest_byte_from_bitmap(unsigned long *bitmap, long bitmap_offset)
159b20b7b7aSMichael Roth {
160b20b7b7aSMichael Roth     uint8_t entry = 0;
161b20b7b7aSMichael Roth     int i;
162b20b7b7aSMichael Roth 
163b20b7b7aSMichael Roth     for (i = 0; i < BITS_PER_BYTE; i++) {
164b20b7b7aSMichael Roth         if (test_bit(bitmap_offset + i, bitmap)) {
165b20b7b7aSMichael Roth             entry |= (1 << (BITS_PER_BYTE - 1 - i));
166b20b7b7aSMichael Roth         }
167b20b7b7aSMichael Roth     }
168b20b7b7aSMichael Roth 
169b20b7b7aSMichael Roth     return entry;
170b20b7b7aSMichael Roth }
171b20b7b7aSMichael Roth 
172b20b7b7aSMichael Roth static target_ulong vector_addr(target_ulong table_addr, int vector)
173b20b7b7aSMichael Roth {
174b20b7b7aSMichael Roth     uint16_t vector_count, vector_len;
175b20b7b7aSMichael Roth     int i;
176b20b7b7aSMichael Roth 
177b20b7b7aSMichael Roth     vector_count = ldub_phys(&address_space_memory, table_addr) + 1;
178b20b7b7aSMichael Roth     if (vector > vector_count) {
179b20b7b7aSMichael Roth         return 0;
180b20b7b7aSMichael Roth     }
181b20b7b7aSMichael Roth     table_addr++; /* skip nr option vectors */
182b20b7b7aSMichael Roth 
183b20b7b7aSMichael Roth     for (i = 0; i < vector - 1; i++) {
184b20b7b7aSMichael Roth         vector_len = ldub_phys(&address_space_memory, table_addr) + 1;
185b20b7b7aSMichael Roth         table_addr += vector_len + 1; /* bit-vector + length byte */
186b20b7b7aSMichael Roth     }
187b20b7b7aSMichael Roth     return table_addr;
188b20b7b7aSMichael Roth }
189b20b7b7aSMichael Roth 
190b20b7b7aSMichael Roth sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector)
191b20b7b7aSMichael Roth {
192b20b7b7aSMichael Roth     sPAPROptionVector *ov;
193b20b7b7aSMichael Roth     target_ulong addr;
194b20b7b7aSMichael Roth     uint16_t vector_len;
195b20b7b7aSMichael Roth     int i;
196b20b7b7aSMichael Roth 
197b20b7b7aSMichael Roth     g_assert(table_addr);
198b20b7b7aSMichael Roth     g_assert_cmpint(vector, >=, 1); /* vector numbering starts at 1 */
199b20b7b7aSMichael Roth 
200b20b7b7aSMichael Roth     addr = vector_addr(table_addr, vector);
201b20b7b7aSMichael Roth     if (!addr) {
202b20b7b7aSMichael Roth         /* specified vector isn't present */
203b20b7b7aSMichael Roth         return NULL;
204b20b7b7aSMichael Roth     }
205b20b7b7aSMichael Roth 
206b20b7b7aSMichael Roth     vector_len = ldub_phys(&address_space_memory, addr++) + 1;
207b20b7b7aSMichael Roth     g_assert_cmpint(vector_len, <=, OV_MAXBYTES);
208b20b7b7aSMichael Roth     ov = spapr_ovec_new();
209b20b7b7aSMichael Roth 
210b20b7b7aSMichael Roth     for (i = 0; i < vector_len; i++) {
211b20b7b7aSMichael Roth         uint8_t entry = ldub_phys(&address_space_memory, addr + i);
212b20b7b7aSMichael Roth         if (entry) {
213b20b7b7aSMichael Roth             DPRINTFN("read guest vector %2d, byte %3d / %3d: 0x%.2x",
214b20b7b7aSMichael Roth                      vector, i + 1, vector_len, entry);
215b20b7b7aSMichael Roth             guest_byte_to_bitmap(entry, ov->bitmap, i * BITS_PER_BYTE);
216b20b7b7aSMichael Roth         }
217b20b7b7aSMichael Roth     }
218b20b7b7aSMichael Roth 
219b20b7b7aSMichael Roth     return ov;
220b20b7b7aSMichael Roth }
221b20b7b7aSMichael Roth 
222b20b7b7aSMichael Roth int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
223b20b7b7aSMichael Roth                            sPAPROptionVector *ov, const char *name)
224b20b7b7aSMichael Roth {
225b20b7b7aSMichael Roth     uint8_t vec[OV_MAXBYTES + 1];
226b20b7b7aSMichael Roth     uint16_t vec_len;
227b20b7b7aSMichael Roth     unsigned long lastbit;
228b20b7b7aSMichael Roth     int i;
229b20b7b7aSMichael Roth 
230b20b7b7aSMichael Roth     g_assert(ov);
231b20b7b7aSMichael Roth 
232b20b7b7aSMichael Roth     lastbit = find_last_bit(ov->bitmap, OV_MAXBITS);
233b20b7b7aSMichael Roth     /* if no bits are set, include at least 1 byte of the vector so we can
234b20b7b7aSMichael Roth      * still encoded this in the device tree while abiding by the same
235b20b7b7aSMichael Roth      * encoding/sizing expected in ibm,client-architecture-support
236b20b7b7aSMichael Roth      */
237b20b7b7aSMichael Roth     vec_len = (lastbit == OV_MAXBITS) ? 1 : lastbit / BITS_PER_BYTE + 1;
238b20b7b7aSMichael Roth     g_assert_cmpint(vec_len, <=, OV_MAXBYTES);
239b20b7b7aSMichael Roth     /* guest expects vector len encoded as vec_len - 1, since the length byte
240b20b7b7aSMichael Roth      * is assumed and not included, and the first byte of the vector
241b20b7b7aSMichael Roth      * is assumed as well
242b20b7b7aSMichael Roth      */
243b20b7b7aSMichael Roth     vec[0] = vec_len - 1;
244b20b7b7aSMichael Roth 
245b20b7b7aSMichael Roth     for (i = 1; i < vec_len + 1; i++) {
246b20b7b7aSMichael Roth         vec[i] = guest_byte_from_bitmap(ov->bitmap, (i - 1) * BITS_PER_BYTE);
247b20b7b7aSMichael Roth         if (vec[i]) {
248b20b7b7aSMichael Roth             DPRINTFN("encoding guest vector byte %3d / %3d: 0x%.2x",
249b20b7b7aSMichael Roth                      i, vec_len, vec[i]);
250b20b7b7aSMichael Roth         }
251b20b7b7aSMichael Roth     }
252b20b7b7aSMichael Roth 
253*fe93e3e6SSam Bobroff     return fdt_setprop(fdt, fdt_offset, name, vec, vec_len + 1);
254b20b7b7aSMichael Roth }
255