drivers/firmware/efi/libstub/unaccepted_memory.c

Source file repositories/reference/linux-study-clean/drivers/firmware/efi/libstub/unaccepted_memory.c

File Facts

System
Linux kernel
Corpus path
drivers/firmware/efi/libstub/unaccepted_memory.c
Extension
.c
Size
6865 bytes
Lines
224
Domain
Driver Families
Bucket
drivers/firmware
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (unaccepted_table->version != 1) {
			efi_err("Unknown version of unaccepted memory table\n");
			return EFI_UNSUPPORTED;
		}
		return EFI_SUCCESS;
	}

	/* Check if there's any unaccepted memory and find the max address */
	for (i = 0; i < nr_desc; i++) {
		efi_memory_desc_t *d;
		unsigned long m = (unsigned long)map->map;

		d = efi_memdesc_ptr(m, map->desc_size, i);
		if (d->type != EFI_UNACCEPTED_MEMORY)
			continue;

		unaccepted_start = min(unaccepted_start, d->phys_addr);
		unaccepted_end = max(unaccepted_end,
				     d->phys_addr + d->num_pages * PAGE_SIZE);
	}

	if (unaccepted_start == ULLONG_MAX)
		return EFI_SUCCESS;

	unaccepted_start = round_down(unaccepted_start,
				      EFI_UNACCEPTED_UNIT_SIZE);
	unaccepted_end = round_up(unaccepted_end, EFI_UNACCEPTED_UNIT_SIZE);

	/*
	 * If unaccepted memory is present, allocate a bitmap to track what
	 * memory has to be accepted before access.
	 *
	 * One bit in the bitmap represents 2MiB in the address space:
	 * A 4k bitmap can track 64GiB of physical address space.
	 *
	 * In the worst case scenario -- a huge hole in the middle of the
	 * address space -- It needs 256MiB to handle 4PiB of the address
	 * space.
	 *
	 * The bitmap will be populated in setup_e820() according to the memory
	 * map after efi_exit_boot_services().
	 */
	bitmap_size = DIV_ROUND_UP(unaccepted_end - unaccepted_start,
				   EFI_UNACCEPTED_UNIT_SIZE * BITS_PER_BYTE);

	status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
			     sizeof(*unaccepted_table) + bitmap_size,
			     (void **)&unaccepted_table);
	if (status != EFI_SUCCESS) {
		efi_err("Failed to allocate unaccepted memory config table\n");
		return status;
	}

	unaccepted_table->version = 1;
	unaccepted_table->unit_size = EFI_UNACCEPTED_UNIT_SIZE;
	unaccepted_table->phys_base = unaccepted_start;
	unaccepted_table->size = bitmap_size;
	memset(unaccepted_table->bitmap, 0, bitmap_size);

	status = efi_bs_call(install_configuration_table,
			     &unaccepted_table_guid, unaccepted_table);
	if (status != EFI_SUCCESS) {
		efi_bs_call(free_pool, unaccepted_table);
		efi_err("Failed to install unaccepted memory config table!\n");
	}

	return status;
}

/*
 * The accepted memory bitmap only works at unit_size granularity.  Take
 * unaligned start/end addresses and either:
 *  1. Accepts the memory immediately and in its entirety
 *  2. Accepts unaligned parts, and marks *some* aligned part unaccepted
 *
 * The function will never reach the bitmap_set() with zero bits to set.
 */
void process_unaccepted_memory(u64 start, u64 end)
{
	u64 unit_size = unaccepted_table->unit_size;
	u64 unit_mask = unaccepted_table->unit_size - 1;
	u64 bitmap_size = unaccepted_table->size;

	/*
	 * Ensure that at least one bit will be set in the bitmap by
	 * immediately accepting all regions under 2*unit_size.  This is
	 * imprecise and may immediately accept some areas that could
	 * have been represented in the bitmap.  But, results in simpler
	 * code below
	 *

Annotation

Implementation Notes