qemu/hw/ppc/spapr_ovec.c
<<
>>
Prefs
   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 */
  30struct SpaprOptionVector {
  31    unsigned long *bitmap;
  32    int32_t bitmap_size; /* only used for migration */
  33};
  34
  35const 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
  45SpaprOptionVector *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
  56SpaprOptionVector *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
  68void 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 */
  80bool 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
 106void spapr_ovec_cleanup(SpaprOptionVector *ov)
 107{
 108    if (ov) {
 109        g_free(ov->bitmap);
 110        g_free(ov);
 111    }
 112}
 113
 114void 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
 122void 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
 130bool 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
 138static 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
 150static 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
 164static 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
 182SpaprOptionVector *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
 213int 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