1*2053bc57SKirill A. Shutemov // SPDX-License-Identifier: GPL-2.0-only 2*2053bc57SKirill A. Shutemov 3*2053bc57SKirill A. Shutemov #include <linux/efi.h> 4*2053bc57SKirill A. Shutemov #include <linux/memblock.h> 5*2053bc57SKirill A. Shutemov #include <linux/spinlock.h> 6*2053bc57SKirill A. Shutemov #include <asm/unaccepted_memory.h> 7*2053bc57SKirill A. Shutemov 8*2053bc57SKirill A. Shutemov /* Protects unaccepted memory bitmap */ 9*2053bc57SKirill A. Shutemov static DEFINE_SPINLOCK(unaccepted_memory_lock); 10*2053bc57SKirill A. Shutemov 11*2053bc57SKirill A. Shutemov /* 12*2053bc57SKirill A. Shutemov * accept_memory() -- Consult bitmap and accept the memory if needed. 13*2053bc57SKirill A. Shutemov * 14*2053bc57SKirill A. Shutemov * Only memory that is explicitly marked as unaccepted in the bitmap requires 15*2053bc57SKirill A. Shutemov * an action. All the remaining memory is implicitly accepted and doesn't need 16*2053bc57SKirill A. Shutemov * acceptance. 17*2053bc57SKirill A. Shutemov * 18*2053bc57SKirill A. Shutemov * No need to accept: 19*2053bc57SKirill A. Shutemov * - anything if the system has no unaccepted table; 20*2053bc57SKirill A. Shutemov * - memory that is below phys_base; 21*2053bc57SKirill A. Shutemov * - memory that is above the memory that addressable by the bitmap; 22*2053bc57SKirill A. Shutemov */ 23*2053bc57SKirill A. Shutemov void accept_memory(phys_addr_t start, phys_addr_t end) 24*2053bc57SKirill A. Shutemov { 25*2053bc57SKirill A. Shutemov struct efi_unaccepted_memory *unaccepted; 26*2053bc57SKirill A. Shutemov unsigned long range_start, range_end; 27*2053bc57SKirill A. Shutemov unsigned long flags; 28*2053bc57SKirill A. Shutemov u64 unit_size; 29*2053bc57SKirill A. Shutemov 30*2053bc57SKirill A. Shutemov unaccepted = efi_get_unaccepted_table(); 31*2053bc57SKirill A. Shutemov if (!unaccepted) 32*2053bc57SKirill A. Shutemov return; 33*2053bc57SKirill A. Shutemov 34*2053bc57SKirill A. Shutemov unit_size = unaccepted->unit_size; 35*2053bc57SKirill A. Shutemov 36*2053bc57SKirill A. Shutemov /* 37*2053bc57SKirill A. Shutemov * Only care for the part of the range that is represented 38*2053bc57SKirill A. Shutemov * in the bitmap. 39*2053bc57SKirill A. Shutemov */ 40*2053bc57SKirill A. Shutemov if (start < unaccepted->phys_base) 41*2053bc57SKirill A. Shutemov start = unaccepted->phys_base; 42*2053bc57SKirill A. Shutemov if (end < unaccepted->phys_base) 43*2053bc57SKirill A. Shutemov return; 44*2053bc57SKirill A. Shutemov 45*2053bc57SKirill A. Shutemov /* Translate to offsets from the beginning of the bitmap */ 46*2053bc57SKirill A. Shutemov start -= unaccepted->phys_base; 47*2053bc57SKirill A. Shutemov end -= unaccepted->phys_base; 48*2053bc57SKirill A. Shutemov 49*2053bc57SKirill A. Shutemov /* Make sure not to overrun the bitmap */ 50*2053bc57SKirill A. Shutemov if (end > unaccepted->size * unit_size * BITS_PER_BYTE) 51*2053bc57SKirill A. Shutemov end = unaccepted->size * unit_size * BITS_PER_BYTE; 52*2053bc57SKirill A. Shutemov 53*2053bc57SKirill A. Shutemov range_start = start / unit_size; 54*2053bc57SKirill A. Shutemov 55*2053bc57SKirill A. Shutemov spin_lock_irqsave(&unaccepted_memory_lock, flags); 56*2053bc57SKirill A. Shutemov for_each_set_bitrange_from(range_start, range_end, unaccepted->bitmap, 57*2053bc57SKirill A. Shutemov DIV_ROUND_UP(end, unit_size)) { 58*2053bc57SKirill A. Shutemov unsigned long phys_start, phys_end; 59*2053bc57SKirill A. Shutemov unsigned long len = range_end - range_start; 60*2053bc57SKirill A. Shutemov 61*2053bc57SKirill A. Shutemov phys_start = range_start * unit_size + unaccepted->phys_base; 62*2053bc57SKirill A. Shutemov phys_end = range_end * unit_size + unaccepted->phys_base; 63*2053bc57SKirill A. Shutemov 64*2053bc57SKirill A. Shutemov arch_accept_memory(phys_start, phys_end); 65*2053bc57SKirill A. Shutemov bitmap_clear(unaccepted->bitmap, range_start, len); 66*2053bc57SKirill A. Shutemov } 67*2053bc57SKirill A. Shutemov spin_unlock_irqrestore(&unaccepted_memory_lock, flags); 68*2053bc57SKirill A. Shutemov } 69*2053bc57SKirill A. Shutemov 70*2053bc57SKirill A. Shutemov bool range_contains_unaccepted_memory(phys_addr_t start, phys_addr_t end) 71*2053bc57SKirill A. Shutemov { 72*2053bc57SKirill A. Shutemov struct efi_unaccepted_memory *unaccepted; 73*2053bc57SKirill A. Shutemov unsigned long flags; 74*2053bc57SKirill A. Shutemov bool ret = false; 75*2053bc57SKirill A. Shutemov u64 unit_size; 76*2053bc57SKirill A. Shutemov 77*2053bc57SKirill A. Shutemov unaccepted = efi_get_unaccepted_table(); 78*2053bc57SKirill A. Shutemov if (!unaccepted) 79*2053bc57SKirill A. Shutemov return false; 80*2053bc57SKirill A. Shutemov 81*2053bc57SKirill A. Shutemov unit_size = unaccepted->unit_size; 82*2053bc57SKirill A. Shutemov 83*2053bc57SKirill A. Shutemov /* 84*2053bc57SKirill A. Shutemov * Only care for the part of the range that is represented 85*2053bc57SKirill A. Shutemov * in the bitmap. 86*2053bc57SKirill A. Shutemov */ 87*2053bc57SKirill A. Shutemov if (start < unaccepted->phys_base) 88*2053bc57SKirill A. Shutemov start = unaccepted->phys_base; 89*2053bc57SKirill A. Shutemov if (end < unaccepted->phys_base) 90*2053bc57SKirill A. Shutemov return false; 91*2053bc57SKirill A. Shutemov 92*2053bc57SKirill A. Shutemov /* Translate to offsets from the beginning of the bitmap */ 93*2053bc57SKirill A. Shutemov start -= unaccepted->phys_base; 94*2053bc57SKirill A. Shutemov end -= unaccepted->phys_base; 95*2053bc57SKirill A. Shutemov 96*2053bc57SKirill A. Shutemov /* Make sure not to overrun the bitmap */ 97*2053bc57SKirill A. Shutemov if (end > unaccepted->size * unit_size * BITS_PER_BYTE) 98*2053bc57SKirill A. Shutemov end = unaccepted->size * unit_size * BITS_PER_BYTE; 99*2053bc57SKirill A. Shutemov 100*2053bc57SKirill A. Shutemov spin_lock_irqsave(&unaccepted_memory_lock, flags); 101*2053bc57SKirill A. Shutemov while (start < end) { 102*2053bc57SKirill A. Shutemov if (test_bit(start / unit_size, unaccepted->bitmap)) { 103*2053bc57SKirill A. Shutemov ret = true; 104*2053bc57SKirill A. Shutemov break; 105*2053bc57SKirill A. Shutemov } 106*2053bc57SKirill A. Shutemov 107*2053bc57SKirill A. Shutemov start += unit_size; 108*2053bc57SKirill A. Shutemov } 109*2053bc57SKirill A. Shutemov spin_unlock_irqrestore(&unaccepted_memory_lock, flags); 110*2053bc57SKirill A. Shutemov 111*2053bc57SKirill A. Shutemov return ret; 112*2053bc57SKirill A. Shutemov } 113