Exemplo n.º 1
0
static int
grub_cmd_badram_hook (grub_uint64_t addr, grub_uint64_t size,
		      grub_uint32_t type __attribute__ ((unused)),
		      void *closure)
{
  struct grub_cmd_badram_closure *c = closure;
  grub_uint64_t iterator, low, high, cur;
  int tail, var;
  int i;
  grub_dprintf ("badram", "hook %llx+%llx\n", (unsigned long long) addr,
		(unsigned long long) size);

  /* How many trailing zeros? */
  for (tail = 0; ! (c->badmask & (1ULL << tail)); tail++);

  /* How many zeros in mask? */
  var = 0;
  for (i = 0; i < 64; i++)
    if (! (c->badmask & (1ULL << i)))
      var++;

  if (fill_mask (c->badaddr, c->badmask, 0) >= addr)
    iterator = 0;
  else
    {
      low = 0;
      high = ~0ULL;
      /* Find starting value. Keep low and high such that
	 fill_mask (low) < addr and fill_mask (high) >= addr;
      */
      while (high - low > 1)
	{
	  cur = (low + high) / 2;
	  if (fill_mask (c->badaddr, c->badmask, cur) >= addr)
	    high = cur;
	  else
	    low = cur;
	}
      iterator = high;
    }

  for (; iterator < (1ULL << (var - tail))
	 && (cur = fill_mask (c->badaddr, c->badmask, iterator)) < addr + size;
       iterator++)
    {
      grub_dprintf ("badram", "%llx (size %llx) is a badram range\n",
		    (unsigned long long) cur, (1ULL << tail));
      grub_mmap_register (cur, (1ULL << tail), GRUB_MACHINE_MEMORY_HOLE);
    }
  return 0;
}
Exemplo n.º 2
0
void *
grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size,
			       int *handle, int type, int flags)
{
  void *ret;

  if (flags & (GRUB_MMAP_MALLOC_LOW | GRUB_MMAP_MALLOC_HIGH))
    {
      struct grub_mmap_malign_and_register_closure c;

      c.align = align;
      c.size = size;
      c.highestlow = 0;
      if (flags & GRUB_MMAP_MALLOC_LOW)
	{
	  c.min = 0;
	  c.max = 0x100000;
	}
      else
	{
	  c.min = grub_mmap_high;
	  c.max = 0x100000000ll;
	}
      /* FIXME: use low-memory mm allocation once it's available. */
      grub_mmap_iterate (find_hook, &c);
      ret = UINT_TO_PTR (c.highestlow);
    }
  else
    ret = grub_memalign (align, size);

  if (! ret)
    {
      *handle = 0;
      return 0;
    }

  *handle = grub_mmap_register (PTR_TO_UINT64 (ret), size, type);
  if (! *handle)
    {
      grub_free (ret);
      return 0;
    }

  return ret;
}
Exemplo n.º 3
0
grub_err_t
grub_acpi_create_ebda (void)
{
  struct grub_acpi_create_ebda_ctx ctx = {
    .highestlow = 0
  };
  int ebda_kb_len = 0;
  int mmapregion = 0;
  grub_uint8_t *ebda, *v1inebda = 0, *v2inebda = 0;
  grub_uint8_t *targetebda, *target;
  struct grub_acpi_rsdp_v10 *v1;
  struct grub_acpi_rsdp_v20 *v2;

  ebda = (grub_uint8_t *) (grub_addr_t) ((*((grub_uint16_t *)0x40e)) << 4);
  if (ebda)
    ebda_kb_len = *(grub_uint16_t *) ebda;
  if (ebda_kb_len > 16)
    ebda_kb_len = 0;
  ctx.ebda_len = (ebda_kb_len + 1) << 10;

  /* FIXME: use low-memory mm allocation once it's available. */
  grub_mmap_iterate (find_hook, &ctx);
  targetebda = (grub_uint8_t *) (grub_addr_t) ctx.highestlow;
  grub_dprintf ("acpi", "creating ebda @%llx\n",
		(unsigned long long) ctx.highestlow);
  if (! ctx.highestlow)
    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
		       "couldn't find space for the new EBDA");

  mmapregion = grub_mmap_register ((grub_addr_t) targetebda, ctx.ebda_len,
				   GRUB_MEMORY_RESERVED);
  if (! mmapregion)
    return grub_errno;

  /* XXX: EBDA is unstandardized, so this implementation is heuristical. */
  if (ebda_kb_len)
    grub_memcpy (targetebda, ebda, 0x400);
  else
    grub_memset (targetebda, 0, 0x400);
  *((grub_uint16_t *) targetebda) = ebda_kb_len + 1;
  target = targetebda;

  v1 = grub_acpi_get_rsdpv1 ();
  v2 = grub_acpi_get_rsdpv2 ();
  if (v2 && v2->length > 40)
    v2 = 0;

  /* First try to replace already existing rsdp. */
  if (v2)
    {
      grub_dprintf ("acpi", "Scanning EBDA for old rsdpv2\n");
      for (; target < targetebda + 0x400 - v2->length; target += 0x10)
	if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
	    && grub_byte_checksum (target,
				   sizeof (struct grub_acpi_rsdp_v10)) == 0
	    && ((struct grub_acpi_rsdp_v10 *) target)->revision != 0
	    && ((struct grub_acpi_rsdp_v20 *) target)->length <= v2->length)
	  {
	    grub_memcpy (target, v2, v2->length);
	    grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
	    v2inebda = target;
	    target += v2->length;
	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
	    v2 = 0;
	    break;
	  }
    }

  if (v1)
    {
      grub_dprintf ("acpi", "Scanning EBDA for old rsdpv1\n");
      for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
	   target += 0x10)
	if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
	    && grub_byte_checksum (target,
				   sizeof (struct grub_acpi_rsdp_v10)) == 0)
	  {
	    grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
	    grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
	    v1inebda = target;
	    target += sizeof (struct grub_acpi_rsdp_v10);
	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
	    v1 = 0;
	    break;
	  }
    }

  target = targetebda + 0x100;

  /* Try contiguous zeros. */
  if (v2)
    {
      grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
      for (; target < targetebda + 0x400 - v2->length; target += 0x10)
	if (iszero (target, v2->length))
	  {
	    grub_dprintf ("acpi", "Copying rsdpv2 to %p\n", target);
	    grub_memcpy (target, v2, v2->length);
	    v2inebda = target;
	    target += v2->length;
	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
	    v2 = 0;
	    break;
	  }
    }

  if (v1)
    {
      grub_dprintf ("acpi", "Scanning EBDA for block of zeros\n");
      for (; target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
	   target += 0x10)
	if (iszero (target, sizeof (struct grub_acpi_rsdp_v10)))
	  {
	    grub_dprintf ("acpi", "Copying rsdpv1 to %p\n", target);
	    grub_memcpy (target, v1, sizeof (struct grub_acpi_rsdp_v10));
	    v1inebda = target;
	    target += sizeof (struct grub_acpi_rsdp_v10);
	    target = (grub_uint8_t *) ((((long) target - 1) | 0xf) + 1);
	    v1 = 0;
	    break;
	  }
    }

  if (v1 || v2)
    {
      grub_mmap_unregister (mmapregion);
      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
			 "couldn't find suitable spot in EBDA");
    }

  /* Remove any other RSDT. */
  for (target = targetebda;
       target < targetebda + 0x400 - sizeof (struct grub_acpi_rsdp_v10);
       target += 0x10)
    if (grub_memcmp (target, GRUB_RSDP_SIGNATURE, GRUB_RSDP_SIGNATURE_SIZE) == 0
	&& grub_byte_checksum (target,
			       sizeof (struct grub_acpi_rsdp_v10)) == 0
	&& target != v1inebda && target != v2inebda)
      *target = 0;

  grub_dprintf ("acpi", "Switching EBDA\n");
  (*((grub_uint16_t *) 0x40e)) = ((long)targetebda) >> 4;
  grub_dprintf ("acpi", "EBDA switched\n");

  return GRUB_ERR_NONE;
}
#endif

