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"
19 #include "sysemu/qtest.h"
23 #define OV_MAXBYTES 256 /* not including length byte */
24 #define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE)
26 /* we *could* work with bitmaps directly, but handling the bitmap privately
27 * allows us to more safely make assumptions about the bitmap size and
28 * simplify the calling code somewhat
30 struct sPAPROptionVector
{
31 unsigned long *bitmap
;
32 int32_t bitmap_size
; /* only used for migration */
35 const VMStateDescription vmstate_spapr_ovec
= {
36 .name
= "spapr_option_vector",
38 .minimum_version_id
= 1,
39 .fields
= (VMStateField
[]) {
40 VMSTATE_BITMAP(bitmap
, sPAPROptionVector
, 1, bitmap_size
),
45 sPAPROptionVector
*spapr_ovec_new(void)
47 sPAPROptionVector
*ov
;
49 ov
= g_new0(sPAPROptionVector
, 1);
50 ov
->bitmap
= bitmap_new(OV_MAXBITS
);
51 ov
->bitmap_size
= OV_MAXBITS
;
56 sPAPROptionVector
*spapr_ovec_clone(sPAPROptionVector
*ov_orig
)
58 sPAPROptionVector
*ov
;
62 ov
= spapr_ovec_new();
63 bitmap_copy(ov
->bitmap
, ov_orig
->bitmap
, OV_MAXBITS
);
68 void spapr_ovec_intersect(sPAPROptionVector
*ov
,
69 sPAPROptionVector
*ov1
,
70 sPAPROptionVector
*ov2
)
76 bitmap_and(ov
->bitmap
, ov1
->bitmap
, ov2
->bitmap
, OV_MAXBITS
);
79 /* returns true if options bits were removed, false otherwise */
80 bool spapr_ovec_diff(sPAPROptionVector
*ov
,
81 sPAPROptionVector
*ov_old
,
82 sPAPROptionVector
*ov_new
)
84 unsigned long *change_mask
= bitmap_new(OV_MAXBITS
);
85 unsigned long *removed_bits
= bitmap_new(OV_MAXBITS
);
86 bool bits_were_removed
= false;
92 bitmap_xor(change_mask
, ov_old
->bitmap
, ov_new
->bitmap
, OV_MAXBITS
);
93 bitmap_and(ov
->bitmap
, ov_new
->bitmap
, change_mask
, OV_MAXBITS
);
94 bitmap_and(removed_bits
, ov_old
->bitmap
, change_mask
, OV_MAXBITS
);
96 if (!bitmap_empty(removed_bits
, OV_MAXBITS
)) {
97 bits_were_removed
= true;
101 g_free(removed_bits
);
103 return bits_were_removed
;
106 void spapr_ovec_cleanup(sPAPROptionVector
*ov
)
114 void spapr_ovec_set(sPAPROptionVector
*ov
, long bitnr
)
117 g_assert(bitnr
< OV_MAXBITS
);
119 set_bit(bitnr
, ov
->bitmap
);
122 void spapr_ovec_clear(sPAPROptionVector
*ov
, long bitnr
)
125 g_assert(bitnr
< OV_MAXBITS
);
127 clear_bit(bitnr
, ov
->bitmap
);
130 bool spapr_ovec_test(sPAPROptionVector
*ov
, long bitnr
)
133 g_assert(bitnr
< OV_MAXBITS
);
135 /* support memory unplug for qtest */
136 if (qtest_enabled() && bitnr
== OV5_HP_EVT
) {
140 return test_bit(bitnr
, ov
->bitmap
) ? true : false;
143 static void guest_byte_to_bitmap(uint8_t entry
, unsigned long *bitmap
,
148 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
149 if (entry
& (1 << (BITS_PER_BYTE
- 1 - i
))) {
150 bitmap_set(bitmap
, bitmap_offset
+ i
, 1);
155 static uint8_t guest_byte_from_bitmap(unsigned long *bitmap
, long bitmap_offset
)
160 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
161 if (test_bit(bitmap_offset
+ i
, bitmap
)) {
162 entry
|= (1 << (BITS_PER_BYTE
- 1 - i
));
169 static target_ulong
vector_addr(target_ulong table_addr
, int vector
)
171 uint16_t vector_count
, vector_len
;
174 vector_count
= ldub_phys(&address_space_memory
, table_addr
) + 1;
175 if (vector
> vector_count
) {
178 table_addr
++; /* skip nr option vectors */
180 for (i
= 0; i
< vector
- 1; i
++) {
181 vector_len
= ldub_phys(&address_space_memory
, table_addr
) + 1;
182 table_addr
+= vector_len
+ 1; /* bit-vector + length byte */
187 sPAPROptionVector
*spapr_ovec_parse_vector(target_ulong table_addr
, int vector
)
189 sPAPROptionVector
*ov
;
194 g_assert(table_addr
);
195 g_assert(vector
>= 1); /* vector numbering starts at 1 */
197 addr
= vector_addr(table_addr
, vector
);
199 /* specified vector isn't present */
203 vector_len
= ldub_phys(&address_space_memory
, addr
++) + 1;
204 g_assert(vector_len
<= OV_MAXBYTES
);
205 ov
= spapr_ovec_new();
207 for (i
= 0; i
< vector_len
; i
++) {
208 uint8_t entry
= ldub_phys(&address_space_memory
, addr
+ i
);
210 trace_spapr_ovec_parse_vector(vector
, i
+ 1, vector_len
, entry
);
211 guest_byte_to_bitmap(entry
, ov
->bitmap
, i
* BITS_PER_BYTE
);
218 int spapr_ovec_populate_dt(void *fdt
, int fdt_offset
,
219 sPAPROptionVector
*ov
, const char *name
)
221 uint8_t vec
[OV_MAXBYTES
+ 1];
223 unsigned long lastbit
;
228 lastbit
= find_last_bit(ov
->bitmap
, OV_MAXBITS
);
229 /* if no bits are set, include at least 1 byte of the vector so we can
230 * still encoded this in the device tree while abiding by the same
231 * encoding/sizing expected in ibm,client-architecture-support
233 vec_len
= (lastbit
== OV_MAXBITS
) ? 1 : lastbit
/ BITS_PER_BYTE
+ 1;
234 g_assert(vec_len
<= OV_MAXBYTES
);
235 /* guest expects vector len encoded as vec_len - 1, since the length byte
236 * is assumed and not included, and the first byte of the vector
239 vec
[0] = vec_len
- 1;
241 for (i
= 1; i
< vec_len
+ 1; i
++) {
242 vec
[i
] = guest_byte_from_bitmap(ov
->bitmap
, (i
- 1) * BITS_PER_BYTE
);
244 trace_spapr_ovec_populate_dt(i
, vec_len
, vec
[i
]);
248 return fdt_setprop(fdt
, fdt_offset
, name
, vec
, vec_len
+ 1);