1*745e3ed8SKirill A. Shutemov // SPDX-License-Identifier: GPL-2.0-only 2*745e3ed8SKirill A. Shutemov 3*745e3ed8SKirill A. Shutemov #include <linux/efi.h> 4*745e3ed8SKirill A. Shutemov #include <asm/efi.h> 5*745e3ed8SKirill A. Shutemov #include "efistub.h" 6*745e3ed8SKirill A. Shutemov 7*745e3ed8SKirill A. Shutemov struct efi_unaccepted_memory *unaccepted_table; 8*745e3ed8SKirill A. Shutemov 9*745e3ed8SKirill A. Shutemov efi_status_t allocate_unaccepted_bitmap(__u32 nr_desc, 10*745e3ed8SKirill A. Shutemov struct efi_boot_memmap *map) 11*745e3ed8SKirill A. Shutemov { 12*745e3ed8SKirill A. Shutemov efi_guid_t unaccepted_table_guid = LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID; 13*745e3ed8SKirill A. Shutemov u64 unaccepted_start = ULLONG_MAX, unaccepted_end = 0, bitmap_size; 14*745e3ed8SKirill A. Shutemov efi_status_t status; 15*745e3ed8SKirill A. Shutemov int i; 16*745e3ed8SKirill A. Shutemov 17*745e3ed8SKirill A. Shutemov /* Check if the table is already installed */ 18*745e3ed8SKirill A. Shutemov unaccepted_table = get_efi_config_table(unaccepted_table_guid); 19*745e3ed8SKirill A. Shutemov if (unaccepted_table) { 20*745e3ed8SKirill A. Shutemov if (unaccepted_table->version != 1) { 21*745e3ed8SKirill A. Shutemov efi_err("Unknown version of unaccepted memory table\n"); 22*745e3ed8SKirill A. Shutemov return EFI_UNSUPPORTED; 23*745e3ed8SKirill A. Shutemov } 24*745e3ed8SKirill A. Shutemov return EFI_SUCCESS; 25*745e3ed8SKirill A. Shutemov } 26*745e3ed8SKirill A. Shutemov 27*745e3ed8SKirill A. Shutemov /* Check if there's any unaccepted memory and find the max address */ 28*745e3ed8SKirill A. Shutemov for (i = 0; i < nr_desc; i++) { 29*745e3ed8SKirill A. Shutemov efi_memory_desc_t *d; 30*745e3ed8SKirill A. Shutemov unsigned long m = (unsigned long)map->map; 31*745e3ed8SKirill A. Shutemov 32*745e3ed8SKirill A. Shutemov d = efi_early_memdesc_ptr(m, map->desc_size, i); 33*745e3ed8SKirill A. Shutemov if (d->type != EFI_UNACCEPTED_MEMORY) 34*745e3ed8SKirill A. Shutemov continue; 35*745e3ed8SKirill A. Shutemov 36*745e3ed8SKirill A. Shutemov unaccepted_start = min(unaccepted_start, d->phys_addr); 37*745e3ed8SKirill A. Shutemov unaccepted_end = max(unaccepted_end, 38*745e3ed8SKirill A. Shutemov d->phys_addr + d->num_pages * PAGE_SIZE); 39*745e3ed8SKirill A. Shutemov } 40*745e3ed8SKirill A. Shutemov 41*745e3ed8SKirill A. Shutemov if (unaccepted_start == ULLONG_MAX) 42*745e3ed8SKirill A. Shutemov return EFI_SUCCESS; 43*745e3ed8SKirill A. Shutemov 44*745e3ed8SKirill A. Shutemov unaccepted_start = round_down(unaccepted_start, 45*745e3ed8SKirill A. Shutemov EFI_UNACCEPTED_UNIT_SIZE); 46*745e3ed8SKirill A. Shutemov unaccepted_end = round_up(unaccepted_end, EFI_UNACCEPTED_UNIT_SIZE); 47*745e3ed8SKirill A. Shutemov 48*745e3ed8SKirill A. Shutemov /* 49*745e3ed8SKirill A. Shutemov * If unaccepted memory is present, allocate a bitmap to track what 50*745e3ed8SKirill A. Shutemov * memory has to be accepted before access. 51*745e3ed8SKirill A. Shutemov * 52*745e3ed8SKirill A. Shutemov * One bit in the bitmap represents 2MiB in the address space: 53*745e3ed8SKirill A. Shutemov * A 4k bitmap can track 64GiB of physical address space. 54*745e3ed8SKirill A. Shutemov * 55*745e3ed8SKirill A. Shutemov * In the worst case scenario -- a huge hole in the middle of the 56*745e3ed8SKirill A. Shutemov * address space -- It needs 256MiB to handle 4PiB of the address 57*745e3ed8SKirill A. Shutemov * space. 58*745e3ed8SKirill A. Shutemov * 59*745e3ed8SKirill A. Shutemov * The bitmap will be populated in setup_e820() according to the memory 60*745e3ed8SKirill A. Shutemov * map after efi_exit_boot_services(). 61*745e3ed8SKirill A. Shutemov */ 62*745e3ed8SKirill A. Shutemov bitmap_size = DIV_ROUND_UP(unaccepted_end - unaccepted_start, 63*745e3ed8SKirill A. Shutemov EFI_UNACCEPTED_UNIT_SIZE * BITS_PER_BYTE); 64*745e3ed8SKirill A. Shutemov 65*745e3ed8SKirill A. Shutemov status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, 66*745e3ed8SKirill A. Shutemov sizeof(*unaccepted_table) + bitmap_size, 67*745e3ed8SKirill A. Shutemov (void **)&unaccepted_table); 68*745e3ed8SKirill A. Shutemov if (status != EFI_SUCCESS) { 69*745e3ed8SKirill A. Shutemov efi_err("Failed to allocate unaccepted memory config table\n"); 70*745e3ed8SKirill A. Shutemov return status; 71*745e3ed8SKirill A. Shutemov } 72*745e3ed8SKirill A. Shutemov 73*745e3ed8SKirill A. Shutemov unaccepted_table->version = 1; 74*745e3ed8SKirill A. Shutemov unaccepted_table->unit_size = EFI_UNACCEPTED_UNIT_SIZE; 75*745e3ed8SKirill A. Shutemov unaccepted_table->phys_base = unaccepted_start; 76*745e3ed8SKirill A. Shutemov unaccepted_table->size = bitmap_size; 77*745e3ed8SKirill A. Shutemov memset(unaccepted_table->bitmap, 0, bitmap_size); 78*745e3ed8SKirill A. Shutemov 79*745e3ed8SKirill A. Shutemov status = efi_bs_call(install_configuration_table, 80*745e3ed8SKirill A. Shutemov &unaccepted_table_guid, unaccepted_table); 81*745e3ed8SKirill A. Shutemov if (status != EFI_SUCCESS) { 82*745e3ed8SKirill A. Shutemov efi_bs_call(free_pool, unaccepted_table); 83*745e3ed8SKirill A. Shutemov efi_err("Failed to install unaccepted memory config table!\n"); 84*745e3ed8SKirill A. Shutemov } 85*745e3ed8SKirill A. Shutemov 86*745e3ed8SKirill A. Shutemov return status; 87*745e3ed8SKirill A. Shutemov } 88*745e3ed8SKirill A. Shutemov 89*745e3ed8SKirill A. Shutemov /* 90*745e3ed8SKirill A. Shutemov * The accepted memory bitmap only works at unit_size granularity. Take 91*745e3ed8SKirill A. Shutemov * unaligned start/end addresses and either: 92*745e3ed8SKirill A. Shutemov * 1. Accepts the memory immediately and in its entirety 93*745e3ed8SKirill A. Shutemov * 2. Accepts unaligned parts, and marks *some* aligned part unaccepted 94*745e3ed8SKirill A. Shutemov * 95*745e3ed8SKirill A. Shutemov * The function will never reach the bitmap_set() with zero bits to set. 96*745e3ed8SKirill A. Shutemov */ 97*745e3ed8SKirill A. Shutemov void process_unaccepted_memory(u64 start, u64 end) 98*745e3ed8SKirill A. Shutemov { 99*745e3ed8SKirill A. Shutemov u64 unit_size = unaccepted_table->unit_size; 100*745e3ed8SKirill A. Shutemov u64 unit_mask = unaccepted_table->unit_size - 1; 101*745e3ed8SKirill A. Shutemov u64 bitmap_size = unaccepted_table->size; 102*745e3ed8SKirill A. Shutemov 103*745e3ed8SKirill A. Shutemov /* 104*745e3ed8SKirill A. Shutemov * Ensure that at least one bit will be set in the bitmap by 105*745e3ed8SKirill A. Shutemov * immediately accepting all regions under 2*unit_size. This is 106*745e3ed8SKirill A. Shutemov * imprecise and may immediately accept some areas that could 107*745e3ed8SKirill A. Shutemov * have been represented in the bitmap. But, results in simpler 108*745e3ed8SKirill A. Shutemov * code below 109*745e3ed8SKirill A. Shutemov * 110*745e3ed8SKirill A. Shutemov * Consider case like this (assuming unit_size == 2MB): 111*745e3ed8SKirill A. Shutemov * 112*745e3ed8SKirill A. Shutemov * | 4k | 2044k | 2048k | 113*745e3ed8SKirill A. Shutemov * ^ 0x0 ^ 2MB ^ 4MB 114*745e3ed8SKirill A. Shutemov * 115*745e3ed8SKirill A. Shutemov * Only the first 4k has been accepted. The 0MB->2MB region can not be 116*745e3ed8SKirill A. Shutemov * represented in the bitmap. The 2MB->4MB region can be represented in 117*745e3ed8SKirill A. Shutemov * the bitmap. But, the 0MB->4MB region is <2*unit_size and will be 118*745e3ed8SKirill A. Shutemov * immediately accepted in its entirety. 119*745e3ed8SKirill A. Shutemov */ 120*745e3ed8SKirill A. Shutemov if (end - start < 2 * unit_size) { 121*745e3ed8SKirill A. Shutemov arch_accept_memory(start, end); 122*745e3ed8SKirill A. Shutemov return; 123*745e3ed8SKirill A. Shutemov } 124*745e3ed8SKirill A. Shutemov 125*745e3ed8SKirill A. Shutemov /* 126*745e3ed8SKirill A. Shutemov * No matter how the start and end are aligned, at least one unaccepted 127*745e3ed8SKirill A. Shutemov * unit_size area will remain to be marked in the bitmap. 128*745e3ed8SKirill A. Shutemov */ 129*745e3ed8SKirill A. Shutemov 130*745e3ed8SKirill A. Shutemov /* Immediately accept a <unit_size piece at the start: */ 131*745e3ed8SKirill A. Shutemov if (start & unit_mask) { 132*745e3ed8SKirill A. Shutemov arch_accept_memory(start, round_up(start, unit_size)); 133*745e3ed8SKirill A. Shutemov start = round_up(start, unit_size); 134*745e3ed8SKirill A. Shutemov } 135*745e3ed8SKirill A. Shutemov 136*745e3ed8SKirill A. Shutemov /* Immediately accept a <unit_size piece at the end: */ 137*745e3ed8SKirill A. Shutemov if (end & unit_mask) { 138*745e3ed8SKirill A. Shutemov arch_accept_memory(round_down(end, unit_size), end); 139*745e3ed8SKirill A. Shutemov end = round_down(end, unit_size); 140*745e3ed8SKirill A. Shutemov } 141*745e3ed8SKirill A. Shutemov 142*745e3ed8SKirill A. Shutemov /* 143*745e3ed8SKirill A. Shutemov * Accept part of the range that before phys_base and cannot be recorded 144*745e3ed8SKirill A. Shutemov * into the bitmap. 145*745e3ed8SKirill A. Shutemov */ 146*745e3ed8SKirill A. Shutemov if (start < unaccepted_table->phys_base) { 147*745e3ed8SKirill A. Shutemov arch_accept_memory(start, 148*745e3ed8SKirill A. Shutemov min(unaccepted_table->phys_base, end)); 149*745e3ed8SKirill A. Shutemov start = unaccepted_table->phys_base; 150*745e3ed8SKirill A. Shutemov } 151*745e3ed8SKirill A. Shutemov 152*745e3ed8SKirill A. Shutemov /* Nothing to record */ 153*745e3ed8SKirill A. Shutemov if (end < unaccepted_table->phys_base) 154*745e3ed8SKirill A. Shutemov return; 155*745e3ed8SKirill A. Shutemov 156*745e3ed8SKirill A. Shutemov /* Translate to offsets from the beginning of the bitmap */ 157*745e3ed8SKirill A. Shutemov start -= unaccepted_table->phys_base; 158*745e3ed8SKirill A. Shutemov end -= unaccepted_table->phys_base; 159*745e3ed8SKirill A. Shutemov 160*745e3ed8SKirill A. Shutemov /* Accept memory that doesn't fit into bitmap */ 161*745e3ed8SKirill A. Shutemov if (end > bitmap_size * unit_size * BITS_PER_BYTE) { 162*745e3ed8SKirill A. Shutemov unsigned long phys_start, phys_end; 163*745e3ed8SKirill A. Shutemov 164*745e3ed8SKirill A. Shutemov phys_start = bitmap_size * unit_size * BITS_PER_BYTE + 165*745e3ed8SKirill A. Shutemov unaccepted_table->phys_base; 166*745e3ed8SKirill A. Shutemov phys_end = end + unaccepted_table->phys_base; 167*745e3ed8SKirill A. Shutemov 168*745e3ed8SKirill A. Shutemov arch_accept_memory(phys_start, phys_end); 169*745e3ed8SKirill A. Shutemov end = bitmap_size * unit_size * BITS_PER_BYTE; 170*745e3ed8SKirill A. Shutemov } 171*745e3ed8SKirill A. Shutemov 172*745e3ed8SKirill A. Shutemov /* 173*745e3ed8SKirill A. Shutemov * 'start' and 'end' are now both unit_size-aligned. 174*745e3ed8SKirill A. Shutemov * Record the range as being unaccepted: 175*745e3ed8SKirill A. Shutemov */ 176*745e3ed8SKirill A. Shutemov bitmap_set(unaccepted_table->bitmap, 177*745e3ed8SKirill A. Shutemov start / unit_size, (end - start) / unit_size); 178*745e3ed8SKirill A. Shutemov } 179*745e3ed8SKirill A. Shutemov 180*745e3ed8SKirill A. Shutemov void accept_memory(phys_addr_t start, phys_addr_t end) 181*745e3ed8SKirill A. Shutemov { 182*745e3ed8SKirill A. Shutemov unsigned long range_start, range_end; 183*745e3ed8SKirill A. Shutemov unsigned long bitmap_size; 184*745e3ed8SKirill A. Shutemov u64 unit_size; 185*745e3ed8SKirill A. Shutemov 186*745e3ed8SKirill A. Shutemov if (!unaccepted_table) 187*745e3ed8SKirill A. Shutemov return; 188*745e3ed8SKirill A. Shutemov 189*745e3ed8SKirill A. Shutemov unit_size = unaccepted_table->unit_size; 190*745e3ed8SKirill A. Shutemov 191*745e3ed8SKirill A. Shutemov /* 192*745e3ed8SKirill A. Shutemov * Only care for the part of the range that is represented 193*745e3ed8SKirill A. Shutemov * in the bitmap. 194*745e3ed8SKirill A. Shutemov */ 195*745e3ed8SKirill A. Shutemov if (start < unaccepted_table->phys_base) 196*745e3ed8SKirill A. Shutemov start = unaccepted_table->phys_base; 197*745e3ed8SKirill A. Shutemov if (end < unaccepted_table->phys_base) 198*745e3ed8SKirill A. Shutemov return; 199*745e3ed8SKirill A. Shutemov 200*745e3ed8SKirill A. Shutemov /* Translate to offsets from the beginning of the bitmap */ 201*745e3ed8SKirill A. Shutemov start -= unaccepted_table->phys_base; 202*745e3ed8SKirill A. Shutemov end -= unaccepted_table->phys_base; 203*745e3ed8SKirill A. Shutemov 204*745e3ed8SKirill A. Shutemov /* Make sure not to overrun the bitmap */ 205*745e3ed8SKirill A. Shutemov if (end > unaccepted_table->size * unit_size * BITS_PER_BYTE) 206*745e3ed8SKirill A. Shutemov end = unaccepted_table->size * unit_size * BITS_PER_BYTE; 207*745e3ed8SKirill A. Shutemov 208*745e3ed8SKirill A. Shutemov range_start = start / unit_size; 209*745e3ed8SKirill A. Shutemov bitmap_size = DIV_ROUND_UP(end, unit_size); 210*745e3ed8SKirill A. Shutemov 211*745e3ed8SKirill A. Shutemov for_each_set_bitrange_from(range_start, range_end, 212*745e3ed8SKirill A. Shutemov unaccepted_table->bitmap, bitmap_size) { 213*745e3ed8SKirill A. Shutemov unsigned long phys_start, phys_end; 214*745e3ed8SKirill A. Shutemov 215*745e3ed8SKirill A. Shutemov phys_start = range_start * unit_size + unaccepted_table->phys_base; 216*745e3ed8SKirill A. Shutemov phys_end = range_end * unit_size + unaccepted_table->phys_base; 217*745e3ed8SKirill A. Shutemov 218*745e3ed8SKirill A. Shutemov arch_accept_memory(phys_start, phys_end); 219*745e3ed8SKirill A. Shutemov bitmap_clear(unaccepted_table->bitmap, 220*745e3ed8SKirill A. Shutemov range_start, range_end - range_start); 221*745e3ed8SKirill A. Shutemov } 222*745e3ed8SKirill A. Shutemov } 223