mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 15:26:57 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			315 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* acpi.c  - Display acpi tables.  */
 | |
| /*
 | |
|  *  GRUB  --  GRand Unified Bootloader
 | |
|  *  Copyright (C) 2008  Free Software Foundation, Inc.
 | |
|  *
 | |
|  *  GRUB is free software: you can redistribute it and/or modify
 | |
|  *  it under the terms of the GNU General Public License as published by
 | |
|  *  the Free Software Foundation, either version 3 of the License, or
 | |
|  *  (at your option) any later version.
 | |
|  *
 | |
|  *  GRUB is distributed in the hope that it will be useful,
 | |
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  *  GNU General Public License for more details.
 | |
|  *
 | |
|  *  You should have received a copy of the GNU General Public License
 | |
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| #include <grub/types.h>
 | |
| #include <grub/mm.h>
 | |
| #include <grub/misc.h>
 | |
| #include <grub/normal.h>
 | |
| #include <grub/acpi.h>
 | |
| #include <grub/extcmd.h>
 | |
| #include <grub/i18n.h>
 | |
| #include <grub/dl.h>
 | |
| 
 | |
| #pragma GCC diagnostic ignored "-Wcast-align"
 | |
| 
 | |
| GRUB_MOD_LICENSE ("GPLv3+");
 | |
| 
 | |
| static void
 | |
| print_strn (grub_uint8_t *str, grub_size_t len)
 | |
| {
 | |
|   for (; *str && len; str++, len--)
 | |
|     grub_printf ("%c", *str);
 | |
|   for (len++; len; len--)
 | |
|     grub_printf (" ");  
 | |
| }
 | |
| 
 | |
| #define print_field(x) print_strn(x, sizeof (x))
 | |
| 
 | |
| static void
 | |
| disp_acpi_table (struct grub_acpi_table_header *t)
 | |
| {
 | |
|   print_field (t->signature);
 | |
|   grub_printf ("%4" PRIuGRUB_UINT32_T "B rev=%u chksum=0x%02x (%s) OEM=", t->length, t->revision, t->checksum,
 | |
| 	       grub_byte_checksum (t, t->length) == 0 ? "valid" : "invalid");
 | |
|   print_field (t->oemid);
 | |
|   print_field (t->oemtable);
 | |
|   grub_printf ("OEMrev=%08" PRIxGRUB_UINT32_T " ", t->oemrev);
 | |
|   print_field (t->creator_id);
 | |
|   grub_printf (" %08" PRIxGRUB_UINT32_T "\n", t->creator_rev);
 | |
| }
 | |
| 
 | |
| static void
 | |
| disp_madt_table (struct grub_acpi_madt *t)
 | |
| {
 | |
|   struct grub_acpi_madt_entry_header *d;
 | |
|   grub_uint32_t len;
 | |
| 
 | |
|   disp_acpi_table (&t->hdr);
 | |
|   grub_printf ("Local APIC=%08" PRIxGRUB_UINT32_T "  Flags=%08"
 | |
| 	       PRIxGRUB_UINT32_T "\n",
 | |
| 	       t->lapic_addr, t->flags);
 | |
|   len = t->hdr.length - sizeof (struct grub_acpi_madt);
 | |
|   d = t->entries;
 | |
|   for (;len > 0; len -= d->len, d = (void *) ((grub_uint8_t *) d + d->len))
 | |
|     {
 | |
|       switch (d->type)
 | |
| 	{
 | |
| 	case GRUB_ACPI_MADT_ENTRY_TYPE_LAPIC:
 | |
| 	  {
 | |
| 	    struct grub_acpi_madt_entry_lapic *dt = (void *) d;
 | |
| 	    grub_printf ("  LAPIC ACPI_ID=%02x APIC_ID=%02x Flags=%08x\n",
 | |
| 			 dt->acpiid, dt->apicid, dt->flags);
 | |
| 	    if (dt->hdr.len != sizeof (*dt))
 | |
| 	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
 | |
| 			   (int) sizeof (*dt));
 | |
| 	    break;
 | |
| 	  }
 | |
| 
 | |
| 	case GRUB_ACPI_MADT_ENTRY_TYPE_IOAPIC:
 | |
| 	  {
 | |
| 	    struct grub_acpi_madt_entry_ioapic *dt = (void *) d;
 | |
| 	    grub_printf ("  IOAPIC ID=%02x address=%08x GSI=%08x\n",
 | |
| 			 dt->id, dt->address, dt->global_sys_interrupt);
 | |
| 	    if (dt->hdr.len != sizeof (*dt))
 | |
| 	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
 | |
| 			   (int) sizeof (*dt));
 | |
| 	    if (dt->pad)
 | |
| 	      grub_printf ("   non-zero pad: %02x\n", dt->pad);
 | |
| 	    break;
 | |
| 	  }
 | |
| 
 | |
| 	case GRUB_ACPI_MADT_ENTRY_TYPE_INTERRUPT_OVERRIDE:
 | |
| 	  {
 | |
| 	    struct grub_acpi_madt_entry_interrupt_override *dt = (void *) d;
 | |
| 	    grub_printf ("  Int Override bus=%x src=%x GSI=%08x Flags=%04x\n",
 | |
| 			 dt->bus, dt->source, dt->global_sys_interrupt,
 | |
| 			 dt->flags);
 | |
| 	    if (dt->hdr.len != sizeof (*dt))
 | |
| 	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
 | |
| 			   (int) sizeof (*dt));
 | |
| 	  }
 | |
| 	  break;
 | |
| 
 | |
| 	case GRUB_ACPI_MADT_ENTRY_TYPE_LAPIC_NMI:
 | |
| 	  {
 | |
| 	    struct grub_acpi_madt_entry_lapic_nmi *dt = (void *) d;
 | |
| 	    grub_printf ("  LAPIC_NMI ACPI_ID=%02x Flags=%04x lint=%02x\n",
 | |
| 			 dt->acpiid, dt->flags, dt->lint);
 | |
| 	    if (dt->hdr.len != sizeof (*dt))
 | |
| 	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
 | |
| 			   (int) sizeof (*dt));
 | |
| 	    break;
 | |
| 	  }
 | |
| 
 | |
| 	case GRUB_ACPI_MADT_ENTRY_TYPE_SAPIC:
 | |
| 	  {
 | |
| 	    struct grub_acpi_madt_entry_sapic *dt = (void *) d;
 | |
| 	    grub_printf ("  IOSAPIC Id=%02x GSI=%08x Addr=%016" PRIxGRUB_UINT64_T
 | |
| 			 "\n",
 | |
| 			 dt->id, dt->global_sys_interrupt_base,
 | |
| 			 dt->addr);
 | |
| 	    if (dt->hdr.len != sizeof (*dt))
 | |
| 	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
 | |
| 			   (int) sizeof (*dt));
 | |
| 	    if (dt->pad)
 | |
| 	      grub_printf ("   non-zero pad: %02x\n", dt->pad);
 | |
| 
 | |
| 	  }
 | |
| 	  break;
 | |
| 	case GRUB_ACPI_MADT_ENTRY_TYPE_LSAPIC:
 | |
| 	  {
 | |
| 	    struct grub_acpi_madt_entry_lsapic *dt = (void *) d;
 | |
| 	    grub_printf ("  LSAPIC ProcId=%02x ID=%02x EID=%02x Flags=%x",
 | |
| 			 dt->cpu_id, dt->id, dt->eid, dt->flags);
 | |
| 	    if (dt->flags & GRUB_ACPI_MADT_ENTRY_SAPIC_FLAGS_ENABLED)
 | |
| 	      grub_printf (" Enabled\n");
 | |
| 	    else
 | |
| 	      grub_printf (" Disabled\n");
 | |
| 	    if (d->len > sizeof (struct grub_acpi_madt_entry_sapic))
 | |
| 	      grub_printf ("  UID val=%08x, Str=%s\n", dt->cpu_uid,
 | |
| 			   dt->cpu_uid_str);
 | |
| 	    if (dt->hdr.len != sizeof (*dt) + grub_strlen ((char *) dt->cpu_uid_str) + 1)
 | |
| 	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
 | |
| 			   (int) sizeof (*dt));
 | |
| 	    if (dt->pad[0] || dt->pad[1] || dt->pad[2])
 | |
| 	      grub_printf ("   non-zero pad: %02x%02x%02x\n", dt->pad[0], dt->pad[1], dt->pad[2]);
 | |
| 	  }
 | |
| 	  break;
 | |
| 	case GRUB_ACPI_MADT_ENTRY_TYPE_PLATFORM_INT_SOURCE:
 | |
| 	  {
 | |
| 	    struct grub_acpi_madt_entry_platform_int_source *dt = (void *) d;
 | |
| 	    static const char * const platint_type[] =
 | |
| 	      {"Nul", "PMI", "INIT", "CPEI"};
 | |
| 
 | |
| 	    grub_printf ("  Platform INT flags=%04x type=%02x (%s)"
 | |
| 			 " ID=%02x EID=%02x\n",
 | |
| 			 dt->flags, dt->inttype,
 | |
| 			 (dt->inttype < ARRAY_SIZE (platint_type))
 | |
| 			 ? platint_type[dt->inttype] : "??", dt->cpu_id,
 | |
| 			 dt->cpu_eid);
 | |
| 	    grub_printf ("  IOSAPIC Vec=%02x GSI=%08x source flags=%08x\n",
 | |
| 			 dt->sapic_vector, dt->global_sys_int, dt->src_flags);
 | |
| 	  }
 | |
| 	  break;
 | |
| 	default:
 | |
| 	  grub_printf ("  type=%x l=%u ", d->type, d->len);
 | |
| 	  grub_printf (" ??\n");
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| disp_acpi_xsdt_table (struct grub_acpi_table_header *t)
 | |
| {
 | |
|   grub_uint32_t len;
 | |
|   grub_uint64_t *desc;
 | |
| 
 | |
|   disp_acpi_table (t);
 | |
|   len = t->length - sizeof (*t);
 | |
|   desc = (grub_uint64_t *) (t + 1);
 | |
|   for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc))
 | |
|     {
 | |
| #if GRUB_CPU_SIZEOF_VOID_P == 4
 | |
|       if (*desc >= (1ULL << 32))
 | |
| 	{
 | |
| 	  grub_printf ("Unreachable table\n");
 | |
| 	  continue;
 | |
| 	}
 | |
| #endif
 | |
|       t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;
 | |
| 
 | |
|       if (t == NULL)
 | |
| 	continue;
 | |
| 
 | |
|       if (grub_memcmp (t->signature, GRUB_ACPI_MADT_SIGNATURE,
 | |
| 		       sizeof (t->signature)) == 0)
 | |
| 	disp_madt_table ((struct grub_acpi_madt *) t);
 | |
|       else
 | |
| 	disp_acpi_table (t);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| disp_acpi_rsdt_table (struct grub_acpi_table_header *t)
 | |
| {
 | |
|   grub_uint32_t len;
 | |
|   grub_uint32_t *desc;
 | |
| 
 | |
|   disp_acpi_table (t);
 | |
|   len = t->length - sizeof (*t);
 | |
|   desc = (grub_uint32_t *) (t + 1);
 | |
|   for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc))
 | |
|     {
 | |
|       t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;
 | |
| 
 | |
|       if (t == NULL)
 | |
| 	continue;
 | |
| 
 | |
|       if (grub_memcmp (t->signature, GRUB_ACPI_MADT_SIGNATURE,
 | |
| 		       sizeof (t->signature)) == 0)
 | |
| 	disp_madt_table ((struct grub_acpi_madt *) t);
 | |
|       else
 | |
| 	disp_acpi_table (t);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| disp_acpi_rsdpv1 (struct grub_acpi_rsdp_v10 *rsdp)
 | |
| {
 | |
|   print_field (rsdp->signature);
 | |
|   grub_printf ("chksum:%02x (%s), OEM-ID: ", rsdp->checksum, grub_byte_checksum (rsdp, sizeof (*rsdp)) == 0 ? "valid" : "invalid");
 | |
|   print_field (rsdp->oemid);
 | |
|   grub_printf ("rev=%d\n", rsdp->revision);
 | |
|   grub_printf ("RSDT=%08" PRIxGRUB_UINT32_T "\n", rsdp->rsdt_addr);
 | |
| }
 | |
| 
 | |
| static void
 | |
| disp_acpi_rsdpv2 (struct grub_acpi_rsdp_v20 *rsdp)
 | |
| {
 | |
|   disp_acpi_rsdpv1 (&rsdp->rsdpv1);
 | |
|   grub_printf ("len=%d chksum=%02x (%s) XSDT=%016" PRIxGRUB_UINT64_T "\n", rsdp->length, rsdp->checksum, grub_byte_checksum (rsdp, rsdp->length) == 0 ? "valid" : "invalid",
 | |
| 	       rsdp->xsdt_addr);
 | |
|   if (rsdp->length != sizeof (*rsdp))
 | |
|     grub_printf (" length mismatch %d != %d\n", rsdp->length,
 | |
| 		 (int) sizeof (*rsdp));
 | |
|   if (rsdp->reserved[0] || rsdp->reserved[1] || rsdp->reserved[2])
 | |
|     grub_printf (" non-zero reserved %02x%02x%02x\n", rsdp->reserved[0], rsdp->reserved[1], rsdp->reserved[2]);
 | |
| }
 | |
| 
 | |
| static const struct grub_arg_option options[] = {
 | |
|   {"v1", '1', 0, N_("Show version 1 tables only."), 0, ARG_TYPE_NONE},
 | |
|   {"v2", '2', 0, N_("Show version 2 and version 3 tables only."), 0, ARG_TYPE_NONE},
 | |
|   {0, 0, 0, 0, 0, 0}
 | |
| };
 | |
| 
 | |
| static grub_err_t
 | |
| grub_cmd_lsacpi (struct grub_extcmd_context *ctxt,
 | |
| 		 int argc __attribute__ ((unused)),
 | |
| 		 char **args __attribute__ ((unused)))
 | |
| {
 | |
|   if (!ctxt->state[1].set)
 | |
|     {
 | |
|       struct grub_acpi_rsdp_v10 *rsdp1 = grub_acpi_get_rsdpv1 ();
 | |
|       if (!rsdp1)
 | |
| 	grub_printf ("No RSDPv1\n");
 | |
|       else
 | |
| 	{
 | |
| 	  grub_printf ("RSDPv1 signature:");
 | |
| 	  disp_acpi_rsdpv1 (rsdp1);
 | |
| 	  disp_acpi_rsdt_table ((void *) (grub_addr_t) rsdp1->rsdt_addr);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (!ctxt->state[0].set)
 | |
|     {
 | |
|       struct grub_acpi_rsdp_v20 *rsdp2 = grub_acpi_get_rsdpv2 ();
 | |
|       if (!rsdp2)
 | |
| 	grub_printf ("No RSDPv2\n");
 | |
|       else
 | |
| 	{
 | |
| #if GRUB_CPU_SIZEOF_VOID_P == 4
 | |
| 	  if (rsdp2->xsdt_addr >= (1ULL << 32))
 | |
| 	    grub_printf ("Unreachable RSDPv2\n");
 | |
| 	  else
 | |
| #endif
 | |
| 	    {
 | |
| 	      grub_printf ("RSDPv2 signature:");
 | |
| 	      disp_acpi_rsdpv2 (rsdp2);
 | |
| 	      disp_acpi_xsdt_table ((void *) (grub_addr_t) rsdp2->xsdt_addr);
 | |
| 	      grub_printf ("\n");
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| static grub_extcmd_t cmd;
 | |
| 
 | |
| GRUB_MOD_INIT(lsapi)
 | |
| {
 | |
|   cmd = grub_register_extcmd ("lsacpi", grub_cmd_lsacpi, 0, "[-1|-2]",
 | |
| 			      N_("Show ACPI information."), options);
 | |
| }
 | |
| 
 | |
| GRUB_MOD_FINI(lsacpi)
 | |
| {
 | |
|   grub_unregister_extcmd (cmd);
 | |
| }
 | |
| 
 | |
| 
 | 
