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 "migration/vmstate.h"
17 #include "qemu/bitmap.h"
18 #include "exec/address-spaces.h"
19 #include "qemu/error-report.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 return test_bit(bitnr
, ov
->bitmap
) ? true : false;
138 static void guest_byte_to_bitmap(uint8_t entry
, unsigned long *bitmap
,
143 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
144 if (entry
& (1 << (BITS_PER_BYTE
- 1 - i
))) {
145 bitmap_set(bitmap
, bitmap_offset
+ i
, 1);
150 static uint8_t guest_byte_from_bitmap(unsigned long *bitmap
, long bitmap_offset
)
155 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
156 if (test_bit(bitmap_offset
+ i
, bitmap
)) {
157 entry
|= (1 << (BITS_PER_BYTE
- 1 - i
));
164 static target_ulong
vector_addr(target_ulong table_addr
, int vector
)
166 uint16_t vector_count
, vector_len
;
169 vector_count
= ldub_phys(&address_space_memory
, table_addr
) + 1;
170 if (vector
> vector_count
) {
173 table_addr
++; /* skip nr option vectors */
175 for (i
= 0; i
< vector
- 1; i
++) {
176 vector_len
= ldub_phys(&address_space_memory
, table_addr
) + 1;
177 table_addr
+= vector_len
+ 1; /* bit-vector + length byte */
182 SpaprOptionVector
*spapr_ovec_parse_vector(target_ulong table_addr
, int vector
)
184 SpaprOptionVector
*ov
;
189 g_assert(table_addr
);
190 g_assert(vector
>= 1); /* vector numbering starts at 1 */
192 addr
= vector_addr(table_addr
, vector
);
194 /* specified vector isn't present */
198 vector_len
= ldub_phys(&address_space_memory
, addr
++) + 1;
199 g_assert(vector_len
<= OV_MAXBYTES
);
200 ov
= spapr_ovec_new();
202 for (i
= 0; i
< vector_len
; i
++) {
203 uint8_t entry
= ldub_phys(&address_space_memory
, addr
+ i
);
205 trace_spapr_ovec_parse_vector(vector
, i
+ 1, vector_len
, entry
);
206 guest_byte_to_bitmap(entry
, ov
->bitmap
, i
* BITS_PER_BYTE
);
213 int spapr_ovec_populate_dt(void *fdt
, int fdt_offset
,
214 SpaprOptionVector
*ov
, const char *name
)
216 uint8_t vec
[OV_MAXBYTES
+ 1];
218 unsigned long lastbit
;
223 lastbit
= find_last_bit(ov
->bitmap
, OV_MAXBITS
);
224 /* if no bits are set, include at least 1 byte of the vector so we can
225 * still encoded this in the device tree while abiding by the same
226 * encoding/sizing expected in ibm,client-architecture-support
228 vec_len
= (lastbit
== OV_MAXBITS
) ? 1 : lastbit
/ BITS_PER_BYTE
+ 1;
229 g_assert(vec_len
<= OV_MAXBYTES
);
230 /* guest expects vector len encoded as vec_len - 1, since the length byte
231 * is assumed and not included, and the first byte of the vector
234 vec
[0] = vec_len
- 1;
236 for (i
= 1; i
< vec_len
+ 1; i
++) {
237 vec
[i
] = guest_byte_from_bitmap(ov
->bitmap
, (i
- 1) * BITS_PER_BYTE
);
239 trace_spapr_ovec_populate_dt(i
, vec_len
, vec
[i
]);
243 return fdt_setprop(fdt
, fdt_offset
, name
, vec
, vec_len
+ 1);