[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC XEN PATCH 11/16] tools/libacpi: load ACPI built by the device model
On Mon, Oct 10, 2016 at 08:32:30AM +0800, Haozhong Zhang wrote: > ACPI tables built by the device model, whose signatures do not > conflict with tables built by Xen (except SSDT), are loaded after ACPI > tables built by Xen. > > ACPI namespace devices built by the device model, whose names do not > conflict with devices built by Xen, are assembled and placed in SSDTs > after ACPI tables built by Xen. > > Signed-off-by: Haozhong Zhang <haozhong.zhang@xxxxxxxxx> > --- > Cc: Jan Beulich <jbeulich@xxxxxxxx> > Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> > Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> > Cc: Wei Liu <wei.liu2@xxxxxxxxxx> > --- > tools/firmware/hvmloader/util.c | 12 +++ > tools/libacpi/acpi2_0.h | 2 + > tools/libacpi/build.c | 216 > ++++++++++++++++++++++++++++++++++++++++ > tools/libacpi/libacpi.h | 5 + > 4 files changed, 235 insertions(+) > > diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c > index dba954a..e6530cd 100644 > --- a/tools/firmware/hvmloader/util.c > +++ b/tools/firmware/hvmloader/util.c > @@ -998,6 +998,18 @@ void hvmloader_acpi_build_tables(struct acpi_config > *config, > if ( !strncmp(xenstore_read("platform/acpi_s4", "1"), "1", 1) ) > config->table_flags |= ACPI_HAS_SSDT_S4; > > + s = xenstore_read(HVM_XS_DM_ACPI_ADDRESS, NULL); > + if ( s ) > + { > + config->dm.addr = strtoll(s, NULL, 0); > + > + s = xenstore_read(HVM_XS_DM_ACPI_LENGTH, NULL); > + if ( s ) > + config->dm.length = strtoll(s, NULL, 0); > + else > + config->dm.addr = 0; > + } > + > config->table_flags |= (ACPI_HAS_TCPA | ACPI_HAS_IOAPIC | ACPI_HAS_WAET); > > config->tis_hdr = (uint16_t *)ACPI_TIS_HDR_ADDRESS; > diff --git a/tools/libacpi/acpi2_0.h b/tools/libacpi/acpi2_0.h > index 775eb7a..7414470 100644 > --- a/tools/libacpi/acpi2_0.h > +++ b/tools/libacpi/acpi2_0.h > @@ -430,6 +430,7 @@ struct acpi_20_slit { > #define ACPI_2_0_WAET_SIGNATURE ASCII32('W','A','E','T') > #define ACPI_2_0_SRAT_SIGNATURE ASCII32('S','R','A','T') > #define ACPI_2_0_SLIT_SIGNATURE ASCII32('S','L','I','T') > +#define ACPI_2_0_SSDT_SIGNATURE ASCII32('S','S','D','T') > > /* > * Table revision numbers. > @@ -445,6 +446,7 @@ struct acpi_20_slit { > #define ACPI_1_0_FADT_REVISION 0x01 > #define ACPI_2_0_SRAT_REVISION 0x01 > #define ACPI_2_0_SLIT_REVISION 0x01 > +#define ACPI_2_0_SSDT_REVISION 0x02 > > #pragma pack () > > diff --git a/tools/libacpi/build.c b/tools/libacpi/build.c > index 47dae01..829a365 100644 > --- a/tools/libacpi/build.c > +++ b/tools/libacpi/build.c > @@ -20,6 +20,7 @@ > #include "ssdt_s4.h" > #include "ssdt_tpm.h" > #include "ssdt_pm.h" > +#include "aml_build.h" > #include <xen/hvm/hvm_info_table.h> > #include <xen/hvm/hvm_xs_strings.h> > #include <xen/hvm/params.h> > @@ -55,6 +56,34 @@ struct acpi_info { > uint64_t pci_hi_min, pci_hi_len; /* 24, 32 - PCI I/O hole boundaries */ > }; > > +#define DM_ACPI_BLOB_TYPE_TABLE 0 /* ACPI table */ > +#define DM_ACPI_BLOB_TYPE_NSDEV 1 /* AML definition of an ACPI namespace > device */ > + > +/* ACPI tables of following signatures should not appear in DM ACPI */ It would be good to have some form of build check to check against this list.. > +static const uint64_t dm_acpi_signature_blacklist[] = { > + ACPI_2_0_RSDP_SIGNATURE, > + ACPI_2_0_FACS_SIGNATURE, > + ACPI_2_0_FADT_SIGNATURE, > + ACPI_2_0_MADT_SIGNATURE, > + ACPI_2_0_RSDT_SIGNATURE, > + ACPI_2_0_XSDT_SIGNATURE, > + ACPI_2_0_TCPA_SIGNATURE, > + ACPI_2_0_HPET_SIGNATURE, > + ACPI_2_0_WAET_SIGNATURE, > + ACPI_2_0_SRAT_SIGNATURE, > + ACPI_2_0_SLIT_SIGNATURE, > +}; > + > +/* ACPI namespace devices of following names should not appear in DM ACPI */ > +static const char *dm_acpi_devname_blacklist[] = { > + "MEM0", > + "PCI0", > + "AC", > + "BAT0", > + "BAT1", > + "TPM", .. and this one. But I am not even sure how one would do that? Perhaps add a big warning: "Make sure to add your table name if you this code (libacpi) is constructing it. "? Or maybe have some 'register_acpi_table' function which will expand this blacklist? > +}; > + > static void set_checksum( > void *table, uint32_t checksum_offset, uint32_t length) > { > @@ -339,6 +368,190 @@ static int construct_passthrough_tables(struct > acpi_ctxt *ctxt, > return nr_added; > } > > +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) That may want to go libacpi.h ? > + > +static int check_signature_collision(uint64_t sig) bool > +{ > + int i; unsigned int > + for ( i = 0; i < ARRAY_SIZE(dm_acpi_signature_blacklist); i++ ) > + { > + if ( sig == dm_acpi_signature_blacklist[i] ) > + return 1; return true > + } > + return 0; > +} > + > +static int check_devname_collision(const char *name) bool > +{ > + int i; unsigned int > + for ( i = 0; i < ARRAY_SIZE(dm_acpi_devname_blacklist); i++ ) > + { > + if ( !strncmp(name, dm_acpi_devname_blacklist[i], 4) ) That 4 could be a #define > + return 1; > + } > + return 0; > +} > + > +static const char *xs_read_dm_acpi_blob_key(struct acpi_ctxt *ctxt, > + const char *name, const char > *key) > +{ > +#define DM_ACPI_BLOB_PATH_MAX_LENGTH 30 > + char path[DM_ACPI_BLOB_PATH_MAX_LENGTH]; > + snprintf(path, DM_ACPI_BLOB_PATH_MAX_LENGTH, HVM_XS_DM_ACPI_ROOT"/%s/%s", > + name, key); > + return ctxt->xs_ops.read(ctxt, path); #undef DM_APCI_BLOB... but perhaps that should go in xen/include/public/hvm/hvm_xs_strings.h ? > +} > + > +static int construct_dm_table(struct acpi_ctxt *ctxt, bool > + unsigned long *table_ptrs, int nr_tables, unsigned int nr_tables > + const void *blob, uint32_t length) > +{ > + const struct acpi_header *header = blob; > + uint8_t *buffer; > + > + if ( check_signature_collision(header->signature) ) > + return 0; > + > + if ( header->length > length || header->length == 0 ) > + return 0; > + > + buffer = ctxt->mem_ops.alloc(ctxt, header->length, 16); > + if ( !buffer ) > + return 0; > + memcpy(buffer, header, header->length); > + > + /* some device models (e.g. QEMU) does not set checksum */ > + set_checksum(buffer, offsetof(struct acpi_header, checksum), > + header->length); > + > + table_ptrs[nr_tables++] = ctxt->mem_ops.v2p(ctxt, buffer); > + > + return 1; > +} > + > +static int construct_dm_nsdev(struct acpi_ctxt *ctxt, bool > + unsigned long *table_ptrs, int nr_tables, unsigned int > + const char *dev_name, > + const void *blob, uint32_t blob_length) > +{ > + struct acpi_header ssdt, *header; > + uint8_t *buffer; > + > + if ( check_devname_collision(dev_name) ) > + return 0; > + > + /* built ACPI namespace device from [name, blob] */ > + buffer = aml_build_begin(ctxt); > + aml_prepend_blob(buffer, blob, blob_length); > + aml_prepend_device(buffer, dev_name); > + aml_prepend_scope(buffer, "\\_SB"); > + > + /* build SSDT header */ > + ssdt.signature = ACPI_2_0_SSDT_SIGNATURE; > + ssdt.revision = ACPI_2_0_SSDT_REVISION; > + fixed_strcpy(ssdt.oem_id, ACPI_OEM_ID); > + fixed_strcpy(ssdt.oem_table_id, ACPI_OEM_TABLE_ID); > + ssdt.oem_revision = ACPI_OEM_REVISION; > + ssdt.creator_id = ACPI_CREATOR_ID; > + ssdt.creator_revision = ACPI_CREATOR_REVISION; > + > + /* prepend SSDT header to ACPI namespace device */ > + aml_prepend_blob(buffer, &ssdt, sizeof(ssdt)); > + header = (struct acpi_header *) buffer; > + header->length = aml_build_end(); > + > + /* calculate checksum of SSDT */ > + set_checksum(header, offsetof(struct acpi_header, checksum), > + header->length); > + > + table_ptrs[nr_tables++] = ctxt->mem_ops.v2p(ctxt, buffer); > + > + return 1; return true. > +} > + > +/* > + * All ACPI stuffs built by the device model are placed in the guest > + * buffer whose address and size are specified by config->dm.{addr, length}, > + * or XenStore keys HVM_XS_DM_ACPI_{ADDRESS, LENGTH}. This should be also provided in xen/include/public/hvm/hvm_xs_strings.h Especially as you are in effect adding new keys and attributes to it. > + * > + * The data layout within the buffer is further specified by XenStore > + * directories under HVM_XS_DM_ACPI_ROOT. Each directory specifies a Is each directory the name of the DSDT object? In which case you want to say a bit about the directory name and the limit (only four characters long), don't use the ones that are built-in, etc.. But it looks like it can be anything. You extract the name from the blob. But we should still say what the directory names ought to be. > + * data blob and contains following XenStore keys: > + * > + * - "type": > + * * DM_ACPI_BLOB_TYPE_TABLE > + * The data blob specified by this directory is an ACPI table. > + * * DM_ACPI_BLOB_TYPE_NSDEV > + * The data blob specified by this directory is an ACPI namespace device. > + * Its name is specified by the directory name, while the AML code of the > + * body of the AML device structure is in the data blob. Could those be strings on XenStore? Strings are nice. "table" or "nsdev"? > + * > + * - "length": the number of bytes in this data blob. > + * > + * - "offset": the offset in bytes of this data blob from the beginning of > buffer > + */ > +static int construct_dm_tables(struct acpi_ctxt *ctxt, static unsigned int > + unsigned long *table_ptrs, > + int nr_tables, unsigned int nr_tables > + struct acpi_config *config) > +{ > + const char *s; > + char **dir; > + uint8_t type; > + void *blob; > + unsigned int num, length, offset, i; > + int nr_added = 0; unsigned int > + > + if ( !config->dm.addr ) > + return 0; > + > + dir = ctxt->xs_ops.directory(ctxt, HVM_XS_DM_ACPI_ROOT, &num); > + if ( !dir || !num ) > + return 0; > + > + if ( num > ACPI_MAX_SECONDARY_TABLES - nr_tables ) > + return 0; > + > + for ( i = 0; i < num; i++, dir++ ) > + { You probably want to check that *dir is not NULL. Just in case. > + s = xs_read_dm_acpi_blob_key(ctxt, *dir, "type"); > + if ( !s ) > + continue; > + type = (uint8_t)strtoll(s, NULL, 0); > + > + s = xs_read_dm_acpi_blob_key(ctxt, *dir, "length"); > + if ( !s ) > + continue; > + length = (uint32_t)strtoll(s, NULL, 0); > + > + s = xs_read_dm_acpi_blob_key(ctxt, *dir, "offset"); > + if ( !s ) > + continue; > + offset = (uint32_t)strtoll(s, NULL, 0); > + > + blob = ctxt->mem_ops.p2v(ctxt, config->dm.addr + offset); > + > + switch ( type ) > + { > + case DM_ACPI_BLOB_TYPE_TABLE: > + nr_added += construct_dm_table(ctxt, > + table_ptrs, nr_tables + nr_added, > + blob, length); > + break; > + case DM_ACPI_BLOB_TYPE_NSDEV: > + nr_added += construct_dm_nsdev(ctxt, > + table_ptrs, nr_tables + nr_added, > + *dir, blob, length); > + break; > + default: > + /* skip blobs of unknown types */ > + continue; > + } > + } > + > + return nr_added; > +} > + > static int construct_secondary_tables(struct acpi_ctxt *ctxt, > unsigned long *table_ptrs, > struct acpi_config *config, > @@ -461,6 +674,9 @@ static int construct_secondary_tables(struct acpi_ctxt > *ctxt, > nr_tables += construct_passthrough_tables(ctxt, table_ptrs, > nr_tables, config); > > + /* Load any additional tables passed from device model (e.g. QEMU) */ Perhaps an period at the end of the sentence? > + nr_tables += construct_dm_tables(ctxt, table_ptrs, nr_tables, config); > + > table_ptrs[nr_tables] = 0; > return nr_tables; > } > diff --git a/tools/libacpi/libacpi.h b/tools/libacpi/libacpi.h > index 12cafd8..684502d 100644 > --- a/tools/libacpi/libacpi.h > +++ b/tools/libacpi/libacpi.h > @@ -82,6 +82,11 @@ struct acpi_config { > uint32_t length; > } pt; > > + struct { > + uint32_t addr; > + uint32_t length; > + } dm; > + > struct acpi_numa numa; > const struct hvm_info_table *hvminfo; > > -- > 2.10.1 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxx > https://lists.xen.org/xen-devel _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |