lsacpi.c 9.28 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/* 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>

28 29
#pragma GCC diagnostic ignored "-Wcast-align"

30 31
GRUB_MOD_LICENSE ("GPLv3+");

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
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);
47 48
  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");
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  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)
	{
72 73 74 75 76 77
	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))
78 79
	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
			   (int) sizeof (*dt));
80 81 82 83 84 85 86 87 88
	    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))
89 90
	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
			   (int) sizeof (*dt));
91 92 93 94 95
	    if (dt->pad)
	      grub_printf ("   non-zero pad: %02x\n", dt->pad);
	    break;
	  }

96 97 98
	case GRUB_ACPI_MADT_ENTRY_TYPE_INTERRUPT_OVERRIDE:
	  {
	    struct grub_acpi_madt_entry_interrupt_override *dt = (void *) d;
99
	    grub_printf ("  Int Override bus=%x src=%x GSI=%08x Flags=%04x\n",
100 101
			 dt->bus, dt->source, dt->global_sys_interrupt,
			 dt->flags);
102
	    if (dt->hdr.len != sizeof (*dt))
103 104
	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
			   (int) sizeof (*dt));
105 106
	  }
	  break;
107 108 109 110 111 112 113

	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))
114 115
	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
			   (int) sizeof (*dt));
116 117 118
	    break;
	  }

119 120 121
	case GRUB_ACPI_MADT_ENTRY_TYPE_SAPIC:
	  {
	    struct grub_acpi_madt_entry_sapic *dt = (void *) d;
122
	    grub_printf ("  IOSAPIC Id=%02x GSI=%08x Addr=%016" PRIxGRUB_UINT64_T
123 124 125
			 "\n",
			 dt->id, dt->global_sys_interrupt_base,
			 dt->addr);
126
	    if (dt->hdr.len != sizeof (*dt))
127 128
	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
			   (int) sizeof (*dt));
129 130 131
	    if (dt->pad)
	      grub_printf ("   non-zero pad: %02x\n", dt->pad);

132 133 134 135 136
	  }
	  break;
	case GRUB_ACPI_MADT_ENTRY_TYPE_LSAPIC:
	  {
	    struct grub_acpi_madt_entry_lsapic *dt = (void *) d;
137
	    grub_printf ("  LSAPIC ProcId=%02x ID=%02x EID=%02x Flags=%x",
138 139 140 141 142 143
			 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))
144
	      grub_printf ("  UID val=%08x, Str=%s\n", dt->cpu_uid,
145
			   dt->cpu_uid_str);
146
	    if (dt->hdr.len != sizeof (*dt) + grub_strlen ((char *) dt->cpu_uid_str) + 1)
147 148
	      grub_printf ("   table size mismatch %d != %d\n", dt->hdr.len,
			   (int) sizeof (*dt));
149 150
	    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]);
151 152 153 154 155 156 157 158
	  }
	  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"};

159
	    grub_printf ("  Platform INT flags=%04x type=%02x (%s)"
160 161 162 163 164
			 " 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);
165
	    grub_printf ("  IOSAPIC Vec=%02x GSI=%08x source flags=%08x\n",
166 167 168 169
			 dt->sapic_vector, dt->global_sys_int, dt->src_flags);
	  }
	  break;
	default:
170
	  grub_printf ("  type=%x l=%u ", d->type, d->len);
171 172 173 174 175 176 177 178 179 180 181 182 183 184
	  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);
185
  for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc))
186
    {
187 188
#if GRUB_CPU_SIZEOF_VOID_P == 4
      if (*desc >= (1ULL << 32))
189 190 191 192
	{
	  grub_printf ("Unreachable table\n");
	  continue;
	}
193
#endif
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
      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);
216
  for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc))
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
    {
      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);
235
  grub_printf ("chksum:%02x (%s), OEM-ID: ", rsdp->checksum, grub_byte_checksum (rsdp, sizeof (*rsdp)) == 0 ? "valid" : "invalid");
236 237 238 239 240 241 242 243 244
  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);
245
  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",
246
	       rsdp->xsdt_addr);
247
  if (rsdp->length != sizeof (*rsdp))
248 249
    grub_printf (" length mismatch %d != %d\n", rsdp->length,
		 (int) sizeof (*rsdp));
250 251
  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]);
252 253 254
}

static const struct grub_arg_option options[] = {
255
  {"v1", '1', 0, N_("Show version 1 tables only."), 0, ARG_TYPE_NONE},
256 257
  {"v2", '2', 0, N_("Show version 2 and version 3 tables only."), 0, ARG_TYPE_NONE},
  {0, 0, 0, 0, 0, 0}
258 259 260
};

static grub_err_t
261 262
grub_cmd_lsacpi (struct grub_extcmd_context *ctxt,
		 int argc __attribute__ ((unused)),
263 264
		 char **args __attribute__ ((unused)))
{
265
  if (!ctxt->state[1].set)
266 267 268 269 270 271 272 273 274 275 276 277
    {
      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);
	}
    }

278
  if (!ctxt->state[0].set)
279 280 281 282 283 284
    {
      struct grub_acpi_rsdp_v20 *rsdp2 = grub_acpi_get_rsdpv2 ();
      if (!rsdp2)
	grub_printf ("No RSDPv2\n");
      else
	{
285 286 287
#if GRUB_CPU_SIZEOF_VOID_P == 4
	  if (rsdp2->xsdt_addr >= (1ULL << 32))
	    grub_printf ("Unreachable RSDPv2\n");
288
	  else
289
#endif
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
	    {
	      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)
{
305
  cmd = grub_register_extcmd ("lsacpi", grub_cmd_lsacpi, 0, "[-1|-2]",
306 307 308 309 310 311 312 313 314
			      N_("Show ACPI information."), options);
}

GRUB_MOD_FINI(lsacpi)
{
  grub_unregister_extcmd (cmd);
}