2 * QEMU SPAPR Architecture Option Vector Helper Functions
4 * Copyright IBM Corp. 2016
7 * Bharata B Rao <bharata@linux.vnet.ibm.com>
8 * Michael Roth <mdroth@linux.vnet.ibm.com>
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "hw/ppc/spapr_ovec.h"
16 #include "qemu/bitmap.h"
17 #include "exec/address-spaces.h"
18 #include "qemu/error-report.h"
21 /* #define DEBUG_SPAPR_OVEC */
23 #ifdef DEBUG_SPAPR_OVEC
24 #define DPRINTFN(fmt, ...) \
25 do { fprintf(stderr, fmt "\n", ## __VA_ARGS__); } while (0)
27 #define DPRINTFN(fmt, ...) \
31 #define OV_MAXBYTES 256 /* not including length byte */
32 #define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE)
34 /* we *could* work with bitmaps directly, but handling the bitmap privately
35 * allows us to more safely make assumptions about the bitmap size and
36 * simplify the calling code somewhat
38 struct sPAPROptionVector
{
39 unsigned long *bitmap
;
40 int32_t bitmap_size
; /* only used for migration */
43 const VMStateDescription vmstate_spapr_ovec
= {
44 .name
= "spapr_option_vector",
46 .minimum_version_id
= 1,
47 .fields
= (VMStateField
[]) {
48 VMSTATE_BITMAP(bitmap
, sPAPROptionVector
, 1, bitmap_size
),
53 sPAPROptionVector
*spapr_ovec_new(void)
55 sPAPROptionVector
*ov
;
57 ov
= g_new0(sPAPROptionVector
, 1);
58 ov
->bitmap
= bitmap_new(OV_MAXBITS
);
59 ov
->bitmap_size
= OV_MAXBITS
;
64 sPAPROptionVector
*spapr_ovec_clone(sPAPROptionVector
*ov_orig
)
66 sPAPROptionVector
*ov
;
70 ov
= spapr_ovec_new();
71 bitmap_copy(ov
->bitmap
, ov_orig
->bitmap
, OV_MAXBITS
);
76 void spapr_ovec_intersect(sPAPROptionVector
*ov
,
77 sPAPROptionVector
*ov1
,
78 sPAPROptionVector
*ov2
)
84 bitmap_and(ov
->bitmap
, ov1
->bitmap
, ov2
->bitmap
, OV_MAXBITS
);
87 /* returns true if options bits were removed, false otherwise */
88 bool spapr_ovec_diff(sPAPROptionVector
*ov
,
89 sPAPROptionVector
*ov_old
,
90 sPAPROptionVector
*ov_new
)
92 unsigned long *change_mask
= bitmap_new(OV_MAXBITS
);
93 unsigned long *removed_bits
= bitmap_new(OV_MAXBITS
);
94 bool bits_were_removed
= false;
100 bitmap_xor(change_mask
, ov_old
->bitmap
, ov_new
->bitmap
, OV_MAXBITS
);
101 bitmap_and(ov
->bitmap
, ov_new
->bitmap
, change_mask
, OV_MAXBITS
);
102 bitmap_and(removed_bits
, ov_old
->bitmap
, change_mask
, OV_MAXBITS
);
104 if (!bitmap_empty(removed_bits
, OV_MAXBITS
)) {
105 bits_were_removed
= true;
109 g_free(removed_bits
);
111 return bits_were_removed
;
114 void spapr_ovec_cleanup(sPAPROptionVector
*ov
)
122 void spapr_ovec_set(sPAPROptionVector
*ov
, long bitnr
)
125 g_assert_cmpint(bitnr
, <, OV_MAXBITS
);
127 set_bit(bitnr
, ov
->bitmap
);
130 void spapr_ovec_clear(sPAPROptionVector
*ov
, long bitnr
)
133 g_assert_cmpint(bitnr
, <, OV_MAXBITS
);
135 clear_bit(bitnr
, ov
->bitmap
);
138 bool spapr_ovec_test(sPAPROptionVector
*ov
, long bitnr
)
141 g_assert_cmpint(bitnr
, <, OV_MAXBITS
);
143 return test_bit(bitnr
, ov
->bitmap
) ? true : false;
146 static void guest_byte_to_bitmap(uint8_t entry
, unsigned long *bitmap
,
151 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
152 if (entry
& (1 << (BITS_PER_BYTE
- 1 - i
))) {
153 bitmap_set(bitmap
, bitmap_offset
+ i
, 1);
158 static uint8_t guest_byte_from_bitmap(unsigned long *bitmap
, long bitmap_offset
)
163 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
164 if (test_bit(bitmap_offset
+ i
, bitmap
)) {
165 entry
|= (1 << (BITS_PER_BYTE
- 1 - i
));
172 static target_ulong
vector_addr(target_ulong table_addr
, int vector
)
174 uint16_t vector_count
, vector_len
;
177 vector_count
= ldub_phys(&address_space_memory
, table_addr
) + 1;
178 if (vector
> vector_count
) {
181 table_addr
++; /* skip nr option vectors */
183 for (i
= 0; i
< vector
- 1; i
++) {
184 vector_len
= ldub_phys(&address_space_memory
, table_addr
) + 1;
185 table_addr
+= vector_len
+ 1; /* bit-vector + length byte */
190 sPAPROptionVector
*spapr_ovec_parse_vector(target_ulong table_addr
, int vector
)
192 sPAPROptionVector
*ov
;
197 g_assert(table_addr
);
198 g_assert_cmpint(vector
, >=, 1); /* vector numbering starts at 1 */
200 addr
= vector_addr(table_addr
, vector
);
202 /* specified vector isn't present */
206 vector_len
= ldub_phys(&address_space_memory
, addr
++) + 1;
207 g_assert_cmpint(vector_len
, <=, OV_MAXBYTES
);
208 ov
= spapr_ovec_new();
210 for (i
= 0; i
< vector_len
; i
++) {
211 uint8_t entry
= ldub_phys(&address_space_memory
, addr
+ i
);
213 DPRINTFN("read guest vector %2d, byte %3d / %3d: 0x%.2x",
214 vector
, i
+ 1, vector_len
, entry
);
215 guest_byte_to_bitmap(entry
, ov
->bitmap
, i
* BITS_PER_BYTE
);
222 int spapr_ovec_populate_dt(void *fdt
, int fdt_offset
,
223 sPAPROptionVector
*ov
, const char *name
)
225 uint8_t vec
[OV_MAXBYTES
+ 1];
227 unsigned long lastbit
;
232 lastbit
= find_last_bit(ov
->bitmap
, OV_MAXBITS
);
233 /* if no bits are set, include at least 1 byte of the vector so we can
234 * still encoded this in the device tree while abiding by the same
235 * encoding/sizing expected in ibm,client-architecture-support
237 vec_len
= (lastbit
== OV_MAXBITS
) ? 1 : lastbit
/ BITS_PER_BYTE
+ 1;
238 g_assert_cmpint(vec_len
, <=, OV_MAXBYTES
);
239 /* guest expects vector len encoded as vec_len - 1, since the length byte
240 * is assumed and not included, and the first byte of the vector
243 vec
[0] = vec_len
- 1;
245 for (i
= 1; i
< vec_len
+ 1; i
++) {
246 vec
[i
] = guest_byte_from_bitmap(ov
->bitmap
, (i
- 1) * BITS_PER_BYTE
);
248 DPRINTFN("encoding guest vector byte %3d / %3d: 0x%.2x",
253 return fdt_setprop(fdt
, fdt_offset
, name
, vec
, vec_len
);