xref: /linux/drivers/firmware/efi/memmap.c (revision 20b1e22d01a4b0b11d3a1066e9feb04be38607ec)
160863c0dSMatt Fleming /*
260863c0dSMatt Fleming  * Common EFI memory map functions.
360863c0dSMatt Fleming  */
460863c0dSMatt Fleming 
560863c0dSMatt Fleming #define pr_fmt(fmt) "efi: " fmt
660863c0dSMatt Fleming 
760863c0dSMatt Fleming #include <linux/init.h>
860863c0dSMatt Fleming #include <linux/kernel.h>
960863c0dSMatt Fleming #include <linux/efi.h>
1060863c0dSMatt Fleming #include <linux/io.h>
1160863c0dSMatt Fleming #include <asm/early_ioremap.h>
12*20b1e22dSNicolai Stange #include <linux/memblock.h>
13*20b1e22dSNicolai Stange #include <linux/slab.h>
14*20b1e22dSNicolai Stange 
15*20b1e22dSNicolai Stange static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
16*20b1e22dSNicolai Stange {
17*20b1e22dSNicolai Stange 	return memblock_alloc(size, 0);
18*20b1e22dSNicolai Stange }
19*20b1e22dSNicolai Stange 
20*20b1e22dSNicolai Stange static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
21*20b1e22dSNicolai Stange {
22*20b1e22dSNicolai Stange 	unsigned int order = get_order(size);
23*20b1e22dSNicolai Stange 	struct page *p = alloc_pages(GFP_KERNEL, order);
24*20b1e22dSNicolai Stange 
25*20b1e22dSNicolai Stange 	if (!p)
26*20b1e22dSNicolai Stange 		return 0;
27*20b1e22dSNicolai Stange 
28*20b1e22dSNicolai Stange 	return PFN_PHYS(page_to_pfn(p));
29*20b1e22dSNicolai Stange }
30*20b1e22dSNicolai Stange 
31*20b1e22dSNicolai Stange /**
32*20b1e22dSNicolai Stange  * efi_memmap_alloc - Allocate memory for the EFI memory map
33*20b1e22dSNicolai Stange  * @num_entries: Number of entries in the allocated map.
34*20b1e22dSNicolai Stange  *
35*20b1e22dSNicolai Stange  * Depending on whether mm_init() has already been invoked or not,
36*20b1e22dSNicolai Stange  * either memblock or "normal" page allocation is used.
37*20b1e22dSNicolai Stange  *
38*20b1e22dSNicolai Stange  * Returns the physical address of the allocated memory map on
39*20b1e22dSNicolai Stange  * success, zero on failure.
40*20b1e22dSNicolai Stange  */
41*20b1e22dSNicolai Stange phys_addr_t __init efi_memmap_alloc(unsigned int num_entries)
42*20b1e22dSNicolai Stange {
43*20b1e22dSNicolai Stange 	unsigned long size = num_entries * efi.memmap.desc_size;
44*20b1e22dSNicolai Stange 
45*20b1e22dSNicolai Stange 	if (slab_is_available())
46*20b1e22dSNicolai Stange 		return __efi_memmap_alloc_late(size);
47*20b1e22dSNicolai Stange 
48*20b1e22dSNicolai Stange 	return __efi_memmap_alloc_early(size);
49*20b1e22dSNicolai Stange }
5060863c0dSMatt Fleming 
5160863c0dSMatt Fleming /**
5260863c0dSMatt Fleming  * __efi_memmap_init - Common code for mapping the EFI memory map
5360863c0dSMatt Fleming  * @data: EFI memory map data
5460863c0dSMatt Fleming  * @late: Use early or late mapping function?
5560863c0dSMatt Fleming  *
5660863c0dSMatt Fleming  * This function takes care of figuring out which function to use to
5760863c0dSMatt Fleming  * map the EFI memory map in efi.memmap based on how far into the boot
5860863c0dSMatt Fleming  * we are.
5960863c0dSMatt Fleming  *
6060863c0dSMatt Fleming  * During bootup @late should be %false since we only have access to
6160863c0dSMatt Fleming  * the early_memremap*() functions as the vmalloc space isn't setup.
6260863c0dSMatt Fleming  * Once the kernel is fully booted we can fallback to the more robust
6360863c0dSMatt Fleming  * memremap*() API.
6460863c0dSMatt Fleming  *
6560863c0dSMatt Fleming  * Returns zero on success, a negative error code on failure.
6660863c0dSMatt Fleming  */
6760863c0dSMatt Fleming static int __init
6860863c0dSMatt Fleming __efi_memmap_init(struct efi_memory_map_data *data, bool late)
6960863c0dSMatt Fleming {
7060863c0dSMatt Fleming 	struct efi_memory_map map;
7160863c0dSMatt Fleming 	phys_addr_t phys_map;
7260863c0dSMatt Fleming 
7360863c0dSMatt Fleming 	if (efi_enabled(EFI_PARAVIRT))
7460863c0dSMatt Fleming 		return 0;
7560863c0dSMatt Fleming 
7660863c0dSMatt Fleming 	phys_map = data->phys_map;
7760863c0dSMatt Fleming 
7860863c0dSMatt Fleming 	if (late)
7960863c0dSMatt Fleming 		map.map = memremap(phys_map, data->size, MEMREMAP_WB);
8060863c0dSMatt Fleming 	else
8160863c0dSMatt Fleming 		map.map = early_memremap(phys_map, data->size);
8260863c0dSMatt Fleming 
8360863c0dSMatt Fleming 	if (!map.map) {
8460863c0dSMatt Fleming 		pr_err("Could not map the memory map!\n");
8560863c0dSMatt Fleming 		return -ENOMEM;
8660863c0dSMatt Fleming 	}
8760863c0dSMatt Fleming 
8860863c0dSMatt Fleming 	map.phys_map = data->phys_map;
8960863c0dSMatt Fleming 	map.nr_map = data->size / data->desc_size;
9060863c0dSMatt Fleming 	map.map_end = map.map + data->size;
9160863c0dSMatt Fleming 
9260863c0dSMatt Fleming 	map.desc_version = data->desc_version;
9360863c0dSMatt Fleming 	map.desc_size = data->desc_size;
9460863c0dSMatt Fleming 	map.late = late;
9560863c0dSMatt Fleming 
9660863c0dSMatt Fleming 	set_bit(EFI_MEMMAP, &efi.flags);
9760863c0dSMatt Fleming 
9860863c0dSMatt Fleming 	efi.memmap = map;
9960863c0dSMatt Fleming 
10060863c0dSMatt Fleming 	return 0;
10160863c0dSMatt Fleming }
10260863c0dSMatt Fleming 
10360863c0dSMatt Fleming /**
10460863c0dSMatt Fleming  * efi_memmap_init_early - Map the EFI memory map data structure
10560863c0dSMatt Fleming  * @data: EFI memory map data
10660863c0dSMatt Fleming  *
10760863c0dSMatt Fleming  * Use early_memremap() to map the passed in EFI memory map and assign
10860863c0dSMatt Fleming  * it to efi.memmap.
10960863c0dSMatt Fleming  */
11060863c0dSMatt Fleming int __init efi_memmap_init_early(struct efi_memory_map_data *data)
11160863c0dSMatt Fleming {
11260863c0dSMatt Fleming 	/* Cannot go backwards */
11360863c0dSMatt Fleming 	WARN_ON(efi.memmap.late);
11460863c0dSMatt Fleming 
11560863c0dSMatt Fleming 	return __efi_memmap_init(data, false);
11660863c0dSMatt Fleming }
11760863c0dSMatt Fleming 
11860863c0dSMatt Fleming void __init efi_memmap_unmap(void)
11960863c0dSMatt Fleming {
12060863c0dSMatt Fleming 	if (!efi.memmap.late) {
12160863c0dSMatt Fleming 		unsigned long size;
12260863c0dSMatt Fleming 
12360863c0dSMatt Fleming 		size = efi.memmap.desc_size * efi.memmap.nr_map;
12460863c0dSMatt Fleming 		early_memunmap(efi.memmap.map, size);
12560863c0dSMatt Fleming 	} else {
12660863c0dSMatt Fleming 		memunmap(efi.memmap.map);
12760863c0dSMatt Fleming 	}
12860863c0dSMatt Fleming 
12960863c0dSMatt Fleming 	efi.memmap.map = NULL;
13060863c0dSMatt Fleming 	clear_bit(EFI_MEMMAP, &efi.flags);
13160863c0dSMatt Fleming }
13260863c0dSMatt Fleming 
13360863c0dSMatt Fleming /**
13460863c0dSMatt Fleming  * efi_memmap_init_late - Map efi.memmap with memremap()
13560863c0dSMatt Fleming  * @phys_addr: Physical address of the new EFI memory map
13660863c0dSMatt Fleming  * @size: Size in bytes of the new EFI memory map
13760863c0dSMatt Fleming  *
13860863c0dSMatt Fleming  * Setup a mapping of the EFI memory map using ioremap_cache(). This
13960863c0dSMatt Fleming  * function should only be called once the vmalloc space has been
14060863c0dSMatt Fleming  * setup and is therefore not suitable for calling during early EFI
14160863c0dSMatt Fleming  * initialise, e.g. in efi_init(). Additionally, it expects
14260863c0dSMatt Fleming  * efi_memmap_init_early() to have already been called.
14360863c0dSMatt Fleming  *
14460863c0dSMatt Fleming  * The reason there are two EFI memmap initialisation
14560863c0dSMatt Fleming  * (efi_memmap_init_early() and this late version) is because the
14660863c0dSMatt Fleming  * early EFI memmap should be explicitly unmapped once EFI
14760863c0dSMatt Fleming  * initialisation is complete as the fixmap space used to map the EFI
14860863c0dSMatt Fleming  * memmap (via early_memremap()) is a scarce resource.
14960863c0dSMatt Fleming  *
15060863c0dSMatt Fleming  * This late mapping is intended to persist for the duration of
15160863c0dSMatt Fleming  * runtime so that things like efi_mem_desc_lookup() and
15260863c0dSMatt Fleming  * efi_mem_attributes() always work.
15360863c0dSMatt Fleming  *
15460863c0dSMatt Fleming  * Returns zero on success, a negative error code on failure.
15560863c0dSMatt Fleming  */
15660863c0dSMatt Fleming int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
15760863c0dSMatt Fleming {
15860863c0dSMatt Fleming 	struct efi_memory_map_data data = {
15960863c0dSMatt Fleming 		.phys_map = addr,
16060863c0dSMatt Fleming 		.size = size,
16160863c0dSMatt Fleming 	};
16260863c0dSMatt Fleming 
16360863c0dSMatt Fleming 	/* Did we forget to unmap the early EFI memmap? */
16460863c0dSMatt Fleming 	WARN_ON(efi.memmap.map);
16560863c0dSMatt Fleming 
16660863c0dSMatt Fleming 	/* Were we already called? */
16760863c0dSMatt Fleming 	WARN_ON(efi.memmap.late);
16860863c0dSMatt Fleming 
16960863c0dSMatt Fleming 	/*
17060863c0dSMatt Fleming 	 * It makes no sense to allow callers to register different
17160863c0dSMatt Fleming 	 * values for the following fields. Copy them out of the
17260863c0dSMatt Fleming 	 * existing early EFI memmap.
17360863c0dSMatt Fleming 	 */
17460863c0dSMatt Fleming 	data.desc_version = efi.memmap.desc_version;
17560863c0dSMatt Fleming 	data.desc_size = efi.memmap.desc_size;
17660863c0dSMatt Fleming 
17760863c0dSMatt Fleming 	return __efi_memmap_init(&data, true);
17860863c0dSMatt Fleming }
17960863c0dSMatt Fleming 
18060863c0dSMatt Fleming /**
181c45f4da3SMatt Fleming  * efi_memmap_install - Install a new EFI memory map in efi.memmap
182c45f4da3SMatt Fleming  * @addr: Physical address of the memory map
183c45f4da3SMatt Fleming  * @nr_map: Number of entries in the memory map
184c45f4da3SMatt Fleming  *
185c45f4da3SMatt Fleming  * Unlike efi_memmap_init_*(), this function does not allow the caller
186c45f4da3SMatt Fleming  * to switch from early to late mappings. It simply uses the existing
187c45f4da3SMatt Fleming  * mapping function and installs the new memmap.
188c45f4da3SMatt Fleming  *
189c45f4da3SMatt Fleming  * Returns zero on success, a negative error code on failure.
190c45f4da3SMatt Fleming  */
191c45f4da3SMatt Fleming int __init efi_memmap_install(phys_addr_t addr, unsigned int nr_map)
192c45f4da3SMatt Fleming {
193c45f4da3SMatt Fleming 	struct efi_memory_map_data data;
194c45f4da3SMatt Fleming 
195c45f4da3SMatt Fleming 	efi_memmap_unmap();
196c45f4da3SMatt Fleming 
197c45f4da3SMatt Fleming 	data.phys_map = addr;
198c45f4da3SMatt Fleming 	data.size = efi.memmap.desc_size * nr_map;
199c45f4da3SMatt Fleming 	data.desc_version = efi.memmap.desc_version;
200c45f4da3SMatt Fleming 	data.desc_size = efi.memmap.desc_size;
201c45f4da3SMatt Fleming 
202c45f4da3SMatt Fleming 	return __efi_memmap_init(&data, efi.memmap.late);
203c45f4da3SMatt Fleming }
204c45f4da3SMatt Fleming 
205c45f4da3SMatt Fleming /**
20660863c0dSMatt Fleming  * efi_memmap_split_count - Count number of additional EFI memmap entries
20760863c0dSMatt Fleming  * @md: EFI memory descriptor to split
20860863c0dSMatt Fleming  * @range: Address range (start, end) to split around
20960863c0dSMatt Fleming  *
21060863c0dSMatt Fleming  * Returns the number of additional EFI memmap entries required to
21160863c0dSMatt Fleming  * accomodate @range.
21260863c0dSMatt Fleming  */
21360863c0dSMatt Fleming int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range)
21460863c0dSMatt Fleming {
21560863c0dSMatt Fleming 	u64 m_start, m_end;
21660863c0dSMatt Fleming 	u64 start, end;
21760863c0dSMatt Fleming 	int count = 0;
21860863c0dSMatt Fleming 
21960863c0dSMatt Fleming 	start = md->phys_addr;
22060863c0dSMatt Fleming 	end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1;
22160863c0dSMatt Fleming 
22260863c0dSMatt Fleming 	/* modifying range */
22360863c0dSMatt Fleming 	m_start = range->start;
22460863c0dSMatt Fleming 	m_end = range->end;
22560863c0dSMatt Fleming 
22660863c0dSMatt Fleming 	if (m_start <= start) {
22760863c0dSMatt Fleming 		/* split into 2 parts */
22860863c0dSMatt Fleming 		if (start < m_end && m_end < end)
22960863c0dSMatt Fleming 			count++;
23060863c0dSMatt Fleming 	}
23160863c0dSMatt Fleming 
23260863c0dSMatt Fleming 	if (start < m_start && m_start < end) {
23360863c0dSMatt Fleming 		/* split into 3 parts */
23460863c0dSMatt Fleming 		if (m_end < end)
23560863c0dSMatt Fleming 			count += 2;
23660863c0dSMatt Fleming 		/* split into 2 parts */
23760863c0dSMatt Fleming 		if (end <= m_end)
23860863c0dSMatt Fleming 			count++;
23960863c0dSMatt Fleming 	}
24060863c0dSMatt Fleming 
24160863c0dSMatt Fleming 	return count;
24260863c0dSMatt Fleming }
24360863c0dSMatt Fleming 
24460863c0dSMatt Fleming /**
24560863c0dSMatt Fleming  * efi_memmap_insert - Insert a memory region in an EFI memmap
24660863c0dSMatt Fleming  * @old_memmap: The existing EFI memory map structure
24760863c0dSMatt Fleming  * @buf: Address of buffer to store new map
24860863c0dSMatt Fleming  * @mem: Memory map entry to insert
24960863c0dSMatt Fleming  *
25060863c0dSMatt Fleming  * It is suggested that you call efi_memmap_split_count() first
25160863c0dSMatt Fleming  * to see how large @buf needs to be.
25260863c0dSMatt Fleming  */
25360863c0dSMatt Fleming void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf,
25460863c0dSMatt Fleming 			      struct efi_mem_range *mem)
25560863c0dSMatt Fleming {
25660863c0dSMatt Fleming 	u64 m_start, m_end, m_attr;
25760863c0dSMatt Fleming 	efi_memory_desc_t *md;
25860863c0dSMatt Fleming 	u64 start, end;
25960863c0dSMatt Fleming 	void *old, *new;
26060863c0dSMatt Fleming 
26160863c0dSMatt Fleming 	/* modifying range */
26260863c0dSMatt Fleming 	m_start = mem->range.start;
26360863c0dSMatt Fleming 	m_end = mem->range.end;
26460863c0dSMatt Fleming 	m_attr = mem->attribute;
26560863c0dSMatt Fleming 
26692dc3350SMatt Fleming 	/*
26792dc3350SMatt Fleming 	 * The EFI memory map deals with regions in EFI_PAGE_SIZE
26892dc3350SMatt Fleming 	 * units. Ensure that the region described by 'mem' is aligned
26992dc3350SMatt Fleming 	 * correctly.
27092dc3350SMatt Fleming 	 */
27192dc3350SMatt Fleming 	if (!IS_ALIGNED(m_start, EFI_PAGE_SIZE) ||
27292dc3350SMatt Fleming 	    !IS_ALIGNED(m_end + 1, EFI_PAGE_SIZE)) {
27392dc3350SMatt Fleming 		WARN_ON(1);
27492dc3350SMatt Fleming 		return;
27592dc3350SMatt Fleming 	}
27692dc3350SMatt Fleming 
27760863c0dSMatt Fleming 	for (old = old_memmap->map, new = buf;
27860863c0dSMatt Fleming 	     old < old_memmap->map_end;
27960863c0dSMatt Fleming 	     old += old_memmap->desc_size, new += old_memmap->desc_size) {
28060863c0dSMatt Fleming 
28160863c0dSMatt Fleming 		/* copy original EFI memory descriptor */
28260863c0dSMatt Fleming 		memcpy(new, old, old_memmap->desc_size);
28360863c0dSMatt Fleming 		md = new;
28460863c0dSMatt Fleming 		start = md->phys_addr;
28560863c0dSMatt Fleming 		end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
28660863c0dSMatt Fleming 
28760863c0dSMatt Fleming 		if (m_start <= start && end <= m_end)
28860863c0dSMatt Fleming 			md->attribute |= m_attr;
28960863c0dSMatt Fleming 
29060863c0dSMatt Fleming 		if (m_start <= start &&
29160863c0dSMatt Fleming 		    (start < m_end && m_end < end)) {
29260863c0dSMatt Fleming 			/* first part */
29360863c0dSMatt Fleming 			md->attribute |= m_attr;
29460863c0dSMatt Fleming 			md->num_pages = (m_end - md->phys_addr + 1) >>
29560863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
29660863c0dSMatt Fleming 			/* latter part */
29760863c0dSMatt Fleming 			new += old_memmap->desc_size;
29860863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
29960863c0dSMatt Fleming 			md = new;
30060863c0dSMatt Fleming 			md->phys_addr = m_end + 1;
30160863c0dSMatt Fleming 			md->num_pages = (end - md->phys_addr + 1) >>
30260863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
30360863c0dSMatt Fleming 		}
30460863c0dSMatt Fleming 
30560863c0dSMatt Fleming 		if ((start < m_start && m_start < end) && m_end < end) {
30660863c0dSMatt Fleming 			/* first part */
30760863c0dSMatt Fleming 			md->num_pages = (m_start - md->phys_addr) >>
30860863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
30960863c0dSMatt Fleming 			/* middle part */
31060863c0dSMatt Fleming 			new += old_memmap->desc_size;
31160863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
31260863c0dSMatt Fleming 			md = new;
31360863c0dSMatt Fleming 			md->attribute |= m_attr;
31460863c0dSMatt Fleming 			md->phys_addr = m_start;
31560863c0dSMatt Fleming 			md->num_pages = (m_end - m_start + 1) >>
31660863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
31760863c0dSMatt Fleming 			/* last part */
31860863c0dSMatt Fleming 			new += old_memmap->desc_size;
31960863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
32060863c0dSMatt Fleming 			md = new;
32160863c0dSMatt Fleming 			md->phys_addr = m_end + 1;
32260863c0dSMatt Fleming 			md->num_pages = (end - m_end) >>
32360863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
32460863c0dSMatt Fleming 		}
32560863c0dSMatt Fleming 
32660863c0dSMatt Fleming 		if ((start < m_start && m_start < end) &&
32760863c0dSMatt Fleming 		    (end <= m_end)) {
32860863c0dSMatt Fleming 			/* first part */
32960863c0dSMatt Fleming 			md->num_pages = (m_start - md->phys_addr) >>
33060863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
33160863c0dSMatt Fleming 			/* latter part */
33260863c0dSMatt Fleming 			new += old_memmap->desc_size;
33360863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
33460863c0dSMatt Fleming 			md = new;
33560863c0dSMatt Fleming 			md->phys_addr = m_start;
33660863c0dSMatt Fleming 			md->num_pages = (end - md->phys_addr + 1) >>
33760863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
33860863c0dSMatt Fleming 			md->attribute |= m_attr;
33960863c0dSMatt Fleming 		}
34060863c0dSMatt Fleming 	}
34160863c0dSMatt Fleming }
342