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 "system/address-spaces.h" 19 #include "system/memory.h" 20 #include "qemu/error-report.h" 21 #include "trace.h" 22 #include <libfdt.h> 23 24 #define OV_MAXBYTES 256 /* not including length byte */ 25 #define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE) 26 27 /* we *could* work with bitmaps directly, but handling the bitmap privately 28 * allows us to more safely make assumptions about the bitmap size and 29 * simplify the calling code somewhat 30 */ 31 struct SpaprOptionVector { 32 unsigned long *bitmap; 33 int32_t bitmap_size; /* only used for migration */ 34 }; 35 36 const VMStateDescription vmstate_spapr_ovec = { 37 .name = "spapr_option_vector", 38 .version_id = 1, 39 .minimum_version_id = 1, 40 .fields = (const VMStateField[]) { 41 VMSTATE_BITMAP(bitmap, SpaprOptionVector, 1, bitmap_size), 42 VMSTATE_END_OF_LIST() 43 } 44 }; 45 46 SpaprOptionVector *spapr_ovec_new(void) 47 { 48 SpaprOptionVector *ov; 49 50 ov = g_new0(SpaprOptionVector, 1); 51 ov->bitmap = bitmap_new(OV_MAXBITS); 52 ov->bitmap_size = OV_MAXBITS; 53 54 return ov; 55 } 56 57 SpaprOptionVector *spapr_ovec_clone(SpaprOptionVector *ov_orig) 58 { 59 SpaprOptionVector *ov; 60 61 g_assert(ov_orig); 62 63 ov = spapr_ovec_new(); 64 bitmap_copy(ov->bitmap, ov_orig->bitmap, OV_MAXBITS); 65 66 return ov; 67 } 68 69 void spapr_ovec_intersect(SpaprOptionVector *ov, 70 SpaprOptionVector *ov1, 71 SpaprOptionVector *ov2) 72 { 73 g_assert(ov); 74 g_assert(ov1); 75 g_assert(ov2); 76 77 bitmap_and(ov->bitmap, ov1->bitmap, ov2->bitmap, OV_MAXBITS); 78 } 79 80 /* returns true if ov1 has a subset of bits in ov2 */ 81 bool spapr_ovec_subset(SpaprOptionVector *ov1, SpaprOptionVector *ov2) 82 { 83 unsigned long *tmp = bitmap_new(OV_MAXBITS); 84 bool result; 85 86 g_assert(ov1); 87 g_assert(ov2); 88 89 bitmap_andnot(tmp, ov1->bitmap, ov2->bitmap, OV_MAXBITS); 90 result = bitmap_empty(tmp, OV_MAXBITS); 91 92 g_free(tmp); 93 94 return result; 95 } 96 97 void spapr_ovec_cleanup(SpaprOptionVector *ov) 98 { 99 if (ov) { 100 g_free(ov->bitmap); 101 g_free(ov); 102 } 103 } 104 105 void spapr_ovec_set(SpaprOptionVector *ov, long bitnr) 106 { 107 g_assert(ov); 108 g_assert(bitnr < OV_MAXBITS); 109 110 set_bit(bitnr, ov->bitmap); 111 } 112 113 void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr) 114 { 115 g_assert(ov); 116 g_assert(bitnr < OV_MAXBITS); 117 118 clear_bit(bitnr, ov->bitmap); 119 } 120 121 bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr) 122 { 123 g_assert(ov); 124 g_assert(bitnr < OV_MAXBITS); 125 126 return test_bit(bitnr, ov->bitmap) ? true : false; 127 } 128 129 bool spapr_ovec_empty(SpaprOptionVector *ov) 130 { 131 g_assert(ov); 132 133 return bitmap_empty(ov->bitmap, OV_MAXBITS); 134 } 135 136 static void guest_byte_to_bitmap(uint8_t entry, unsigned long *bitmap, 137 long bitmap_offset) 138 { 139 int i; 140 141 for (i = 0; i < BITS_PER_BYTE; i++) { 142 if (entry & (1 << (BITS_PER_BYTE - 1 - i))) { 143 bitmap_set(bitmap, bitmap_offset + i, 1); 144 } 145 } 146 } 147 148 static uint8_t guest_byte_from_bitmap(unsigned long *bitmap, long bitmap_offset) 149 { 150 uint8_t entry = 0; 151 int i; 152 153 for (i = 0; i < BITS_PER_BYTE; i++) { 154 if (test_bit(bitmap_offset + i, bitmap)) { 155 entry |= (1 << (BITS_PER_BYTE - 1 - i)); 156 } 157 } 158 159 return entry; 160 } 161 162 static target_ulong vector_addr(target_ulong table_addr, int vector) 163 { 164 uint16_t vector_count, vector_len; 165 int i; 166 167 vector_count = ldub_phys(&address_space_memory, table_addr) + 1; 168 if (vector > vector_count) { 169 return 0; 170 } 171 table_addr++; /* skip nr option vectors */ 172 173 for (i = 0; i < vector - 1; i++) { 174 vector_len = ldub_phys(&address_space_memory, table_addr) + 1; 175 table_addr += vector_len + 1; /* bit-vector + length byte */ 176 } 177 return table_addr; 178 } 179 180 SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector) 181 { 182 SpaprOptionVector *ov; 183 target_ulong addr; 184 uint16_t vector_len; 185 int i; 186 187 g_assert(table_addr); 188 g_assert(vector >= 1); /* vector numbering starts at 1 */ 189 190 addr = vector_addr(table_addr, vector); 191 if (!addr) { 192 /* specified vector isn't present */ 193 return NULL; 194 } 195 196 vector_len = ldub_phys(&address_space_memory, addr++) + 1; 197 g_assert(vector_len <= OV_MAXBYTES); 198 ov = spapr_ovec_new(); 199 200 for (i = 0; i < vector_len; i++) { 201 uint8_t entry = ldub_phys(&address_space_memory, addr + i); 202 if (entry) { 203 trace_spapr_ovec_parse_vector(vector, i + 1, vector_len, entry); 204 guest_byte_to_bitmap(entry, ov->bitmap, i * BITS_PER_BYTE); 205 } 206 } 207 208 return ov; 209 } 210 211 int spapr_dt_ovec(void *fdt, int fdt_offset, 212 SpaprOptionVector *ov, const char *name) 213 { 214 uint8_t vec[OV_MAXBYTES + 1]; 215 uint16_t vec_len; 216 unsigned long lastbit; 217 int i; 218 219 g_assert(ov); 220 221 lastbit = find_last_bit(ov->bitmap, OV_MAXBITS); 222 /* if no bits are set, include at least 1 byte of the vector so we can 223 * still encoded this in the device tree while abiding by the same 224 * encoding/sizing expected in ibm,client-architecture-support 225 */ 226 vec_len = (lastbit == OV_MAXBITS) ? 1 : lastbit / BITS_PER_BYTE + 1; 227 g_assert(vec_len <= OV_MAXBYTES); 228 /* guest expects vector len encoded as vec_len - 1, since the length byte 229 * is assumed and not included, and the first byte of the vector 230 * is assumed as well 231 */ 232 vec[0] = vec_len - 1; 233 234 for (i = 1; i < vec_len + 1; i++) { 235 vec[i] = guest_byte_from_bitmap(ov->bitmap, (i - 1) * BITS_PER_BYTE); 236 if (vec[i]) { 237 trace_spapr_ovec_populate_dt(i, vec_len, vec[i]); 238 } 239 } 240 241 return fdt_setprop(fdt, fdt_offset, name, vec, vec_len + 1); 242 } 243