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