xref: /linux/drivers/firmware/efi/memmap.c (revision 60863c0d1a96b740048cc7d94a2d00d6f89ba3d8)
1*60863c0dSMatt Fleming /*
2*60863c0dSMatt Fleming  * Common EFI memory map functions.
3*60863c0dSMatt Fleming  */
4*60863c0dSMatt Fleming 
5*60863c0dSMatt Fleming #define pr_fmt(fmt) "efi: " fmt
6*60863c0dSMatt Fleming 
7*60863c0dSMatt Fleming #include <linux/init.h>
8*60863c0dSMatt Fleming #include <linux/kernel.h>
9*60863c0dSMatt Fleming #include <linux/efi.h>
10*60863c0dSMatt Fleming #include <linux/io.h>
11*60863c0dSMatt Fleming #include <asm/early_ioremap.h>
12*60863c0dSMatt Fleming 
13*60863c0dSMatt Fleming /**
14*60863c0dSMatt Fleming  * __efi_memmap_init - Common code for mapping the EFI memory map
15*60863c0dSMatt Fleming  * @data: EFI memory map data
16*60863c0dSMatt Fleming  * @late: Use early or late mapping function?
17*60863c0dSMatt Fleming  *
18*60863c0dSMatt Fleming  * This function takes care of figuring out which function to use to
19*60863c0dSMatt Fleming  * map the EFI memory map in efi.memmap based on how far into the boot
20*60863c0dSMatt Fleming  * we are.
21*60863c0dSMatt Fleming  *
22*60863c0dSMatt Fleming  * During bootup @late should be %false since we only have access to
23*60863c0dSMatt Fleming  * the early_memremap*() functions as the vmalloc space isn't setup.
24*60863c0dSMatt Fleming  * Once the kernel is fully booted we can fallback to the more robust
25*60863c0dSMatt Fleming  * memremap*() API.
26*60863c0dSMatt Fleming  *
27*60863c0dSMatt Fleming  * Returns zero on success, a negative error code on failure.
28*60863c0dSMatt Fleming  */
29*60863c0dSMatt Fleming static int __init
30*60863c0dSMatt Fleming __efi_memmap_init(struct efi_memory_map_data *data, bool late)
31*60863c0dSMatt Fleming {
32*60863c0dSMatt Fleming 	struct efi_memory_map map;
33*60863c0dSMatt Fleming 	phys_addr_t phys_map;
34*60863c0dSMatt Fleming 
35*60863c0dSMatt Fleming 	if (efi_enabled(EFI_PARAVIRT))
36*60863c0dSMatt Fleming 		return 0;
37*60863c0dSMatt Fleming 
38*60863c0dSMatt Fleming 	phys_map = data->phys_map;
39*60863c0dSMatt Fleming 
40*60863c0dSMatt Fleming 	if (late)
41*60863c0dSMatt Fleming 		map.map = memremap(phys_map, data->size, MEMREMAP_WB);
42*60863c0dSMatt Fleming 	else
43*60863c0dSMatt Fleming 		map.map = early_memremap(phys_map, data->size);
44*60863c0dSMatt Fleming 
45*60863c0dSMatt Fleming 	if (!map.map) {
46*60863c0dSMatt Fleming 		pr_err("Could not map the memory map!\n");
47*60863c0dSMatt Fleming 		return -ENOMEM;
48*60863c0dSMatt Fleming 	}
49*60863c0dSMatt Fleming 
50*60863c0dSMatt Fleming 	map.phys_map = data->phys_map;
51*60863c0dSMatt Fleming 	map.nr_map = data->size / data->desc_size;
52*60863c0dSMatt Fleming 	map.map_end = map.map + data->size;
53*60863c0dSMatt Fleming 
54*60863c0dSMatt Fleming 	map.desc_version = data->desc_version;
55*60863c0dSMatt Fleming 	map.desc_size = data->desc_size;
56*60863c0dSMatt Fleming 	map.late = late;
57*60863c0dSMatt Fleming 
58*60863c0dSMatt Fleming 	set_bit(EFI_MEMMAP, &efi.flags);
59*60863c0dSMatt Fleming 
60*60863c0dSMatt Fleming 	efi.memmap = map;
61*60863c0dSMatt Fleming 
62*60863c0dSMatt Fleming 	return 0;
63*60863c0dSMatt Fleming }
64*60863c0dSMatt Fleming 
65*60863c0dSMatt Fleming /**
66*60863c0dSMatt Fleming  * efi_memmap_init_early - Map the EFI memory map data structure
67*60863c0dSMatt Fleming  * @data: EFI memory map data
68*60863c0dSMatt Fleming  *
69*60863c0dSMatt Fleming  * Use early_memremap() to map the passed in EFI memory map and assign
70*60863c0dSMatt Fleming  * it to efi.memmap.
71*60863c0dSMatt Fleming  */
72*60863c0dSMatt Fleming int __init efi_memmap_init_early(struct efi_memory_map_data *data)
73*60863c0dSMatt Fleming {
74*60863c0dSMatt Fleming 	/* Cannot go backwards */
75*60863c0dSMatt Fleming 	WARN_ON(efi.memmap.late);
76*60863c0dSMatt Fleming 
77*60863c0dSMatt Fleming 	return __efi_memmap_init(data, false);
78*60863c0dSMatt Fleming }
79*60863c0dSMatt Fleming 
80*60863c0dSMatt Fleming void __init efi_memmap_unmap(void)
81*60863c0dSMatt Fleming {
82*60863c0dSMatt Fleming 	if (!efi.memmap.late) {
83*60863c0dSMatt Fleming 		unsigned long size;
84*60863c0dSMatt Fleming 
85*60863c0dSMatt Fleming 		size = efi.memmap.desc_size * efi.memmap.nr_map;
86*60863c0dSMatt Fleming 		early_memunmap(efi.memmap.map, size);
87*60863c0dSMatt Fleming 	} else {
88*60863c0dSMatt Fleming 		memunmap(efi.memmap.map);
89*60863c0dSMatt Fleming 	}
90*60863c0dSMatt Fleming 
91*60863c0dSMatt Fleming 	efi.memmap.map = NULL;
92*60863c0dSMatt Fleming 	clear_bit(EFI_MEMMAP, &efi.flags);
93*60863c0dSMatt Fleming }
94*60863c0dSMatt Fleming 
95*60863c0dSMatt Fleming /**
96*60863c0dSMatt Fleming  * efi_memmap_init_late - Map efi.memmap with memremap()
97*60863c0dSMatt Fleming  * @phys_addr: Physical address of the new EFI memory map
98*60863c0dSMatt Fleming  * @size: Size in bytes of the new EFI memory map
99*60863c0dSMatt Fleming  *
100*60863c0dSMatt Fleming  * Setup a mapping of the EFI memory map using ioremap_cache(). This
101*60863c0dSMatt Fleming  * function should only be called once the vmalloc space has been
102*60863c0dSMatt Fleming  * setup and is therefore not suitable for calling during early EFI
103*60863c0dSMatt Fleming  * initialise, e.g. in efi_init(). Additionally, it expects
104*60863c0dSMatt Fleming  * efi_memmap_init_early() to have already been called.
105*60863c0dSMatt Fleming  *
106*60863c0dSMatt Fleming  * The reason there are two EFI memmap initialisation
107*60863c0dSMatt Fleming  * (efi_memmap_init_early() and this late version) is because the
108*60863c0dSMatt Fleming  * early EFI memmap should be explicitly unmapped once EFI
109*60863c0dSMatt Fleming  * initialisation is complete as the fixmap space used to map the EFI
110*60863c0dSMatt Fleming  * memmap (via early_memremap()) is a scarce resource.
111*60863c0dSMatt Fleming  *
112*60863c0dSMatt Fleming  * This late mapping is intended to persist for the duration of
113*60863c0dSMatt Fleming  * runtime so that things like efi_mem_desc_lookup() and
114*60863c0dSMatt Fleming  * efi_mem_attributes() always work.
115*60863c0dSMatt Fleming  *
116*60863c0dSMatt Fleming  * Returns zero on success, a negative error code on failure.
117*60863c0dSMatt Fleming  */
118*60863c0dSMatt Fleming int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
119*60863c0dSMatt Fleming {
120*60863c0dSMatt Fleming 	struct efi_memory_map_data data = {
121*60863c0dSMatt Fleming 		.phys_map = addr,
122*60863c0dSMatt Fleming 		.size = size,
123*60863c0dSMatt Fleming 	};
124*60863c0dSMatt Fleming 
125*60863c0dSMatt Fleming 	/* Did we forget to unmap the early EFI memmap? */
126*60863c0dSMatt Fleming 	WARN_ON(efi.memmap.map);
127*60863c0dSMatt Fleming 
128*60863c0dSMatt Fleming 	/* Were we already called? */
129*60863c0dSMatt Fleming 	WARN_ON(efi.memmap.late);
130*60863c0dSMatt Fleming 
131*60863c0dSMatt Fleming 	/*
132*60863c0dSMatt Fleming 	 * It makes no sense to allow callers to register different
133*60863c0dSMatt Fleming 	 * values for the following fields. Copy them out of the
134*60863c0dSMatt Fleming 	 * existing early EFI memmap.
135*60863c0dSMatt Fleming 	 */
136*60863c0dSMatt Fleming 	data.desc_version = efi.memmap.desc_version;
137*60863c0dSMatt Fleming 	data.desc_size = efi.memmap.desc_size;
138*60863c0dSMatt Fleming 
139*60863c0dSMatt Fleming 	return __efi_memmap_init(&data, true);
140*60863c0dSMatt Fleming }
141*60863c0dSMatt Fleming 
142*60863c0dSMatt Fleming /**
143*60863c0dSMatt Fleming  * efi_memmap_split_count - Count number of additional EFI memmap entries
144*60863c0dSMatt Fleming  * @md: EFI memory descriptor to split
145*60863c0dSMatt Fleming  * @range: Address range (start, end) to split around
146*60863c0dSMatt Fleming  *
147*60863c0dSMatt Fleming  * Returns the number of additional EFI memmap entries required to
148*60863c0dSMatt Fleming  * accomodate @range.
149*60863c0dSMatt Fleming  */
150*60863c0dSMatt Fleming int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range)
151*60863c0dSMatt Fleming {
152*60863c0dSMatt Fleming 	u64 m_start, m_end;
153*60863c0dSMatt Fleming 	u64 start, end;
154*60863c0dSMatt Fleming 	int count = 0;
155*60863c0dSMatt Fleming 
156*60863c0dSMatt Fleming 	start = md->phys_addr;
157*60863c0dSMatt Fleming 	end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1;
158*60863c0dSMatt Fleming 
159*60863c0dSMatt Fleming 	/* modifying range */
160*60863c0dSMatt Fleming 	m_start = range->start;
161*60863c0dSMatt Fleming 	m_end = range->end;
162*60863c0dSMatt Fleming 
163*60863c0dSMatt Fleming 	if (m_start <= start) {
164*60863c0dSMatt Fleming 		/* split into 2 parts */
165*60863c0dSMatt Fleming 		if (start < m_end && m_end < end)
166*60863c0dSMatt Fleming 			count++;
167*60863c0dSMatt Fleming 	}
168*60863c0dSMatt Fleming 
169*60863c0dSMatt Fleming 	if (start < m_start && m_start < end) {
170*60863c0dSMatt Fleming 		/* split into 3 parts */
171*60863c0dSMatt Fleming 		if (m_end < end)
172*60863c0dSMatt Fleming 			count += 2;
173*60863c0dSMatt Fleming 		/* split into 2 parts */
174*60863c0dSMatt Fleming 		if (end <= m_end)
175*60863c0dSMatt Fleming 			count++;
176*60863c0dSMatt Fleming 	}
177*60863c0dSMatt Fleming 
178*60863c0dSMatt Fleming 	return count;
179*60863c0dSMatt Fleming }
180*60863c0dSMatt Fleming 
181*60863c0dSMatt Fleming /**
182*60863c0dSMatt Fleming  * efi_memmap_insert - Insert a memory region in an EFI memmap
183*60863c0dSMatt Fleming  * @old_memmap: The existing EFI memory map structure
184*60863c0dSMatt Fleming  * @buf: Address of buffer to store new map
185*60863c0dSMatt Fleming  * @mem: Memory map entry to insert
186*60863c0dSMatt Fleming  *
187*60863c0dSMatt Fleming  * It is suggested that you call efi_memmap_split_count() first
188*60863c0dSMatt Fleming  * to see how large @buf needs to be.
189*60863c0dSMatt Fleming  */
190*60863c0dSMatt Fleming void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf,
191*60863c0dSMatt Fleming 			      struct efi_mem_range *mem)
192*60863c0dSMatt Fleming {
193*60863c0dSMatt Fleming 	u64 m_start, m_end, m_attr;
194*60863c0dSMatt Fleming 	efi_memory_desc_t *md;
195*60863c0dSMatt Fleming 	u64 start, end;
196*60863c0dSMatt Fleming 	void *old, *new;
197*60863c0dSMatt Fleming 
198*60863c0dSMatt Fleming 	/* modifying range */
199*60863c0dSMatt Fleming 	m_start = mem->range.start;
200*60863c0dSMatt Fleming 	m_end = mem->range.end;
201*60863c0dSMatt Fleming 	m_attr = mem->attribute;
202*60863c0dSMatt Fleming 
203*60863c0dSMatt Fleming 	for (old = old_memmap->map, new = buf;
204*60863c0dSMatt Fleming 	     old < old_memmap->map_end;
205*60863c0dSMatt Fleming 	     old += old_memmap->desc_size, new += old_memmap->desc_size) {
206*60863c0dSMatt Fleming 
207*60863c0dSMatt Fleming 		/* copy original EFI memory descriptor */
208*60863c0dSMatt Fleming 		memcpy(new, old, old_memmap->desc_size);
209*60863c0dSMatt Fleming 		md = new;
210*60863c0dSMatt Fleming 		start = md->phys_addr;
211*60863c0dSMatt Fleming 		end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
212*60863c0dSMatt Fleming 
213*60863c0dSMatt Fleming 		if (m_start <= start && end <= m_end)
214*60863c0dSMatt Fleming 			md->attribute |= m_attr;
215*60863c0dSMatt Fleming 
216*60863c0dSMatt Fleming 		if (m_start <= start &&
217*60863c0dSMatt Fleming 		    (start < m_end && m_end < end)) {
218*60863c0dSMatt Fleming 			/* first part */
219*60863c0dSMatt Fleming 			md->attribute |= m_attr;
220*60863c0dSMatt Fleming 			md->num_pages = (m_end - md->phys_addr + 1) >>
221*60863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
222*60863c0dSMatt Fleming 			/* latter part */
223*60863c0dSMatt Fleming 			new += old_memmap->desc_size;
224*60863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
225*60863c0dSMatt Fleming 			md = new;
226*60863c0dSMatt Fleming 			md->phys_addr = m_end + 1;
227*60863c0dSMatt Fleming 			md->num_pages = (end - md->phys_addr + 1) >>
228*60863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
229*60863c0dSMatt Fleming 		}
230*60863c0dSMatt Fleming 
231*60863c0dSMatt Fleming 		if ((start < m_start && m_start < end) && m_end < end) {
232*60863c0dSMatt Fleming 			/* first part */
233*60863c0dSMatt Fleming 			md->num_pages = (m_start - md->phys_addr) >>
234*60863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
235*60863c0dSMatt Fleming 			/* middle part */
236*60863c0dSMatt Fleming 			new += old_memmap->desc_size;
237*60863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
238*60863c0dSMatt Fleming 			md = new;
239*60863c0dSMatt Fleming 			md->attribute |= m_attr;
240*60863c0dSMatt Fleming 			md->phys_addr = m_start;
241*60863c0dSMatt Fleming 			md->num_pages = (m_end - m_start + 1) >>
242*60863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
243*60863c0dSMatt Fleming 			/* last part */
244*60863c0dSMatt Fleming 			new += old_memmap->desc_size;
245*60863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
246*60863c0dSMatt Fleming 			md = new;
247*60863c0dSMatt Fleming 			md->phys_addr = m_end + 1;
248*60863c0dSMatt Fleming 			md->num_pages = (end - m_end) >>
249*60863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
250*60863c0dSMatt Fleming 		}
251*60863c0dSMatt Fleming 
252*60863c0dSMatt Fleming 		if ((start < m_start && m_start < end) &&
253*60863c0dSMatt Fleming 		    (end <= m_end)) {
254*60863c0dSMatt Fleming 			/* first part */
255*60863c0dSMatt Fleming 			md->num_pages = (m_start - md->phys_addr) >>
256*60863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
257*60863c0dSMatt Fleming 			/* latter part */
258*60863c0dSMatt Fleming 			new += old_memmap->desc_size;
259*60863c0dSMatt Fleming 			memcpy(new, old, old_memmap->desc_size);
260*60863c0dSMatt Fleming 			md = new;
261*60863c0dSMatt Fleming 			md->phys_addr = m_start;
262*60863c0dSMatt Fleming 			md->num_pages = (end - md->phys_addr + 1) >>
263*60863c0dSMatt Fleming 				EFI_PAGE_SHIFT;
264*60863c0dSMatt Fleming 			md->attribute |= m_attr;
265*60863c0dSMatt Fleming 		}
266*60863c0dSMatt Fleming 	}
267*60863c0dSMatt Fleming }
268