/* Create tables common to ACPIv1 and ACPIv2+ */
static void
setup_common_tables (void)
{
  struct efiemu_acpi_table *cur;
  struct grub_acpi_table_header *rsdt;
  grub_uint32_t *rsdt_entry;
  int numoftables;

  /* Treat DSDT. */
  grub_memcpy (playground_ptr, table_dsdt, dsdt_size);
  grub_free (table_dsdt);
  table_dsdt = playground_ptr;
  playground_ptr += dsdt_size;

  /* Treat other tables. */
  for (cur = acpi_tables; cur; cur = cur->next)
    {
      struct grub_acpi_fadt *fadt;

      grub_memcpy (playground_ptr, cur->addr, cur->size);
      grub_free (cur->addr);
      cur->addr = playground_ptr;
      playground_ptr += cur->size;

      /* If it's FADT correct DSDT and FACS addresses. */
      fadt = (struct grub_acpi_fadt *) cur->addr;
      if (grub_memcmp (fadt->hdr.signature, GRUB_ACPI_FADT_SIGNATURE,
		       sizeof (fadt->hdr.signature)) == 0)
	{
	  fadt->dsdt_addr = (grub_addr_t) table_dsdt;
	  fadt->facs_addr = facs_addr;

	  /* Does a revision 2 exist at all? */
	  if (fadt->hdr.revision >= 3)
	    {
	      fadt->dsdt_xaddr = (grub_addr_t) table_dsdt;
	      fadt->facs_xaddr = facs_addr;
	    }

	  /* Recompute checksum. */
	  fadt->hdr.checksum = 0;
	  fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length);
	}
    }

  /* Fill RSDT entries. */
  numoftables = 0;
  for (cur = acpi_tables; cur; cur = cur->next)
    numoftables++;

  rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr;
  playground_ptr += sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;

  rsdt_entry = (grub_uint32_t *) (rsdt + 1);

  /* Fill RSDT header. */
  grub_memcpy (&(rsdt->signature), "RSDT", 4);
  rsdt->length = sizeof (struct grub_acpi_table_header) + sizeof (grub_uint32_t) * numoftables;
  rsdt->revision = 1;
  grub_memcpy (&(rsdt->oemid), root_oemid, sizeof (rsdt->oemid));
  grub_memcpy (&(rsdt->oemtable), root_oemtable, sizeof (rsdt->oemtable));
  rsdt->oemrev = root_oemrev;
  grub_memcpy (&(rsdt->creator_id), root_creator_id, sizeof (rsdt->creator_id));
  rsdt->creator_rev = root_creator_rev;

  for (cur = acpi_tables; cur; cur = cur->next)
    *(rsdt_entry++) = (grub_addr_t) cur->addr;

  /* Recompute checksum. */
  rsdt->checksum = 0;
  rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length);
}

/* Regenerate ACPIv1 RSDP */
static void
setv1table (void)
{
  /* Create RSDP. */
  rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr;
  playground_ptr += sizeof (struct grub_acpi_rsdp_v10);
  grub_memcpy (&(rsdpv1_new->signature), GRUB_RSDP_SIGNATURE,
	       sizeof (rsdpv1_new->signature));
  grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof  (rsdpv1_new->oemid));
  rsdpv1_new->revision = 0;
  rsdpv1_new->rsdt_addr = (grub_addr_t) rsdt_addr;
  rsdpv1_new->checksum = 0;
  rsdpv1_new->checksum = 1 + ~grub_byte_checksum (rsdpv1_new,
						  sizeof (*rsdpv1_new));
  grub_dprintf ("acpi", "Generated ACPIv1 tables\n");
}