]>
Commit | Line | Data |
---|---|---|
b20b7b7a MR |
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" | |
d6454270 | 16 | #include "migration/vmstate.h" |
b20b7b7a MR |
17 | #include "qemu/bitmap.h" |
18 | #include "exec/address-spaces.h" | |
19 | #include "qemu/error-report.h" | |
5b929608 | 20 | #include "trace.h" |
b20b7b7a MR |
21 | #include <libfdt.h> |
22 | ||
b20b7b7a MR |
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 | */ | |
ce2918cb | 30 | struct SpaprOptionVector { |
b20b7b7a | 31 | unsigned long *bitmap; |
62ef3760 MR |
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[]) { | |
ce2918cb | 40 | VMSTATE_BITMAP(bitmap, SpaprOptionVector, 1, bitmap_size), |
62ef3760 MR |
41 | VMSTATE_END_OF_LIST() |
42 | } | |
b20b7b7a MR |
43 | }; |
44 | ||
ce2918cb | 45 | SpaprOptionVector *spapr_ovec_new(void) |
b20b7b7a | 46 | { |
ce2918cb | 47 | SpaprOptionVector *ov; |
b20b7b7a | 48 | |
ce2918cb | 49 | ov = g_new0(SpaprOptionVector, 1); |
b20b7b7a | 50 | ov->bitmap = bitmap_new(OV_MAXBITS); |
62ef3760 | 51 | ov->bitmap_size = OV_MAXBITS; |
b20b7b7a MR |
52 | |
53 | return ov; | |
54 | } | |
55 | ||
ce2918cb | 56 | SpaprOptionVector *spapr_ovec_clone(SpaprOptionVector *ov_orig) |
b20b7b7a | 57 | { |
ce2918cb | 58 | SpaprOptionVector *ov; |
b20b7b7a MR |
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 | ||
ce2918cb DG |
68 | void spapr_ovec_intersect(SpaprOptionVector *ov, |
69 | SpaprOptionVector *ov1, | |
70 | SpaprOptionVector *ov2) | |
b20b7b7a MR |
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 | ||
d1d32d62 DG |
79 | /* returns true if ov1 has a subset of bits in ov2 */ |
80 | bool spapr_ovec_subset(SpaprOptionVector *ov1, SpaprOptionVector *ov2) | |
b20b7b7a | 81 | { |
d1d32d62 DG |
82 | unsigned long *tmp = bitmap_new(OV_MAXBITS); |
83 | bool result; | |
b20b7b7a | 84 | |
d1d32d62 DG |
85 | g_assert(ov1); |
86 | g_assert(ov2); | |
b20b7b7a | 87 | |
d1d32d62 DG |
88 | bitmap_andnot(tmp, ov1->bitmap, ov2->bitmap, OV_MAXBITS); |
89 | result = bitmap_empty(tmp, OV_MAXBITS); | |
b20b7b7a | 90 | |
d1d32d62 | 91 | g_free(tmp); |
b20b7b7a | 92 | |
d1d32d62 | 93 | return result; |
b20b7b7a MR |
94 | } |
95 | ||
ce2918cb | 96 | void spapr_ovec_cleanup(SpaprOptionVector *ov) |
b20b7b7a MR |
97 | { |
98 | if (ov) { | |
99 | g_free(ov->bitmap); | |
100 | g_free(ov); | |
101 | } | |
102 | } | |
103 | ||
ce2918cb | 104 | void spapr_ovec_set(SpaprOptionVector *ov, long bitnr) |
b20b7b7a MR |
105 | { |
106 | g_assert(ov); | |
719a3077 | 107 | g_assert(bitnr < OV_MAXBITS); |
b20b7b7a MR |
108 | |
109 | set_bit(bitnr, ov->bitmap); | |
110 | } | |
111 | ||
ce2918cb | 112 | void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr) |
b20b7b7a MR |
113 | { |
114 | g_assert(ov); | |
719a3077 | 115 | g_assert(bitnr < OV_MAXBITS); |
b20b7b7a MR |
116 | |
117 | clear_bit(bitnr, ov->bitmap); | |
118 | } | |
119 | ||
ce2918cb | 120 | bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr) |
b20b7b7a MR |
121 | { |
122 | g_assert(ov); | |
719a3077 | 123 | g_assert(bitnr < OV_MAXBITS); |
b20b7b7a MR |
124 | |
125 | return test_bit(bitnr, ov->bitmap) ? true : false; | |
126 | } | |
127 | ||
73598c75 GK |
128 | bool spapr_ovec_empty(SpaprOptionVector *ov) |
129 | { | |
130 | g_assert(ov); | |
131 | ||
132 | return bitmap_empty(ov->bitmap, OV_MAXBITS); | |
133 | } | |
134 | ||
b20b7b7a MR |
135 | static void guest_byte_to_bitmap(uint8_t entry, unsigned long *bitmap, |
136 | long bitmap_offset) | |
137 | { | |
138 | int i; | |
139 | ||
140 | for (i = 0; i < BITS_PER_BYTE; i++) { | |
141 | if (entry & (1 << (BITS_PER_BYTE - 1 - i))) { | |
142 | bitmap_set(bitmap, bitmap_offset + i, 1); | |
143 | } | |
144 | } | |
145 | } | |
146 | ||
147 | static uint8_t guest_byte_from_bitmap(unsigned long *bitmap, long bitmap_offset) | |
148 | { | |
149 | uint8_t entry = 0; | |
150 | int i; | |
151 | ||
152 | for (i = 0; i < BITS_PER_BYTE; i++) { | |
153 | if (test_bit(bitmap_offset + i, bitmap)) { | |
154 | entry |= (1 << (BITS_PER_BYTE - 1 - i)); | |
155 | } | |
156 | } | |
157 | ||
158 | return entry; | |
159 | } | |
160 | ||
161 | static target_ulong vector_addr(target_ulong table_addr, int vector) | |
162 | { | |
163 | uint16_t vector_count, vector_len; | |
164 | int i; | |
165 | ||
166 | vector_count = ldub_phys(&address_space_memory, table_addr) + 1; | |
167 | if (vector > vector_count) { | |
168 | return 0; | |
169 | } | |
170 | table_addr++; /* skip nr option vectors */ | |
171 | ||
172 | for (i = 0; i < vector - 1; i++) { | |
173 | vector_len = ldub_phys(&address_space_memory, table_addr) + 1; | |
174 | table_addr += vector_len + 1; /* bit-vector + length byte */ | |
175 | } | |
176 | return table_addr; | |
177 | } | |
178 | ||
ce2918cb | 179 | SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector) |
b20b7b7a | 180 | { |
ce2918cb | 181 | SpaprOptionVector *ov; |
b20b7b7a MR |
182 | target_ulong addr; |
183 | uint16_t vector_len; | |
184 | int i; | |
185 | ||
186 | g_assert(table_addr); | |
719a3077 | 187 | g_assert(vector >= 1); /* vector numbering starts at 1 */ |
b20b7b7a MR |
188 | |
189 | addr = vector_addr(table_addr, vector); | |
190 | if (!addr) { | |
191 | /* specified vector isn't present */ | |
192 | return NULL; | |
193 | } | |
194 | ||
195 | vector_len = ldub_phys(&address_space_memory, addr++) + 1; | |
719a3077 | 196 | g_assert(vector_len <= OV_MAXBYTES); |
b20b7b7a MR |
197 | ov = spapr_ovec_new(); |
198 | ||
199 | for (i = 0; i < vector_len; i++) { | |
200 | uint8_t entry = ldub_phys(&address_space_memory, addr + i); | |
201 | if (entry) { | |
5b929608 | 202 | trace_spapr_ovec_parse_vector(vector, i + 1, vector_len, entry); |
b20b7b7a MR |
203 | guest_byte_to_bitmap(entry, ov->bitmap, i * BITS_PER_BYTE); |
204 | } | |
205 | } | |
206 | ||
207 | return ov; | |
208 | } | |
209 | ||
91335a5e DG |
210 | int spapr_dt_ovec(void *fdt, int fdt_offset, |
211 | SpaprOptionVector *ov, const char *name) | |
b20b7b7a MR |
212 | { |
213 | uint8_t vec[OV_MAXBYTES + 1]; | |
214 | uint16_t vec_len; | |
215 | unsigned long lastbit; | |
216 | int i; | |
217 | ||
218 | g_assert(ov); | |
219 | ||
220 | lastbit = find_last_bit(ov->bitmap, OV_MAXBITS); | |
221 | /* if no bits are set, include at least 1 byte of the vector so we can | |
222 | * still encoded this in the device tree while abiding by the same | |
223 | * encoding/sizing expected in ibm,client-architecture-support | |
224 | */ | |
225 | vec_len = (lastbit == OV_MAXBITS) ? 1 : lastbit / BITS_PER_BYTE + 1; | |
719a3077 | 226 | g_assert(vec_len <= OV_MAXBYTES); |
b20b7b7a MR |
227 | /* guest expects vector len encoded as vec_len - 1, since the length byte |
228 | * is assumed and not included, and the first byte of the vector | |
229 | * is assumed as well | |
230 | */ | |
231 | vec[0] = vec_len - 1; | |
232 | ||
233 | for (i = 1; i < vec_len + 1; i++) { | |
234 | vec[i] = guest_byte_from_bitmap(ov->bitmap, (i - 1) * BITS_PER_BYTE); | |
235 | if (vec[i]) { | |
5b929608 | 236 | trace_spapr_ovec_populate_dt(i, vec_len, vec[i]); |
b20b7b7a MR |
237 | } |
238 | } | |
239 | ||
fe93e3e6 | 240 | return fdt_setprop(fdt, fdt_offset, name, vec, vec_len + 1); |
b20b7b7a | 241 | } |