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