On Mon, Oct 24, 2016 at 11:47:27PM -0500, Michael Roth wrote: > PAPR guests advertise their capabilities to the platform by passing > an ibm,architecture-vec structure via an > ibm,client-architecture-support hcall as described by LoPAPR v11, > B.6.2.3. during early boot. > > Using this information, the platform enables the capabilities it > supports, then encodes a subset of those enabled capabilities (the > 5th option vector of the ibm,architecture-vec structure passed to > ibm,client-architecture-support) into the guest device tree via > "/chosen/ibm,architecture-vec-5". > > The logical format of these these option vectors is a bit-vector, > where individual bits are addressed/documented based on the byte-wise > offset from the beginning of the bit-vector, followed by the bit-wise > index starting from the byte-wise offset. Thus the bits of each of > these bytes are stored in reverse order. Additionally, the first > byte of each option vector is encodes the length of the option vector, > so byte offsets begin at 1, and bit offset at 0. > > This is not very intuitive for the purposes of mapping these bits to > a particular documented capability, so this patch introduces a set > of abstractions that encapsulate the work of parsing/encoding these > options vectors and testing for individual capabilities. > > Cc: Bharata B Rao <bhar...@linux.vnet.ibm.com> > Signed-off-by: Michael Roth <mdr...@linux.vnet.ibm.com>
Reviewed-by: David Gibson <da...@gibson.dropbear.id.au> > --- > hw/ppc/Makefile.objs | 2 +- > hw/ppc/spapr_ovec.c | 242 > ++++++++++++++++++++++++++++++++++++++++++++ > include/hw/ppc/spapr_ovec.h | 62 ++++++++++++ > 3 files changed, 305 insertions(+), 1 deletion(-) > create mode 100644 hw/ppc/spapr_ovec.c > create mode 100644 include/hw/ppc/spapr_ovec.h > > diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs > index ebc72af..8025129 100644 > --- a/hw/ppc/Makefile.objs > +++ b/hw/ppc/Makefile.objs > @@ -4,7 +4,7 @@ obj-y += ppc.o ppc_booke.o fdt.o > obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o > obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o > obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o > -obj-$(CONFIG_PSERIES) += spapr_cpu_core.o > +obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o > # IBM PowerNV > obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o > ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) > diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c > new file mode 100644 > index 0000000..c2a0d18 > --- /dev/null > +++ b/hw/ppc/spapr_ovec.c > @@ -0,0 +1,242 @@ > +/* > + * QEMU SPAPR Architecture Option Vector Helper Functions > + * > + * Copyright IBM Corp. 2016 > + * > + * Authors: > + * Bharata B Rao <bhar...@linux.vnet.ibm.com> > + * Michael Roth <mdr...@linux.vnet.ibm.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + */ > + > +#include "qemu/osdep.h" > +#include "hw/ppc/spapr_ovec.h" > +#include "qemu/bitmap.h" > +#include "exec/address-spaces.h" > +#include "qemu/error-report.h" > +#include <libfdt.h> > + > +/* #define DEBUG_SPAPR_OVEC */ > + > +#ifdef DEBUG_SPAPR_OVEC > +#define DPRINTFN(fmt, ...) \ > + do { fprintf(stderr, fmt "\n", ## __VA_ARGS__); } while (0) > +#else > +#define DPRINTFN(fmt, ...) \ > + do { } while (0) > +#endif > + > +#define OV_MAXBYTES 256 /* not including length byte */ > +#define OV_MAXBITS (OV_MAXBYTES * BITS_PER_BYTE) > + > +/* we *could* work with bitmaps directly, but handling the bitmap privately > + * allows us to more safely make assumptions about the bitmap size and > + * simplify the calling code somewhat > + */ > +struct sPAPROptionVector { > + unsigned long *bitmap; > +}; > + > +sPAPROptionVector *spapr_ovec_new(void) > +{ > + sPAPROptionVector *ov; > + > + ov = g_new0(sPAPROptionVector, 1); > + ov->bitmap = bitmap_new(OV_MAXBITS); > + > + return ov; > +} > + > +sPAPROptionVector *spapr_ovec_clone(sPAPROptionVector *ov_orig) > +{ > + sPAPROptionVector *ov; > + > + g_assert(ov_orig); > + > + ov = spapr_ovec_new(); > + bitmap_copy(ov->bitmap, ov_orig->bitmap, OV_MAXBITS); > + > + return ov; > +} > + > +void spapr_ovec_intersect(sPAPROptionVector *ov, > + sPAPROptionVector *ov1, > + sPAPROptionVector *ov2) > +{ > + g_assert(ov); > + g_assert(ov1); > + g_assert(ov2); > + > + bitmap_and(ov->bitmap, ov1->bitmap, ov2->bitmap, OV_MAXBITS); > +} > + > +/* returns true if options bits were removed, false otherwise */ > +bool spapr_ovec_diff(sPAPROptionVector *ov, > + sPAPROptionVector *ov_old, > + sPAPROptionVector *ov_new) > +{ > + unsigned long *change_mask = bitmap_new(OV_MAXBITS); > + unsigned long *removed_bits = bitmap_new(OV_MAXBITS); > + bool bits_were_removed = false; > + > + g_assert(ov); > + g_assert(ov_old); > + g_assert(ov_new); > + > + bitmap_xor(change_mask, ov_old->bitmap, ov_new->bitmap, OV_MAXBITS); > + bitmap_and(ov->bitmap, ov_new->bitmap, change_mask, OV_MAXBITS); > + bitmap_and(removed_bits, ov_old->bitmap, change_mask, OV_MAXBITS); > + > + if (!bitmap_empty(removed_bits, OV_MAXBITS)) { > + bits_were_removed = true; > + } > + > + g_free(change_mask); > + g_free(removed_bits); > + > + return bits_were_removed; > +} > + > +void spapr_ovec_cleanup(sPAPROptionVector *ov) > +{ > + if (ov) { > + g_free(ov->bitmap); > + g_free(ov); > + } > +} > + > +void spapr_ovec_set(sPAPROptionVector *ov, long bitnr) > +{ > + g_assert(ov); > + g_assert_cmpint(bitnr, <, OV_MAXBITS); > + > + set_bit(bitnr, ov->bitmap); > +} > + > +void spapr_ovec_clear(sPAPROptionVector *ov, long bitnr) > +{ > + g_assert(ov); > + g_assert_cmpint(bitnr, <, OV_MAXBITS); > + > + clear_bit(bitnr, ov->bitmap); > +} > + > +bool spapr_ovec_test(sPAPROptionVector *ov, long bitnr) > +{ > + g_assert(ov); > + g_assert_cmpint(bitnr, <, OV_MAXBITS); > + > + return test_bit(bitnr, ov->bitmap) ? true : false; > +} > + > +static void guest_byte_to_bitmap(uint8_t entry, unsigned long *bitmap, > + long bitmap_offset) > +{ > + int i; > + > + for (i = 0; i < BITS_PER_BYTE; i++) { > + if (entry & (1 << (BITS_PER_BYTE - 1 - i))) { > + bitmap_set(bitmap, bitmap_offset + i, 1); > + } > + } > +} > + > +static uint8_t guest_byte_from_bitmap(unsigned long *bitmap, long > bitmap_offset) > +{ > + uint8_t entry = 0; > + int i; > + > + for (i = 0; i < BITS_PER_BYTE; i++) { > + if (test_bit(bitmap_offset + i, bitmap)) { > + entry |= (1 << (BITS_PER_BYTE - 1 - i)); > + } > + } > + > + return entry; > +} > + > +static target_ulong vector_addr(target_ulong table_addr, int vector) > +{ > + uint16_t vector_count, vector_len; > + int i; > + > + vector_count = ldub_phys(&address_space_memory, table_addr) + 1; > + if (vector > vector_count) { > + return 0; > + } > + table_addr++; /* skip nr option vectors */ > + > + for (i = 0; i < vector - 1; i++) { > + vector_len = ldub_phys(&address_space_memory, table_addr) + 1; > + table_addr += vector_len + 1; /* bit-vector + length byte */ > + } > + return table_addr; > +} > + > +sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int > vector) > +{ > + sPAPROptionVector *ov; > + target_ulong addr; > + uint16_t vector_len; > + int i; > + > + g_assert(table_addr); > + g_assert_cmpint(vector, >=, 1); /* vector numbering starts at 1 */ > + > + addr = vector_addr(table_addr, vector); > + if (!addr) { > + /* specified vector isn't present */ > + return NULL; > + } > + > + vector_len = ldub_phys(&address_space_memory, addr++) + 1; > + g_assert_cmpint(vector_len, <=, OV_MAXBYTES); > + ov = spapr_ovec_new(); > + > + for (i = 0; i < vector_len; i++) { > + uint8_t entry = ldub_phys(&address_space_memory, addr + i); > + if (entry) { > + DPRINTFN("read guest vector %2d, byte %3d / %3d: 0x%.2x", > + vector, i + 1, vector_len, entry); > + guest_byte_to_bitmap(entry, ov->bitmap, i * BITS_PER_BYTE); > + } > + } > + > + return ov; > +} > + > +int spapr_ovec_populate_dt(void *fdt, int fdt_offset, > + sPAPROptionVector *ov, const char *name) > +{ > + uint8_t vec[OV_MAXBYTES + 1]; > + uint16_t vec_len; > + unsigned long lastbit; > + int i; > + > + g_assert(ov); > + > + lastbit = find_last_bit(ov->bitmap, OV_MAXBITS); > + /* if no bits are set, include at least 1 byte of the vector so we can > + * still encoded this in the device tree while abiding by the same > + * encoding/sizing expected in ibm,client-architecture-support > + */ > + vec_len = (lastbit == OV_MAXBITS) ? 1 : lastbit / BITS_PER_BYTE + 1; > + g_assert_cmpint(vec_len, <=, OV_MAXBYTES); > + /* guest expects vector len encoded as vec_len - 1, since the length byte > + * is assumed and not included, and the first byte of the vector > + * is assumed as well > + */ > + vec[0] = vec_len - 1; > + > + for (i = 1; i < vec_len + 1; i++) { > + vec[i] = guest_byte_from_bitmap(ov->bitmap, (i - 1) * BITS_PER_BYTE); > + if (vec[i]) { > + DPRINTFN("encoding guest vector byte %3d / %3d: 0x%.2x", > + i, vec_len, vec[i]); > + } > + } > + > + return fdt_setprop(fdt, fdt_offset, name, vec, vec_len); > +} > diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h > new file mode 100644 > index 0000000..fba2d98 > --- /dev/null > +++ b/include/hw/ppc/spapr_ovec.h > @@ -0,0 +1,62 @@ > +/* > + * QEMU SPAPR Option/Architecture Vector Definitions > + * > + * Each architecture option is organized/documented by the following > + * in LoPAPR 1.1, Table 244: > + * > + * <vector number>: the bit-vector in which the option is located > + * <vector byte>: the byte offset of the vector entry > + * <vector bit>: the bit offset within the vector entry > + * > + * where each vector entry can be one or more bytes. > + * > + * Firmware expects a somewhat literal encoding of this bit-vector > + * structure, where each entry is stored in little-endian so that the > + * byte ordering reflects that of the documentation, but where each bit > + * offset is from "left-to-right" in the traditional representation of > + * a byte value where the MSB is the left-most bit. Thus, each > + * individual byte encodes the option bits in reverse order of the > + * documented bit. > + * > + * These definitions/helpers attempt to abstract away this internal > + * representation so that we can define/set/test for individual option > + * bits using only the documented values. This is done mainly by relying > + * on a bitmap to approximate the documented "bit-vector" structure and > + * handling conversations to-from the internal representation under the > + * covers. > + * > + * Copyright IBM Corp. 2016 > + * > + * Authors: > + * Michael Roth <mdr...@linux.vnet.ibm.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + */ > +#if !defined(__HW_SPAPR_OPTION_VECTORS_H__) > +#define __HW_SPAPR_OPTION_VECTORS_H__ > + > +#include "cpu.h" > + > +typedef struct sPAPROptionVector sPAPROptionVector; > + > +#define OV_BIT(byte, bit) ((byte - 1) * BITS_PER_BYTE + bit) > + > +/* interfaces */ > +sPAPROptionVector *spapr_ovec_new(void); > +sPAPROptionVector *spapr_ovec_clone(sPAPROptionVector *ov_orig); > +void spapr_ovec_intersect(sPAPROptionVector *ov, > + sPAPROptionVector *ov1, > + sPAPROptionVector *ov2); > +bool spapr_ovec_diff(sPAPROptionVector *ov, > + sPAPROptionVector *ov_old, > + sPAPROptionVector *ov_new); > +void spapr_ovec_cleanup(sPAPROptionVector *ov); > +void spapr_ovec_set(sPAPROptionVector *ov, long bitnr); > +void spapr_ovec_clear(sPAPROptionVector *ov, long bitnr); > +bool spapr_ovec_test(sPAPROptionVector *ov, long bitnr); > +sPAPROptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int > vector); > +int spapr_ovec_populate_dt(void *fdt, int fdt_offset, > + sPAPROptionVector *ov, const char *name); > + > +#endif /* !defined (__HW_SPAPR_OPTION_VECTORS_H__) */ -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature