Example #1
0
static void 
grub_claim_heap (void)
{
  unsigned long total = 0;

  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM))
    heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN,
	       1, &total);
  else
    grub_machine_mmap_iterate (heap_init, &total);
}
Example #2
0
void
grub_machine_init (void)
{
#ifdef GRUB_MACHINE_QEMU
  grub_qemu_init_cirrus ();
#endif
  /* Initialize the console as early as possible.  */
  grub_vga_text_init ();

  auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t, grub_uint64_t, 
				       grub_memory_type_t);
  int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t size,
				  grub_memory_type_t type)
  {
#if GRUB_CPU_SIZEOF_VOID_P == 4
    /* Restrict ourselves to 32-bit memory space.  */
    if (addr > GRUB_ULONG_MAX)
      return 0;
    if (addr + size > GRUB_ULONG_MAX)
      size = GRUB_ULONG_MAX - addr;
#endif

    if (type != GRUB_MEMORY_AVAILABLE)
      return 0;

    /* Avoid the lower memory.  */
    if (addr < GRUB_MEMORY_MACHINE_LOWER_SIZE)
      {
	if (addr + size <= GRUB_MEMORY_MACHINE_LOWER_SIZE)
	  return 0;
	else
	  {
	    size -= GRUB_MEMORY_MACHINE_LOWER_SIZE - addr;
	    addr = GRUB_MEMORY_MACHINE_LOWER_SIZE;
	  }
      }

    grub_mm_init_region ((void *) (grub_addr_t) addr, (grub_size_t) size);

    return 0;
  }

#if defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU)
  grub_machine_mmap_init ();
#endif
  grub_machine_mmap_iterate (heap_init);

  grub_tsc_init ();
}
Example #3
0
/* We need to call this before grub_claim_memory.  */
static void
grub_get_extended_memory (void)
{
  auto int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type);
  int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type)
    {
      if (type == 1 && addr == 0x100000)
        {
          grub_upper_mem = len;
          return 1;
        }

      return 0;
    }

  grub_machine_mmap_iterate (find_ext_mem);
}
Example #4
0
grub_err_t
grub_mmap_iterate (int (*hook) (grub_uint64_t, grub_uint64_t,
				grub_uint32_t, void *), void *closure)
{
  /* This function resolves overlapping regions and sorts the memory map.
     It uses scanline (sweeping) algorithm.
  */
  /* If same page is used by multiple types it's resolved
     according to priority:
     1 - free memory
     2 - memory usable by firmware-aware code
     3 - unusable memory
     4 - a range deliberately empty
  */
  int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] =
    {
#ifdef GRUB_MACHINE_MEMORY_AVAILABLE
      [GRUB_MACHINE_MEMORY_AVAILABLE] = 1,
#endif
#if defined (GRUB_MACHINE_MEMORY_RESERVED) && GRUB_MACHINE_MEMORY_RESERVED != GRUB_MACHINE_MEMORY_HOLE
      [GRUB_MACHINE_MEMORY_RESERVED] = 3,
#endif
#ifdef GRUB_MACHINE_MEMORY_ACPI
      [GRUB_MACHINE_MEMORY_ACPI] = 2,
#endif
#ifdef GRUB_MACHINE_MEMORY_CODE
      [GRUB_MACHINE_MEMORY_CODE] = 3,
#endif
#ifdef GRUB_MACHINE_MEMORY_NVS
      [GRUB_MACHINE_MEMORY_NVS] = 3,
#endif
      [GRUB_MACHINE_MEMORY_HOLE] = 4,
    };

  int i, k, done;

  struct grub_mmap_scan *scanline_events;
  struct grub_mmap_scan t;

  /* Previous scanline event. */
  grub_uint64_t lastaddr;
  int lasttype;
  /* Current scanline event. */
  int curtype;
  /* How many regions of given type overlap at current location? */
  int present[GRUB_MACHINE_MEMORY_MAX_TYPE + 2];
  /* Number of mmap chunks. */
  int mmap_num;
  struct grub_mmap_iterate_closure c;

#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
  struct grub_mmap_region *cur;
#endif

  mmap_num = 0;

#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
  for (cur = grub_mmap_overlays; cur; cur = cur->next)
    mmap_num++;
#endif

  grub_machine_mmap_iterate (count_hook, &mmap_num);

  /* Initialize variables. */
  grub_memset (present, 0, sizeof (present));
  scanline_events = (struct grub_mmap_scan *)
    grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);

  if (! scanline_events)
    {
      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
			 "couldn't allocate space for new memory map");
    }

  i = 0;
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
  /* Register scanline events. */
  for (cur = grub_mmap_overlays; cur; cur = cur->next)
    {
      scanline_events[i].pos = cur->start;
      scanline_events[i].type = 0;
      if (cur->type == GRUB_MACHINE_MEMORY_HOLE
	  || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE
	      && priority[cur->type]))
	scanline_events[i].memtype = cur->type;
      else
	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
      i++;

      scanline_events[i].pos = cur->end;
      scanline_events[i].type = 1;
      scanline_events[i].memtype = scanline_events[i - 1].memtype;
      i++;
    }
