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