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 ov1 has a subset of bits in ov2 */
80 bool spapr_ovec_subset(SpaprOptionVector
*ov1
, SpaprOptionVector
*ov2
)
82 unsigned long *tmp
= bitmap_new(OV_MAXBITS
);
88 bitmap_andnot(tmp
, ov1
->bitmap
, ov2
->bitmap
, OV_MAXBITS
);
89 result
= bitmap_empty(tmp
, OV_MAXBITS
);
96 void spapr_ovec_cleanup(SpaprOptionVector
*ov
)
104 void spapr_ovec_set(SpaprOptionVector
*ov
, long bitnr
)
107 g_assert(bitnr
< OV_MAXBITS
);
109 set_bit(bitnr
, ov
->bitmap
);
112 void spapr_ovec_clear(SpaprOptionVector
*ov
, long bitnr
)
115 g_assert(bitnr
< OV_MAXBITS
);
117 clear_bit(bitnr
, ov
->bitmap
);
120 bool spapr_ovec_test(SpaprOptionVector
*ov
, long bitnr
)
123 g_assert(bitnr
< OV_MAXBITS
);
125 return test_bit(bitnr
, ov
->bitmap
) ? true : false;
128 static void guest_byte_to_bitmap(uint8_t entry
, unsigned long *bitmap
,
133 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
134 if (entry
& (1 << (BITS_PER_BYTE
- 1 - i
))) {
135 bitmap_set(bitmap
, bitmap_offset
+ i
, 1);
140 static uint8_t guest_byte_from_bitmap(unsigned long *bitmap
, long bitmap_offset
)
145 for (i
= 0; i
< BITS_PER_BYTE
; i
++) {
146 if (test_bit(bitmap_offset
+ i
, bitmap
)) {
147 entry
|= (1 << (BITS_PER_BYTE
- 1 - i
));
154 static target_ulong
vector_addr(target_ulong table_addr
, int vector
)
156 uint16_t vector_count
, vector_len
;
159 vector_count
= ldub_phys(&address_space_memory
, table_addr
) + 1;
160 if (vector
> vector_count
) {
163 table_addr
++; /* skip nr option vectors */
165 for (i
= 0; i
< vector
- 1; i
++) {
166 vector_len
= ldub_phys(&address_space_memory
, table_addr
) + 1;
167 table_addr
+= vector_len
+ 1; /* bit-vector + length byte */
172 SpaprOptionVector
*spapr_ovec_parse_vector(target_ulong table_addr
, int vector
)
174 SpaprOptionVector
*ov
;
179 g_assert(table_addr
);
180 g_assert(vector
>= 1); /* vector numbering starts at 1 */
182 addr
= vector_addr(table_addr
, vector
);
184 /* specified vector isn't present */
188 vector_len
= ldub_phys(&address_space_memory
, addr
++) + 1;
189 g_assert(vector_len
<= OV_MAXBYTES
);
190 ov
= spapr_ovec_new();
192 for (i
= 0; i
< vector_len
; i
++) {
193 uint8_t entry
= ldub_phys(&address_space_memory
, addr
+ i
);
195 trace_spapr_ovec_parse_vector(vector
, i
+ 1, vector_len
, entry
);
196 guest_byte_to_bitmap(entry
, ov
->bitmap
, i
* BITS_PER_BYTE
);
203 int spapr_dt_ovec(void *fdt
, int fdt_offset
,
204 SpaprOptionVector
*ov
, const char *name
)
206 uint8_t vec
[OV_MAXBYTES
+ 1];
208 unsigned long lastbit
;
213 lastbit
= find_last_bit(ov
->bitmap
, OV_MAXBITS
);
214 /* if no bits are set, include at least 1 byte of the vector so we can
215 * still encoded this in the device tree while abiding by the same
216 * encoding/sizing expected in ibm,client-architecture-support
218 vec_len
= (lastbit
== OV_MAXBITS
) ? 1 : lastbit
/ BITS_PER_BYTE
+ 1;
219 g_assert(vec_len
<= OV_MAXBYTES
);
220 /* guest expects vector len encoded as vec_len - 1, since the length byte
221 * is assumed and not included, and the first byte of the vector
224 vec
[0] = vec_len
- 1;
226 for (i
= 1; i
< vec_len
+ 1; i
++) {
227 vec
[i
] = guest_byte_from_bitmap(ov
->bitmap
, (i
- 1) * BITS_PER_BYTE
);
229 trace_spapr_ovec_populate_dt(i
, vec_len
, vec
[i
]);
233 return fdt_setprop(fdt
, fdt_offset
, name
, vec
, vec_len
+ 1);