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"
22 #define OV_MAXBYTES 256 /* not including length byte */
23 #define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE)
25 /* we *could* work with bitmaps directly, but handling the bitmap privately
26 * allows us to more safely make assumptions about the bitmap size and
27 * simplify the calling code somewhat
29 struct sPAPROptionVector
{
30 unsigned long *bitmap
;
31 int32_t bitmap_size
; /* only used for migration */
34 const VMStateDescription vmstate_spapr_ovec
= {
35 .name
= "spapr_option_vector",
37 .minimum_version_id
= 1,
38 .fields
= (VMStateField
[]) {
39 VMSTATE_BITMAP(bitmap
, sPAPROptionVector
, 1, bitmap_size
),
44 sPAPROptionVector
*spapr_ovec_new(void)
46 sPAPROptionVector
*ov
;
48 ov
= g_new0(sPAPROptionVector
, 1);
49 ov
->bitmap
= bitmap_new(OV_MAXBITS
);
50 ov
->bitmap_size
= OV_MAXBITS
;
55 sPAPROptionVector
*spapr_ovec_clone(sPAPROptionVector
*ov_orig
)
57 sPAPROptionVector
*ov
;
61 ov
= spapr_ovec_new();
62 bitmap_copy(ov
->bitmap
, ov_orig
->bitmap
, OV_MAXBITS
);
67 void spapr_ovec_intersect(sPAPROptionVector
*ov
,
68 sPAPROptionVector
*ov1
,
69 sPAPROptionVector
*ov2
)
75 bitmap_and(ov
->bitmap
, ov1
->bitmap
, ov2
->bitmap
, OV_MAXBITS
);
78 /* returns true if options bits were removed, false otherwise */
79 bool spapr_ovec_diff(sPAPROptionVector
*ov
,
80 sPAPROptionVector
*ov_old
,
81 sPAPROptionVector
*ov_new
)
83 unsigned long *change_mask
= bitmap_new(OV_MAXBITS
);
84 unsigned long *removed_bits
= bitmap_new(OV_MAXBITS
);
85 bool bits_were_removed
= false;
91 bitmap_xor(change_mask
, ov_old
->bitmap
, ov_new
->bitmap
, OV_MAXBITS
);
92 bitmap_and(ov
->bitmap
, ov_new
->bitmap
, change_mask
, OV_MAXBITS
);
93 bitmap_and(removed_bits
, ov_old
->bitmap
, change_mask
, OV_MAXBITS
);
95 if (!bitmap_empty(removed_bits
, OV_MAXBITS
)) {
96 bits_were_removed
= true;
100 g_free(removed_bits
);
102 return bits_were_removed
;
105 void spapr_ovec_cleanup(sPAPROptionVector
*ov
)
113 void spapr_ovec_set(sPAPROptionVector
*ov
, long bitnr
)
116 g_assert_cmpint(bitnr
, <, OV_MAXBITS
);
118 set_bit(bitnr
, ov
->bitmap
);
121 void spapr_ovec_clear(sPAPROptionVector
*ov
, long bitnr
)
124 g_assert_cmpint(bitnr
, <, OV_MAXBITS
);
126 clear_bit(bitnr
, ov
->bitmap
);
129 bool spapr_ovec_test(sPAPROptionVector
*ov
, long bitnr
)
132 g_assert_cmpint(bitnr
, <, OV_MAXBITS
);
134 return test_bit(bitnr
, ov
->bitmap
) ? true : false;
137 static void guest_byte_to_bitmap(uint8_t entry
, unsigned long *bitmap
,
142 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
143 if (entry
& (1 << (BITS_PER_BYTE
- 1 - i
))) {
144 bitmap_set(bitmap
, bitmap_offset
+ i
, 1);
149 static uint8_t guest_byte_from_bitmap(unsigned long *bitmap
, long bitmap_offset
)
154 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
155 if (test_bit(bitmap_offset
+ i
, bitmap
)) {
156 entry
|= (1 << (BITS_PER_BYTE
- 1 - i
));
163 static target_ulong
vector_addr(target_ulong table_addr
, int vector
)
165 uint16_t vector_count
, vector_len
;
168 vector_count
= ldub_phys(&address_space_memory
, table_addr
) + 1;
169 if (vector
> vector_count
) {
172 table_addr
++; /* skip nr option vectors */
174 for (i
= 0; i
< vector
- 1; i
++) {
175 vector_len
= ldub_phys(&address_space_memory
, table_addr
) + 1;
176 table_addr
+= vector_len
+ 1; /* bit-vector + length byte */
181 sPAPROptionVector
*spapr_ovec_parse_vector(target_ulong table_addr
, int vector
)
183 sPAPROptionVector
*ov
;
188 g_assert(table_addr
);
189 g_assert_cmpint(vector
, >=, 1); /* vector numbering starts at 1 */
191 addr
= vector_addr(table_addr
, vector
);
193 /* specified vector isn't present */
197 vector_len
= ldub_phys(&address_space_memory
, addr
++) + 1;
198 g_assert_cmpint(vector_len
, <=, OV_MAXBYTES
);
199 ov
= spapr_ovec_new();
201 for (i
= 0; i
< vector_len
; i
++) {
202 uint8_t entry
= ldub_phys(&address_space_memory
, addr
+ i
);
204 trace_spapr_ovec_parse_vector(vector
, i
+ 1, vector_len
, entry
);
205 guest_byte_to_bitmap(entry
, ov
->bitmap
, i
* BITS_PER_BYTE
);
212 int spapr_ovec_populate_dt(void *fdt
, int fdt_offset
,
213 sPAPROptionVector
*ov
, const char *name
)
215 uint8_t vec
[OV_MAXBYTES
+ 1];
217 unsigned long lastbit
;
222 lastbit
= find_last_bit(ov
->bitmap
, OV_MAXBITS
);
223 /* if no bits are set, include at least 1 byte of the vector so we can
224 * still encoded this in the device tree while abiding by the same
225 * encoding/sizing expected in ibm,client-architecture-support
227 vec_len
= (lastbit
== OV_MAXBITS
) ? 1 : lastbit
/ BITS_PER_BYTE
+ 1;
228 g_assert_cmpint(vec_len
, <=, OV_MAXBYTES
);
229 /* guest expects vector len encoded as vec_len - 1, since the length byte
230 * is assumed and not included, and the first byte of the vector
233 vec
[0] = vec_len
- 1;
235 for (i
= 1; i
< vec_len
+ 1; i
++) {
236 vec
[i
] = guest_byte_from_bitmap(ov
->bitmap
, (i
- 1) * BITS_PER_BYTE
);
238 trace_spapr_ovec_populate_dt(i
, vec_len
, vec
[i
]);
242 return fdt_setprop(fdt
, fdt_offset
, name
, vec
, vec_len
+ 1);