1 | /* |
2 | * QEMU SPAPR Architecture Option Vector Helper Functions |
3 | * |
4 | * Copyright IBM Corp. 2016 |
5 | * |
6 | * Authors: |
7 | * Bharata B Rao <bharata@linux.vnet.ibm.com> |
8 | * Michael Roth <mdroth@linux.vnet.ibm.com> |
9 | * |
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. |
12 | */ |
13 | |
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" |
20 | #include "trace.h" |
21 | #include <libfdt.h> |
22 | |
23 | #define OV_MAXBYTES 256 /* not including length byte */ |
24 | #define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE) |
25 | |
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 |
29 | */ |
30 | struct SpaprOptionVector { |
31 | unsigned long *bitmap; |
32 | int32_t bitmap_size; /* only used for migration */ |
33 | }; |
34 | |
35 | const VMStateDescription vmstate_spapr_ovec = { |
36 | .name = "spapr_option_vector" , |
37 | .version_id = 1, |
38 | .minimum_version_id = 1, |
39 | .fields = (VMStateField[]) { |
40 | VMSTATE_BITMAP(bitmap, SpaprOptionVector, 1, bitmap_size), |
41 | VMSTATE_END_OF_LIST() |
42 | } |
43 | }; |
44 | |
45 | SpaprOptionVector *spapr_ovec_new(void) |
46 | { |
47 | SpaprOptionVector *ov; |
48 | |
49 | ov = g_new0(SpaprOptionVector, 1); |
50 | ov->bitmap = bitmap_new(OV_MAXBITS); |
51 | ov->bitmap_size = OV_MAXBITS; |
52 | |
53 | return ov; |
54 | } |
55 | |
56 | SpaprOptionVector *spapr_ovec_clone(SpaprOptionVector *ov_orig) |
57 | { |
58 | SpaprOptionVector *ov; |
59 | |
60 | g_assert(ov_orig); |
61 | |
62 | ov = spapr_ovec_new(); |
63 | bitmap_copy(ov->bitmap, ov_orig->bitmap, OV_MAXBITS); |
64 | |
65 | return ov; |
66 | } |
67 | |
68 | void spapr_ovec_intersect(SpaprOptionVector *ov, |
69 | SpaprOptionVector *ov1, |
70 | SpaprOptionVector *ov2) |
71 | { |
72 | g_assert(ov); |
73 | g_assert(ov1); |
74 | g_assert(ov2); |
75 | |
76 | bitmap_and(ov->bitmap, ov1->bitmap, ov2->bitmap, OV_MAXBITS); |
77 | } |
78 | |
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) |
83 | { |
84 | unsigned long *change_mask = bitmap_new(OV_MAXBITS); |
85 | unsigned long *removed_bits = bitmap_new(OV_MAXBITS); |
86 | bool bits_were_removed = false; |
87 | |
88 | g_assert(ov); |
89 | g_assert(ov_old); |
90 | g_assert(ov_new); |
91 | |
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); |
95 | |
96 | if (!bitmap_empty(removed_bits, OV_MAXBITS)) { |
97 | bits_were_removed = true; |
98 | } |
99 | |
100 | g_free(change_mask); |
101 | g_free(removed_bits); |
102 | |
103 | return bits_were_removed; |
104 | } |
105 | |
106 | void spapr_ovec_cleanup(SpaprOptionVector *ov) |
107 | { |
108 | if (ov) { |
109 | g_free(ov->bitmap); |
110 | g_free(ov); |
111 | } |
112 | } |
113 | |
114 | void spapr_ovec_set(SpaprOptionVector *ov, long bitnr) |
115 | { |
116 | g_assert(ov); |
117 | g_assert(bitnr < OV_MAXBITS); |
118 | |
119 | set_bit(bitnr, ov->bitmap); |
120 | } |
121 | |
122 | void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr) |
123 | { |
124 | g_assert(ov); |
125 | g_assert(bitnr < OV_MAXBITS); |
126 | |
127 | clear_bit(bitnr, ov->bitmap); |
128 | } |
129 | |
130 | bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr) |
131 | { |
132 | g_assert(ov); |
133 | g_assert(bitnr < OV_MAXBITS); |
134 | |
135 | return test_bit(bitnr, ov->bitmap) ? true : false; |
136 | } |
137 | |
138 | static void guest_byte_to_bitmap(uint8_t entry, unsigned long *bitmap, |
139 | long bitmap_offset) |
140 | { |
141 | int i; |
142 | |
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); |
146 | } |
147 | } |
148 | } |
149 | |
150 | static uint8_t guest_byte_from_bitmap(unsigned long *bitmap, long bitmap_offset) |
151 | { |
152 | uint8_t entry = 0; |
153 | int i; |
154 | |
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)); |
158 | } |
159 | } |
160 | |
161 | return entry; |
162 | } |
163 | |
164 | static target_ulong vector_addr(target_ulong table_addr, int vector) |
165 | { |
166 | uint16_t vector_count, vector_len; |
167 | int i; |
168 | |
169 | vector_count = ldub_phys(&address_space_memory, table_addr) + 1; |
170 | if (vector > vector_count) { |
171 | return 0; |
172 | } |
173 | table_addr++; /* skip nr option vectors */ |
174 | |
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 */ |
178 | } |
179 | return table_addr; |
180 | } |
181 | |
182 | SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector) |
183 | { |
184 | SpaprOptionVector *ov; |
185 | target_ulong addr; |
186 | uint16_t vector_len; |
187 | int i; |
188 | |
189 | g_assert(table_addr); |
190 | g_assert(vector >= 1); /* vector numbering starts at 1 */ |
191 | |
192 | addr = vector_addr(table_addr, vector); |
193 | if (!addr) { |
194 | /* specified vector isn't present */ |
195 | return NULL; |
196 | } |
197 | |
198 | vector_len = ldub_phys(&address_space_memory, addr++) + 1; |
199 | g_assert(vector_len <= OV_MAXBYTES); |
200 | ov = spapr_ovec_new(); |
201 | |
202 | for (i = 0; i < vector_len; i++) { |
203 | uint8_t entry = ldub_phys(&address_space_memory, addr + i); |
204 | if (entry) { |
205 | trace_spapr_ovec_parse_vector(vector, i + 1, vector_len, entry); |
206 | guest_byte_to_bitmap(entry, ov->bitmap, i * BITS_PER_BYTE); |
207 | } |
208 | } |
209 | |
210 | return ov; |
211 | } |
212 | |
213 | int spapr_ovec_populate_dt(void *fdt, int fdt_offset, |
214 | SpaprOptionVector *ov, const char *name) |
215 | { |
216 | uint8_t vec[OV_MAXBYTES + 1]; |
217 | uint16_t vec_len; |
218 | unsigned long lastbit; |
219 | int i; |
220 | |
221 | g_assert(ov); |
222 | |
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 |
227 | */ |
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 |
232 | * is assumed as well |
233 | */ |
234 | vec[0] = vec_len - 1; |
235 | |
236 | for (i = 1; i < vec_len + 1; i++) { |
237 | vec[i] = guest_byte_from_bitmap(ov->bitmap, (i - 1) * BITS_PER_BYTE); |
238 | if (vec[i]) { |
239 | trace_spapr_ovec_populate_dt(i, vec_len, vec[i]); |
240 | } |
241 | } |
242 | |
243 | return fdt_setprop(fdt, fdt_offset, name, vec, vec_len + 1); |
244 | } |
245 | |