aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform/efi/quirks.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/platform/efi/quirks.c')
-rw-r--r--arch/x86/platform/efi/quirks.c79
1 files changed, 62 insertions, 17 deletions
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 2d66db8f80f9..ed30e79347e8 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -131,6 +131,27 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
131EXPORT_SYMBOL_GPL(efi_query_variable_store); 131EXPORT_SYMBOL_GPL(efi_query_variable_store);
132 132
133/* 133/*
134 * Helper function for efi_reserve_boot_services() to figure out if we
135 * can free regions in efi_free_boot_services().
136 *
137 * Use this function to ensure we do not free regions owned by somebody
138 * else. We must only reserve (and then free) regions:
139 *
140 * - Not within any part of the kernel
141 * - Not the BIOS reserved area (E820_RESERVED, E820_NVS, etc)
142 */
143static bool can_free_region(u64 start, u64 size)
144{
145 if (start + size > __pa_symbol(_text) && start <= __pa_symbol(_end))
146 return false;
147
148 if (!e820_all_mapped(start, start+size, E820_RAM))
149 return false;
150
151 return true;
152}
153
154/*
134 * The UEFI specification makes it clear that the operating system is free to do 155 * The UEFI specification makes it clear that the operating system is free to do
135 * whatever it wants with boot services code after ExitBootServices() has been 156 * whatever it wants with boot services code after ExitBootServices() has been
136 * called. Ignoring this recommendation a significant bunch of EFI implementations 157 * called. Ignoring this recommendation a significant bunch of EFI implementations
@@ -147,26 +168,50 @@ void __init efi_reserve_boot_services(void)
147 efi_memory_desc_t *md = p; 168 efi_memory_desc_t *md = p;
148 u64 start = md->phys_addr; 169 u64 start = md->phys_addr;
149 u64 size = md->num_pages << EFI_PAGE_SHIFT; 170 u64 size = md->num_pages << EFI_PAGE_SHIFT;
171 bool already_reserved;
150 172
151 if (md->type != EFI_BOOT_SERVICES_CODE && 173 if (md->type != EFI_BOOT_SERVICES_CODE &&
152 md->type != EFI_BOOT_SERVICES_DATA) 174 md->type != EFI_BOOT_SERVICES_DATA)
153 continue; 175 continue;
154 /* Only reserve where possible: 176
155 * - Not within any already allocated areas 177 already_reserved = memblock_is_region_reserved(start, size);
156 * - Not over any memory area (really needed, if above?) 178
157 * - Not within any part of the kernel 179 /*
158 * - Not the bios reserved area 180 * Because the following memblock_reserve() is paired
159 */ 181 * with free_bootmem_late() for this region in
160 if ((start + size > __pa_symbol(_text) 182 * efi_free_boot_services(), we must be extremely
161 && start <= __pa_symbol(_end)) || 183 * careful not to reserve, and subsequently free,
162 !e820_all_mapped(start, start+size, E820_RAM) || 184 * critical regions of memory (like the kernel image) or
163 memblock_is_region_reserved(start, size)) { 185 * those regions that somebody else has already
164 /* Could not reserve, skip it */ 186 * reserved.
165 md->num_pages = 0; 187 *
166 memblock_dbg("Could not reserve boot range [0x%010llx-0x%010llx]\n", 188 * A good example of a critical region that must not be
167 start, start+size-1); 189 * freed is page zero (first 4Kb of memory), which may
168 } else 190 * contain boot services code/data but is marked
191 * E820_RESERVED by trim_bios_range().
192 */
193 if (!already_reserved) {
169 memblock_reserve(start, size); 194 memblock_reserve(start, size);
195
196 /*
197 * If we are the first to reserve the region, no
198 * one else cares about it. We own it and can
199 * free it later.
200 */
201 if (can_free_region(start, size))
202 continue;
203 }
204
205 /*
206 * We don't own the region. We must not free it.
207 *
208 * Setting this bit for a boot services region really
209 * doesn't make sense as far as the firmware is
210 * concerned, but it does provide us with a way to tag
211 * those regions that must not be paired with
212 * free_bootmem_late().
213 */
214 md->attribute |= EFI_MEMORY_RUNTIME;
170 } 215 }
171} 216}
172 217
@@ -183,8 +228,8 @@ void __init efi_free_boot_services(void)
183 md->type != EFI_BOOT_SERVICES_DATA) 228 md->type != EFI_BOOT_SERVICES_DATA)
184 continue; 229 continue;
185 230
186 /* Could not reserve boot area */ 231 /* Do not free, someone else owns it: */
187 if (!size) 232 if (md->attribute & EFI_MEMORY_RUNTIME)
188 continue; 233 continue;
189 234
190 free_bootmem_late(start, size); 235 free_bootmem_late(start, size);