/* Check if the table is already installed */
unaccepted_table = get_efi_config_table(unaccepted_table_guid); if (unaccepted_table) { 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; unsignedlong m = (unsignedlong)map->map;
d = efi_memdesc_ptr(m, map->desc_size, i); if (d->type != EFI_UNACCEPTED_MEMORY) continue;
/* * 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;
}
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 * * Consider case like this (assuming unit_size == 2MB): * * | 4k | 2044k | 2048k | * ^ 0x0 ^ 2MB ^ 4MB * * Only the first 4k has been accepted. The 0MB->2MB region can not be * represented in the bitmap. The 2MB->4MB region can be represented in * the bitmap. But, the 0MB->4MB region is <2*unit_size and will be * immediately accepted in its entirety.
*/ if (end - start < 2 * unit_size) {
arch_accept_memory(start, end); return;
}
/* * No matter how the start and end are aligned, at least one unaccepted * unit_size area will remain to be marked in the bitmap.
*/
/* Immediately accept a <unit_size piece at the start: */ if (start & unit_mask) {
arch_accept_memory(start, round_up(start, unit_size));
start = round_up(start, unit_size);
}
/* Immediately accept a <unit_size piece at the end: */ if (end & unit_mask) {
arch_accept_memory(round_down(end, unit_size), end);
end = round_down(end, unit_size);
}
/* * Accept part of the range that before phys_base and cannot be recorded * into the bitmap.
*/ if (start < unaccepted_table->phys_base) {
arch_accept_memory(start,
min(unaccepted_table->phys_base, end));
start = unaccepted_table->phys_base;
}
/* Nothing to record */ if (end < unaccepted_table->phys_base) return;
/* Translate to offsets from the beginning of the bitmap */
start -= unaccepted_table->phys_base;
end -= unaccepted_table->phys_base;
/* Accept memory that doesn't fit into bitmap */ if (end > bitmap_size * unit_size * BITS_PER_BYTE) { unsignedlong phys_start, phys_end;
arch_accept_memory(phys_start, phys_end);
end = bitmap_size * unit_size * BITS_PER_BYTE;
}
/* * 'start' and 'end' are now both unit_size-aligned. * Record the range as being unaccepted:
*/
bitmap_set(unaccepted_table->bitmap,
start / unit_size, (end - start) / unit_size);
}
/* * Only care for the part of the range that is represented * in the bitmap.
*/ if (start < unaccepted_table->phys_base)
start = unaccepted_table->phys_base; if (end < unaccepted_table->phys_base) return;
/* Translate to offsets from the beginning of the bitmap */
start -= unaccepted_table->phys_base;
end -= unaccepted_table->phys_base;
/* Make sure not to overrun the bitmap */ if (end > unaccepted_table->size * unit_size * BITS_PER_BYTE)
end = unaccepted_table->size * unit_size * BITS_PER_BYTE;
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.