18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
38c2ecf20Sopenharmony_ci#include <linux/efi.h>
48c2ecf20Sopenharmony_ci#include <asm/e820/api.h>
58c2ecf20Sopenharmony_ci#include "fake_mem.h"
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_civoid __init efi_fake_memmap_early(void)
88c2ecf20Sopenharmony_ci{
98c2ecf20Sopenharmony_ci	int i;
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci	/*
128c2ecf20Sopenharmony_ci	 * The late efi_fake_mem() call can handle all requests if
138c2ecf20Sopenharmony_ci	 * EFI_MEMORY_SP support is disabled.
148c2ecf20Sopenharmony_ci	 */
158c2ecf20Sopenharmony_ci	if (!efi_soft_reserve_enabled())
168c2ecf20Sopenharmony_ci		return;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
198c2ecf20Sopenharmony_ci		return;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	/*
228c2ecf20Sopenharmony_ci	 * Given that efi_fake_memmap() needs to perform memblock
238c2ecf20Sopenharmony_ci	 * allocations it needs to run after e820__memblock_setup().
248c2ecf20Sopenharmony_ci	 * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
258c2ecf20Sopenharmony_ci	 * address range that potentially needs to mark the memory as
268c2ecf20Sopenharmony_ci	 * reserved prior to e820__memblock_setup(). Update e820
278c2ecf20Sopenharmony_ci	 * directly if EFI_MEMORY_SP is specified for an
288c2ecf20Sopenharmony_ci	 * EFI_CONVENTIONAL_MEMORY descriptor.
298c2ecf20Sopenharmony_ci	 */
308c2ecf20Sopenharmony_ci	for (i = 0; i < nr_fake_mem; i++) {
318c2ecf20Sopenharmony_ci		struct efi_mem_range *mem = &efi_fake_mems[i];
328c2ecf20Sopenharmony_ci		efi_memory_desc_t *md;
338c2ecf20Sopenharmony_ci		u64 m_start, m_end;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci		if ((mem->attribute & EFI_MEMORY_SP) == 0)
368c2ecf20Sopenharmony_ci			continue;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci		m_start = mem->range.start;
398c2ecf20Sopenharmony_ci		m_end = mem->range.end;
408c2ecf20Sopenharmony_ci		for_each_efi_memory_desc(md) {
418c2ecf20Sopenharmony_ci			u64 start, end, size;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci			if (md->type != EFI_CONVENTIONAL_MEMORY)
448c2ecf20Sopenharmony_ci				continue;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci			start = md->phys_addr;
478c2ecf20Sopenharmony_ci			end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci			if (m_start <= end && m_end >= start)
508c2ecf20Sopenharmony_ci				/* fake range overlaps descriptor */;
518c2ecf20Sopenharmony_ci			else
528c2ecf20Sopenharmony_ci				continue;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci			/*
558c2ecf20Sopenharmony_ci			 * Trim the boundary of the e820 update to the
568c2ecf20Sopenharmony_ci			 * descriptor in case the fake range overlaps
578c2ecf20Sopenharmony_ci			 * !EFI_CONVENTIONAL_MEMORY
588c2ecf20Sopenharmony_ci			 */
598c2ecf20Sopenharmony_ci			start = max(start, m_start);
608c2ecf20Sopenharmony_ci			end = min(end, m_end);
618c2ecf20Sopenharmony_ci			size = end - start + 1;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci			if (end <= start)
648c2ecf20Sopenharmony_ci				continue;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci			/*
678c2ecf20Sopenharmony_ci			 * Ensure each efi_fake_mem instance results in
688c2ecf20Sopenharmony_ci			 * a unique e820 resource
698c2ecf20Sopenharmony_ci			 */
708c2ecf20Sopenharmony_ci			e820__range_remove(start, size, E820_TYPE_RAM, 1);
718c2ecf20Sopenharmony_ci			e820__range_add(start, size, E820_TYPE_SOFT_RESERVED);
728c2ecf20Sopenharmony_ci			e820__update_table(e820_table);
738c2ecf20Sopenharmony_ci		}
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci}
76