#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */

  c.i = i;
  c.scanline_events = scanline_events;
  c.priority = priority;
  grub_machine_mmap_iterate (fill_hook, &c);

  /* Primitive bubble sort. It has complexity O(n^2) but since we're
     unlikely to have more than 100 chunks it's probably one of the
     fastest for one purpose. */
  done = 1;
  while (done)
    {
      done = 0;
      for (i = 0; i < 2 * mmap_num - 1; i++)
	if (scanline_events[i + 1].pos < scanline_events[i].pos
	    || (scanline_events[i + 1].pos == scanline_events[i].pos
		&& scanline_events[i + 1].type == 0
		&& scanline_events[i].type == 1))
	  {
	    t = scanline_events[i + 1];
	    scanline_events[i + 1] = scanline_events[i];
	    scanline_events[i] = t;
	    done = 1;
	  }
    }

  lastaddr = scanline_events[0].pos;
  lasttype = scanline_events[0].memtype;
  for (i = 0; i < 2 * mmap_num; i++)
    {
      /* Process event. */
      if (scanline_events[i].type)
	present[scanline_events[i].memtype]--;
      else
	present[scanline_events[i].memtype]++;

      /* Determine current region type. */
      curtype = -1;
      for (k = 0; k <= GRUB_MACHINE_MEMORY_MAX_TYPE + 1; k++)
	if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
	  curtype = k;

      /* Announce region to the hook if necessary. */
      if ((curtype == -1 || curtype != lasttype)
	  && lastaddr != scanline_events[i].pos
	  && lasttype != -1
	  && lasttype != GRUB_MACHINE_MEMORY_HOLE
	  && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype,
		   closure))
	{
	  grub_free (scanline_events);
	  return GRUB_ERR_NONE;
	}

      /* Update last values if necessary. */
      if (curtype == -1 || curtype != lasttype)
	{
	  lasttype = curtype;
	  lastaddr = scanline_events[i].pos;
	}
    }

  grub_free (scanline_events);
  return GRUB_ERR_NONE;
}
Example #5
0
/* Claim some available memory in the first /memory node. */
static void grub_claim_heap (void)
{
  unsigned long total = 0;

  auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type);
  int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type)
  {
    if (type != 1)
      return 0;

    if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM))
      {
	if (addr + len <= 0x180000)
	  return 0;

	if (addr < 0x180000)
	  {
	    len = addr + len - 0x180000;
	    addr = 0x180000;
	  }
      }
    len -= 1; /* Required for some firmware.  */

    /* Never exceed HEAP_MAX_SIZE  */
    if (total + len > HEAP_MAX_SIZE)
      len = HEAP_MAX_SIZE - total;

    /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */
    if ((addr < HEAP_MAX_ADDR) &&				/* if it's too late, don't bother */
        (addr + len > HEAP_MAX_ADDR) &&				/* if it wasn't available anyway, don't bother */
        (total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE))	/* only limit ourselves when we can afford to */
       len = HEAP_MAX_ADDR - addr;

    /* In theory, firmware should already prevent this from happening by not
       listing our own image in /memory/available.  The check below is intended
       as a safeguard in case that doesn't happen.  However, it doesn't protect
       us from corrupting our module area, which extends up to a
       yet-undetermined region above _end.  */
    if ((addr < (grub_addr_t) _end) && ((addr + len) > (grub_addr_t) _start))
      {
        grub_printf ("Warning: attempt to claim over our own code!\n");
        len = 0;
      }

    if (len)
      {
	/* Claim and use it.  */
	if (grub_claimmap (addr, len) < 0)
	  return grub_error (GRUB_ERR_OUT_OF_MEMORY,
			     "failed to claim heap at 0x%llx, len 0x%llx",
			     addr, len);
	grub_mm_init_region ((void *) (grub_addr_t) addr, len);
      }

    total += len;
    if (total >= HEAP_MAX_SIZE)
      return 1;

    return 0;
  }

  if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET))
    heap_init (HEAP_MAX_ADDR - HEAP_MIN_SIZE, HEAP_MIN_SIZE, 1);
  else
    grub_machine_mmap_iterate (heap_init);
}
Example #6
0
void
grub_machine_init (void)
{
  int i;
  int grub_lower_mem;

  /* Initialize the console as early as possible.  */
  grub_console_init ();

  grub_lower_mem = grub_get_conv_memsize () << 10;

  /* Sanity check.  */
  if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END)
    grub_fatal ("too small memory");

/* FIXME: This prevents loader/i386/linux.c from using low memory.  When our
   heap implements support for requesting a chunk in low memory, this should
   no longer be a problem.  */
#if 0
  /* Add the lower memory into free memory.  */
  if (grub_lower_mem >= GRUB_MEMORY_MACHINE_RESERVED_END)
    add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
		    grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
#endif

  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
				  grub_memory_type_t);
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
			     grub_memory_type_t type)
    {
      /* Avoid the lower memory.  */
      if (addr < 0x100000)
	{
	  if (size <= 0x100000 - addr)
	    return 0;

	  size -= 0x100000 - addr;
	  addr = 0x100000;
	}

      /* Ignore >4GB.  */
      if (addr <= 0xFFFFFFFF && type == GRUB_MEMORY_AVAILABLE)
	{
	  grub_size_t len;

	  len = (grub_size_t) ((addr + size > 0xFFFFFFFF)
		 ? 0xFFFFFFFF - addr
		 : size);
	  add_mem_region (addr, len);
	}

      return 0;
    }

  grub_machine_mmap_iterate (hook);

  compact_mem_regions ();

  for (i = 0; i < num_regions; i++)
      grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);

  grub_tsc_init ();
}