Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/firmware/efi/libstub/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 4 kB image not shown  

Quelle  relocate.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0

#include <linux/efi.h>
#include <asm/efi.h>

#include "efistub.h"

/**
 * efi_low_alloc_above() - allocate pages at or above given address
 * @size: size of the memory area to allocate
 * @align: minimum alignment of the allocated memory area. It should
 * a power of two.
 * @addr: on exit the address of the allocated memory
 * @min: minimum address to used for the memory allocation
 *
 * Allocate at the lowest possible address that is not below @min as
 * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
 * least EFI_ALLOC_ALIGN. The first allocated page will not below the address
 * given by @min.
 *
 * Return: status code
 */

efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
     unsigned long *addr, unsigned long min)
{
 struct efi_boot_memmap *map __free(efi_pool) = NULL;
 efi_status_t status;
 unsigned long nr_pages;
 int i;

 status = efi_get_memory_map(&map, false);
 if (status != EFI_SUCCESS)
  return status;

 /*
 * Enforce minimum alignment that EFI or Linux requires when
 * requesting a specific address.  We are doing page-based (or
 * larger) allocations, and both the address and size must meet
 * alignment constraints.
 */

 if (align < EFI_ALLOC_ALIGN)
  align = EFI_ALLOC_ALIGN;

 size = round_up(size, EFI_ALLOC_ALIGN);
 nr_pages = size / EFI_PAGE_SIZE;
 for (i = 0; i < map->map_size / map->desc_size; i++) {
  efi_memory_desc_t *desc;
  unsigned long m = (unsigned long)map->map;
  u64 start, end;

  desc = efi_memdesc_ptr(m, map->desc_size, i);

  if (desc->type != EFI_CONVENTIONAL_MEMORY)
   continue;

  if (desc->attribute & EFI_MEMORY_HOT_PLUGGABLE)
   continue;

  if (efi_soft_reserve_enabled() &&
      (desc->attribute & EFI_MEMORY_SP))
   continue;

  if (desc->num_pages < nr_pages)
   continue;

  start = desc->phys_addr;
  end = start + desc->num_pages * EFI_PAGE_SIZE;

  if (start < min)
   start = min;

  start = round_up(start, align);
  if ((start + size) > end)
   continue;

  status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
         EFI_LOADER_DATA, nr_pages, &start);
  if (status == EFI_SUCCESS) {
   *addr = start;
   break;
  }
 }

 if (i == map->map_size / map->desc_size)
  return EFI_NOT_FOUND;

 return EFI_SUCCESS;
}

/**
 * efi_relocate_kernel() - copy memory area
 * @image_addr: pointer to address of memory area to copy
 * @image_size: size of memory area to copy
 * @alloc_size: minimum size of memory to allocate, must be greater or
 * equal to image_size
 * @preferred_addr: preferred target address
 * @alignment: minimum alignment of the allocated memory area. It
 * should be a power of two.
 * @min_addr: minimum target address
 *
 * Copy a memory area to a newly allocated memory area aligned according
 * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
 * is not available, the allocated address will not be below @min_addr.
 * On exit, @image_addr is updated to the target copy address that was used.
 *
 * This function is used to copy the Linux kernel verbatim. It does not apply
 * any relocation changes.
 *
 * Return: status code
 */

efi_status_t efi_relocate_kernel(unsigned long *image_addr,
     unsigned long image_size,
     unsigned long alloc_size,
     unsigned long preferred_addr,
     unsigned long alignment,
     unsigned long min_addr)
{
 unsigned long cur_image_addr;
 unsigned long new_addr = 0;
 efi_status_t status;
 unsigned long nr_pages;
 efi_physical_addr_t efi_addr = preferred_addr;

 if (!image_addr || !image_size || !alloc_size)
  return EFI_INVALID_PARAMETER;
 if (alloc_size < image_size)
  return EFI_INVALID_PARAMETER;

 cur_image_addr = *image_addr;

 /*
 * The EFI firmware loader could have placed the kernel image
 * anywhere in memory, but the kernel has restrictions on the
 * max physical address it can run at.  Some architectures
 * also have a preferred address, so first try to relocate
 * to the preferred address.  If that fails, allocate as low
 * as possible while respecting the required alignment.
 */

 nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
        EFI_LOADER_DATA, nr_pages, &efi_addr);
 new_addr = efi_addr;
 /*
 * If preferred address allocation failed allocate as low as
 * possible.
 */

 if (status != EFI_SUCCESS) {
  status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
          min_addr);
 }
 if (status != EFI_SUCCESS) {
  efi_err("Failed to allocate usable memory for kernel.\n");
  return status;
 }

 /*
 * We know source/dest won't overlap since both memory ranges
 * have been allocated by UEFI, so we can safely use memcpy.
 */

 memcpy((void *)new_addr, (void *)cur_image_addr, image_size);

 /* Return the new address of the relocated image. */
 *image_addr = new_addr;

 return status;
}

Messung V0.5
C=93 H=90 G=91

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.