bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v3 gnumach] ACPI: Support XSDT (ACPI >= v2.0)


From: Samuel Thibault
Subject: Re: [PATCH v3 gnumach] ACPI: Support XSDT (ACPI >= v2.0)
Date: Thu, 1 Feb 2024 02:22:52 +0100
User-agent: NeoMutt/20170609 (1.8.3)

Applied, thanks!

Damien Zammit, le mer. 31 janv. 2024 02:12:26 +0000, a ecrit:
> This enables gnumach to additionally parse the XSDT table
> if the revision of ACPI is 2.
> 
> TESTED: Still works on qemu (ACPI v1.0)
> TESTED: Works on a x86 board with XSDT (ACPI v2.0)
> ---
>  i386/i386at/acpi_parse_apic.c | 258 ++++++++++++++++++++++------------
>  i386/i386at/acpi_parse_apic.h |  18 ++-
>  i386/i386at/model_dep.c       |   8 +-
>  3 files changed, 195 insertions(+), 89 deletions(-)
> 
> diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
> index 1aef53ed..dcd5da89 100644
> --- a/i386/i386at/acpi_parse_apic.c
> +++ b/i386/i386at/acpi_parse_apic.c
> @@ -43,13 +43,12 @@ unsigned lapic_addr;
>   * and the number of entries stored in RSDT.
>   */
>  void
> -acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int 
> acpi_rsdt_n)
> +acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n)
>  {
>  
>      printf("ACPI:\n");
> -    printf(" rsdp = %p; rsdp->rsdt_addr = %x\n", rsdp, rsdp->rsdt_addr);
> -    printf(" rsdt = %p; rsdt->length = %x (n = %x)\n", rsdt, 
> rsdt->header.length,
> -           acpi_rsdt_n);
> +    printf(" rsdp = 0x%lx\n", rsdp);
> +    printf(" rsdt/xsdt = 0x%p (n = %d)\n", rsdt, acpi_rsdt_n);
>  }
>  
>  /*
> @@ -99,27 +98,45 @@ acpi_check_signature(const uint8_t table_signature[], 
> const char *real_signature
>   *
>   * Preconditions: RSDP pointer must not be NULL.
>   *
> - * Returns 0 if correct.
> + * Returns 1 if ACPI 1.0 and sets sdt_base
> + * Returns 2 if ACPI >= 2.0 and sets sdt_base
>   */
>  static int8_t
> -acpi_check_rsdp(struct acpi_rsdp *rsdp)
> +acpi_check_rsdp(struct acpi_rsdp2 *rsdp, phys_addr_t *sdt_base)
>  {
> -    uint32_t checksum;
>      int is_rsdp;
> +    uint8_t cksum;
>  
>      /* Check if rsdp signature match with the ACPI RSDP signature. */
> -    is_rsdp = acpi_check_signature(rsdp->signature, ACPI_RSDP_SIG, 
> 8*sizeof(uint8_t));
> +    is_rsdp = acpi_check_signature(rsdp->v1.signature, ACPI_RSDP_SIG, 
> 8*sizeof(uint8_t));
>  
>      if (is_rsdp != ACPI_SUCCESS)
>          return ACPI_BAD_SIGNATURE;
>  
> -    /* If match, calculates rdsp checksum and check It. */
> -    checksum = acpi_checksum(rsdp, sizeof(struct acpi_rsdp));
> +    if (rsdp->v1.revision == 0) {
> +        // ACPI 1.0
> +        *sdt_base = rsdp->v1.rsdt_addr;
> +        printf("ACPI v1.0\n");
> +        cksum = acpi_checksum((void *)(&rsdp->v1), sizeof(struct acpi_rsdp));
>  
> -    if (checksum != 0)
> -        return ACPI_BAD_CHECKSUM;
> +        if (cksum != 0)
> +            return ACPI_BAD_CHECKSUM;
>  
> -    return ACPI_SUCCESS;
> +        return 1;
> +
> +    } else if (rsdp->v1.revision == 2) {
> +        // ACPI >= 2.0
> +        *sdt_base = rsdp->xsdt_addr;
> +        printf("ACPI >= v2.0\n");
> +        cksum = acpi_checksum((void *)rsdp, sizeof(struct acpi_rsdp2));
> +
> +        if (cksum != 0)
> +            return ACPI_BAD_CHECKSUM;
> +
> +        return 2;
> +    }
> +
> +    return ACPI_NO_RSDP;
>  }
>  
>  /*
> @@ -147,38 +164,41 @@ acpi_check_rsdp_align(void *addr)
>   *
>   * Preconditions: The start address (addr) must be aligned.
>   *
> - * Returns the reference to rsdp structure if success, NULL if failure.
> + * Returns the physical address of rsdp structure if success, 0 if failure.
>   */
> -static struct acpi_rsdp*
> -acpi_search_rsdp(void *addr, uint32_t length)
> +static phys_addr_t
> +acpi_search_rsdp(void *addr, uint32_t length, int *is_64bit)
>  {
>      void *end;
> +    int version = 0;
> +    phys_addr_t sdt_base = 0;
>  
>      /* Search RDSP in memory space between addr and addr+lenght. */
>      for (end = addr+length; addr < end; addr += ACPI_RSDP_ALIGN) {
>  
>          /* Check if the current memory block stores the RDSP. */
> -        if ((addr != NULL) && (acpi_check_rsdp(addr) == ACPI_SUCCESS)) {
> -            /* If yes, return RSDP address */
> -            return (struct acpi_rsdp*) addr;
> +        if ((addr != NULL) && ((version = acpi_check_rsdp(addr, &sdt_base)) 
> > 0)) {
> +            /* If yes, return RSDT/XSDT address */
> +            *is_64bit = (version == 2);
> +            return sdt_base;
>          }
>      }
>  
> -    return NULL;
> +    return 0;
>  }
>  
>  /*
>   * acpi_get_rsdp: tries to find the RSDP table,
>   * searching It in many memory ranges, as It's written in ACPI Specification.
>   *
> - * Returns the reference to RDSP structure if success, NULL if failure.
> + * Returns the reference to RDSP structure if success, 0 if failure.
>   */
> -static struct acpi_rsdp*
> -acpi_get_rsdp(void)
> +static phys_addr_t
> +acpi_get_rsdp(int *is_64bit)
>  {
>      uint16_t *start = 0;
>      phys_addr_t base = 0;
> -    struct acpi_rsdp *rsdp = NULL;
> +    phys_addr_t rsdp = 0;
>  
>      /* EDBA start address. */
>      start = (uint16_t*) phystokv(0x040e);
> @@ -186,40 +206,17 @@ acpi_get_rsdp(void)
>  
>      /* check alignment. */
>      if (acpi_check_rsdp_align((void *)base) == ACPI_BAD_ALIGN)
> -        return NULL;
> -    rsdp = acpi_search_rsdp((void *)base, 1024);
> +        return 0;
> +    rsdp = acpi_search_rsdp((void *)base, 1024, is_64bit);
>  
> -    if (rsdp == NULL) {
> +    if (rsdp == 0) {
>          /* If RSDP isn't in EDBA, search in the BIOS read-only memory space 
> between 0E0000h and 0FFFFFh */
> -        rsdp = acpi_search_rsdp((void *)phystokv(0xe0000), 0x100000 - 
> 0x0e0000);
> +        rsdp = acpi_search_rsdp((void *)phystokv(0xe0000), 0x100000 - 
> 0x0e0000, is_64bit);
>      }
>  
>      return rsdp;
>  }
>  
> -/*
> - * acpi_check_rsdt: check if the RSDT initial address is correct
> - * checking its checksum.
> - *
> - * Receives as input a reference for the RSDT "candidate" table.
> - * Returns 0 if success.
> - *
> - * Preconditions: rsdp must not be NULL.
> - *
> - */
> -static int
> -acpi_check_rsdt(struct acpi_rsdt *rsdt)
> -{
> -    uint8_t checksum;
> -
> -    checksum = acpi_checksum(rsdt, rsdt->header.length);
> -
> -    if (checksum != 0)
> -        return ACPI_BAD_CHECKSUM;
> -
> -    return ACPI_SUCCESS;
> -}
> -
>  /*
>   * acpi_get_rsdt: Get RSDT table reference from RSDP entries.
>   *
> @@ -229,16 +226,12 @@ acpi_check_rsdt(struct acpi_rsdt *rsdt)
>   * Returns the reference to RSDT table if success, NULL if error.
>   */
>  static struct acpi_rsdt*
> -acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
> +acpi_get_rsdt(phys_addr_t rsdp_phys, int* acpi_rsdt_n)
>  {
> -    phys_addr_t rsdt_phys;
>      struct acpi_rsdt *rsdt = NULL;
> -    int acpi_check;
>      int signature_check;
>  
> -    /* Get rsdt address from rsdp table. */
> -    rsdt_phys = rsdp->rsdt_addr;
> -    rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdt_phys, 
> sizeof(struct acpi_rsdt), VM_PROT_READ);
> +    rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdp_phys, 
> sizeof(struct acpi_rsdt), VM_PROT_READ);
>  
>      /* Check if the RSDT mapping is fine. */
>      if (rsdt == NULL)
> @@ -251,12 +244,6 @@ acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
>      if (signature_check != ACPI_SUCCESS)
>          return NULL;
>  
> -    /* Check if rsdt is correct. */
> -    acpi_check = acpi_check_rsdt(rsdt);
> -
> -    if (acpi_check != ACPI_SUCCESS)
> -        return NULL;
> -
>      /* Calculated number of elements stored in rsdt. */
>      *acpi_rsdt_n = (rsdt->header.length - sizeof(rsdt->header))
>                     / sizeof(rsdt->entry[0]);
> @@ -264,6 +251,40 @@ acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
>      return rsdt;
>  }
>  
> +/*
> + * acpi_get_xsdt: Get XSDT table reference from RSDPv2 entries.
> + *
> + * Receives as input a reference for RSDPv2 table
> + * and a reference to store the number of entries of XSDT.
> + *
> + * Returns the reference to XSDT table if success, NULL if error.
> + */
> +static struct acpi_xsdt*
> +acpi_get_xsdt(phys_addr_t rsdp_phys, int* acpi_xsdt_n)
> +{
> +    struct acpi_xsdt *xsdt = NULL;
> +    int signature_check;
> +
> +    xsdt = (struct acpi_xsdt*) kmem_map_aligned_table(rsdp_phys, 
> sizeof(struct acpi_xsdt), VM_PROT_READ);
> +
> +    /* Check if the RSDT mapping is fine. */
> +    if (xsdt == NULL)
> +        return NULL;
> +
> +    /* Check is rsdt signature is equals to ACPI RSDT signature. */
> +    signature_check = acpi_check_signature(xsdt->header.signature, 
> ACPI_XSDT_SIG,
> +                                           4*sizeof(uint8_t));
> +
> +    if (signature_check != ACPI_SUCCESS)
> +        return NULL;
> +
> +    /* Calculated number of elements stored in rsdt. */
> +    *acpi_xsdt_n = (xsdt->header.length - sizeof(xsdt->header))
> +                   / sizeof(xsdt->entry[0]);
> +
> +    return xsdt;
> +}
> +
>  /*
>   * acpi_get_apic: get MADT/APIC table from RSDT entries.
>   *
> @@ -295,6 +316,37 @@ acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n)
>      return NULL;
>  }
>  
> +/*
> + * acpi_get_apic2: get MADT/APIC table from XSDT entries.
> + *
> + * Receives as input the XSDT initial address,
> + * and the number of entries of XSDT table.
> + *
> + * Returns a reference to APIC/MADT table if success, NULL if failure.
> + */
> +static struct acpi_apic*
> +acpi_get_apic2(struct acpi_xsdt *xsdt, int acpi_xsdt_n)
> +{
> +    struct acpi_dhdr *descr_header;
> +    int check_signature;
> +
> +    /* Search APIC entries in rsdt table. */
> +    for (int i = 0; i < acpi_xsdt_n; i++) {
> +        descr_header = (struct acpi_dhdr*) 
> kmem_map_aligned_table(xsdt->entry[i], sizeof(struct acpi_dhdr),
> +                                                                  
> VM_PROT_READ);
> +
> +        /* Check if the entry contains an APIC. */
> +        check_signature = acpi_check_signature(descr_header->signature, 
> ACPI_APIC_SIG, 4*sizeof(uint8_t));
> +
> +        if (check_signature == ACPI_SUCCESS) {
> +            /* If yes, return the APIC. */
> +            return (struct acpi_apic*) descr_header;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
>  /*
>   * acpi_add_lapic: add a new Local APIC to cpu_to_lapic array
>   * and increase the number of cpus.
> @@ -382,6 +434,8 @@ acpi_apic_parse_table(struct acpi_apic *apic)
>      /* Get the end address of APIC table */
>      end = (vm_offset_t) apic + apic->header.length;
>  
> +    printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
> +
>      /* Initialize number of cpus */
>      numcpus = apic_get_numcpus();
>  
> @@ -391,6 +445,7 @@ acpi_apic_parse_table(struct acpi_apic *apic)
>          struct acpi_apic_ioapic *ioapic_entry;
>          struct acpi_apic_irq_override *irq_override_entry;
>  
> +        printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
>          /* Check entry type. */
>          switch(apic_entry->type) {
>  
> @@ -421,6 +476,9 @@ acpi_apic_parse_table(struct acpi_apic *apic)
>              break;
>  
>          /* FIXME: There is another unhandled case */
> +     default:
> +         printf("Unhandled APIC entry type 0x%x\n", apic_entry->type);
> +         break;
>          }
>  
>          /* Get next APIC entry. */
> @@ -452,16 +510,9 @@ acpi_apic_parse_table(struct acpi_apic *apic)
>  static int
>  acpi_apic_setup(struct acpi_apic *apic)
>  {
> -    int apic_checksum;
>      ApicLocalUnit* lapic_unit;
>      uint8_t ncpus, nioapics;
>  
> -    /* Check the checksum of the APIC */
> -    apic_checksum = acpi_checksum(apic, apic->header.length);
> -
> -    if(apic_checksum != 0)
> -        return ACPI_BAD_CHECKSUM;
> -
>      /* map common lapic address */
>      lapic_addr = apic->lapic_addr;
>      lapic_unit = kmem_map_aligned_table(apic->lapic_addr, 
> sizeof(ApicLocalUnit),
> @@ -502,29 +553,64 @@ acpi_apic_setup(struct acpi_apic *apic)
>  int
>  acpi_apic_init(void)
>  {
> -    struct acpi_rsdp *rsdp = 0;
> +    phys_addr_t rsdp = 0;
>      struct acpi_rsdt *rsdt = 0;
> +    struct acpi_xsdt *xsdt = 0;
>      int acpi_rsdt_n;
>      int ret_acpi_setup;
>      int apic_init_success = 0;
> +    int is_64bit = 0;
> +    uint8_t checksum;
>  
> -    /* Try to get the RSDP pointer. */
> -    rsdp = acpi_get_rsdp();
> -    if (rsdp == NULL)
> +    /* Try to get the RSDP physical address. */
> +    rsdp = acpi_get_rsdp(&is_64bit);
> +    if (rsdp == 0)
>          return ACPI_NO_RSDP;
>  
> -    /* Try to get the RSDT pointer. */
> -    rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
> -    if (rsdt == NULL)
> -        return ACPI_NO_RSDT;
> -
> -    /* Try to get the APIC table pointer. */
> -    apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
> -    if (apic_madt == NULL)
> -        return ACPI_NO_APIC;
> -
> -    /* Print the ACPI tables addresses. */
> -    acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
> +    if (!is_64bit) {
> +        /* Try to get the RSDT pointer. */
> +        rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
> +        if (rsdt == NULL)
> +            return ACPI_NO_RSDT;
> +
> +        checksum = acpi_checksum((void *)rsdt, rsdt->header.length);
> +        if (checksum != 0)
> +            return ACPI_BAD_CHECKSUM;
> +
> +        /* Try to get the APIC table pointer. */
> +        apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
> +        if (apic_madt == NULL)
> +            return ACPI_NO_APIC;
> +
> +        checksum = acpi_checksum((void *)apic_madt, 
> apic_madt->header.length);
> +        if (checksum != 0)
> +            return ACPI_BAD_CHECKSUM;
> +
> +        /* Print the ACPI tables addresses. */
> +        acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
> +
> +    } else {
> +     /* Try to get the XSDT pointer. */
> +        xsdt = acpi_get_xsdt(rsdp, &acpi_rsdt_n);
> +        if (xsdt == NULL)
> +            return ACPI_NO_RSDT;
> +
> +        checksum = acpi_checksum((void *)xsdt, xsdt->header.length);
> +        if (checksum != 0)
> +            return ACPI_BAD_CHECKSUM;
> +
> +        /* Try to get the APIC table pointer. */
> +        apic_madt = acpi_get_apic2(xsdt, acpi_rsdt_n);
> +        if (apic_madt == NULL)
> +            return ACPI_NO_APIC;
> +
> +        checksum = acpi_checksum((void *)apic_madt, 
> apic_madt->header.length);
> +        if (checksum != 0)
> +            return ACPI_BAD_CHECKSUM;
> +
> +        /* Print the ACPI tables addresses. */
> +        acpi_print_info(rsdp, xsdt, acpi_rsdt_n);
> +    }
>  
>      apic_init_success = apic_data_init();
>      if (apic_init_success != ACPI_SUCCESS)
> diff --git a/i386/i386at/acpi_parse_apic.h b/i386/i386at/acpi_parse_apic.h
> index bad10054..df36bb31 100644
> --- a/i386/i386at/acpi_parse_apic.h
> +++ b/i386/i386at/acpi_parse_apic.h
> @@ -44,10 +44,17 @@ struct acpi_rsdp {
>      uint8_t          signature[8];
>      uint8_t          checksum;
>      uint8_t          oem_id[6];
> -    uint8_t          revision[1];
> +    uint8_t          revision;
>      uint32_t         rsdt_addr;
>  } __attribute__((__packed__));
>  
> +struct acpi_rsdp2 {
> +    struct acpi_rsdp v1;
> +    uint32_t length;
> +    uint64_t xsdt_addr;
> +    uint8_t  checksum;
> +    uint8_t  reserved[3];
> +} __attribute__((__packed__));
>  
>  /*
>   * RSDT Entry Header
> @@ -77,6 +84,13 @@ struct acpi_rsdt {
>      uint32_t                         entry[0];
>  } __attribute__((__packed__));
>  
> +#define ACPI_XSDT_SIG "XSDT"
> +
> +struct acpi_xsdt {
> +    struct acpi_dhdr         header;
> +    uint64_t                         entry[0];
> +} __attribute__((__packed__));
> +
>  /* APIC table signature. */
>  #define ACPI_APIC_SIG "APIC"
>  
> @@ -157,7 +171,7 @@ struct acpi_apic_irq_override {
>  } __attribute__((__packed__));
>  
>  int acpi_apic_init(void);
> -void acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int 
> acpi_rsdt_n);
> +void acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n);
>  
>  extern unsigned lapic_addr;
>  
> diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
> index fb95029f..a53556e7 100644
> --- a/i386/i386at/model_dep.c
> +++ b/i386/i386at/model_dep.c
> @@ -163,7 +163,13 @@ void machine_init(void)
>       hyp_init();
>  #else        /* MACH_HYP */
>  #if defined(APIC)
> -     acpi_apic_init();
> +     int err;
> +
> +     err = acpi_apic_init();
> +     if (err) {
> +             printf("acpi_apic_init failed with %d\n", err);
> +             for (;;);
> +     }
>  #endif
>  #if (NCPUS > 1)
>       smp_init();
> -- 
> 2.43.0
> 
> 
> 

-- 
Samuel
---
Pour une évaluation indépendante, transparente et rigoureuse !
Je soutiens la Commission d'Évaluation de l'Inria.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]