[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.