0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) "efi: " fmt
0007
0008 #include <linux/init.h>
0009 #include <linux/kernel.h>
0010 #include <linux/efi.h>
0011 #include <linux/io.h>
0012 #include <asm/early_ioremap.h>
0013 #include <linux/memblock.h>
0014 #include <linux/slab.h>
0015
0016 static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
0017 {
0018 return memblock_phys_alloc(size, SMP_CACHE_BYTES);
0019 }
0020
0021 static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
0022 {
0023 unsigned int order = get_order(size);
0024 struct page *p = alloc_pages(GFP_KERNEL, order);
0025
0026 if (!p)
0027 return 0;
0028
0029 return PFN_PHYS(page_to_pfn(p));
0030 }
0031
0032 void __init __efi_memmap_free(u64 phys, unsigned long size, unsigned long flags)
0033 {
0034 if (flags & EFI_MEMMAP_MEMBLOCK) {
0035 if (slab_is_available())
0036 memblock_free_late(phys, size);
0037 else
0038 memblock_phys_free(phys, size);
0039 } else if (flags & EFI_MEMMAP_SLAB) {
0040 struct page *p = pfn_to_page(PHYS_PFN(phys));
0041 unsigned int order = get_order(size);
0042
0043 free_pages((unsigned long) page_address(p), order);
0044 }
0045 }
0046
0047 static void __init efi_memmap_free(void)
0048 {
0049 __efi_memmap_free(efi.memmap.phys_map,
0050 efi.memmap.desc_size * efi.memmap.nr_map,
0051 efi.memmap.flags);
0052 }
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 int __init efi_memmap_alloc(unsigned int num_entries,
0065 struct efi_memory_map_data *data)
0066 {
0067
0068 WARN_ON(data->phys_map || data->size);
0069
0070 data->size = num_entries * efi.memmap.desc_size;
0071 data->desc_version = efi.memmap.desc_version;
0072 data->desc_size = efi.memmap.desc_size;
0073 data->flags &= ~(EFI_MEMMAP_SLAB | EFI_MEMMAP_MEMBLOCK);
0074 data->flags |= efi.memmap.flags & EFI_MEMMAP_LATE;
0075
0076 if (slab_is_available()) {
0077 data->flags |= EFI_MEMMAP_SLAB;
0078 data->phys_map = __efi_memmap_alloc_late(data->size);
0079 } else {
0080 data->flags |= EFI_MEMMAP_MEMBLOCK;
0081 data->phys_map = __efi_memmap_alloc_early(data->size);
0082 }
0083
0084 if (!data->phys_map)
0085 return -ENOMEM;
0086 return 0;
0087 }
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 static int __init __efi_memmap_init(struct efi_memory_map_data *data)
0105 {
0106 struct efi_memory_map map;
0107 phys_addr_t phys_map;
0108
0109 if (efi_enabled(EFI_PARAVIRT))
0110 return 0;
0111
0112 phys_map = data->phys_map;
0113
0114 if (data->flags & EFI_MEMMAP_LATE)
0115 map.map = memremap(phys_map, data->size, MEMREMAP_WB);
0116 else
0117 map.map = early_memremap(phys_map, data->size);
0118
0119 if (!map.map) {
0120 pr_err("Could not map the memory map!\n");
0121 return -ENOMEM;
0122 }
0123
0124
0125 efi_memmap_free();
0126
0127 map.phys_map = data->phys_map;
0128 map.nr_map = data->size / data->desc_size;
0129 map.map_end = map.map + data->size;
0130
0131 map.desc_version = data->desc_version;
0132 map.desc_size = data->desc_size;
0133 map.flags = data->flags;
0134
0135 set_bit(EFI_MEMMAP, &efi.flags);
0136
0137 efi.memmap = map;
0138
0139 return 0;
0140 }
0141
0142
0143
0144
0145
0146
0147
0148
0149 int __init efi_memmap_init_early(struct efi_memory_map_data *data)
0150 {
0151
0152 WARN_ON(efi.memmap.flags & EFI_MEMMAP_LATE);
0153
0154 data->flags = 0;
0155 return __efi_memmap_init(data);
0156 }
0157
0158 void __init efi_memmap_unmap(void)
0159 {
0160 if (!efi_enabled(EFI_MEMMAP))
0161 return;
0162
0163 if (!(efi.memmap.flags & EFI_MEMMAP_LATE)) {
0164 unsigned long size;
0165
0166 size = efi.memmap.desc_size * efi.memmap.nr_map;
0167 early_memunmap(efi.memmap.map, size);
0168 } else {
0169 memunmap(efi.memmap.map);
0170 }
0171
0172 efi.memmap.map = NULL;
0173 clear_bit(EFI_MEMMAP, &efi.flags);
0174 }
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size)
0200 {
0201 struct efi_memory_map_data data = {
0202 .phys_map = addr,
0203 .size = size,
0204 .flags = EFI_MEMMAP_LATE,
0205 };
0206
0207
0208 WARN_ON(efi.memmap.map);
0209
0210
0211 WARN_ON(efi.memmap.flags & EFI_MEMMAP_LATE);
0212
0213
0214
0215
0216
0217
0218 data.desc_version = efi.memmap.desc_version;
0219 data.desc_size = efi.memmap.desc_size;
0220
0221 return __efi_memmap_init(&data);
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 int __init efi_memmap_install(struct efi_memory_map_data *data)
0235 {
0236 efi_memmap_unmap();
0237
0238 return __efi_memmap_init(data);
0239 }
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249 int __init efi_memmap_split_count(efi_memory_desc_t *md, struct range *range)
0250 {
0251 u64 m_start, m_end;
0252 u64 start, end;
0253 int count = 0;
0254
0255 start = md->phys_addr;
0256 end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1;
0257
0258
0259 m_start = range->start;
0260 m_end = range->end;
0261
0262 if (m_start <= start) {
0263
0264 if (start < m_end && m_end < end)
0265 count++;
0266 }
0267
0268 if (start < m_start && m_start < end) {
0269
0270 if (m_end < end)
0271 count += 2;
0272
0273 if (end <= m_end)
0274 count++;
0275 }
0276
0277 return count;
0278 }
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289 void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf,
0290 struct efi_mem_range *mem)
0291 {
0292 u64 m_start, m_end, m_attr;
0293 efi_memory_desc_t *md;
0294 u64 start, end;
0295 void *old, *new;
0296
0297
0298 m_start = mem->range.start;
0299 m_end = mem->range.end;
0300 m_attr = mem->attribute;
0301
0302
0303
0304
0305
0306
0307 if (!IS_ALIGNED(m_start, EFI_PAGE_SIZE) ||
0308 !IS_ALIGNED(m_end + 1, EFI_PAGE_SIZE)) {
0309 WARN_ON(1);
0310 return;
0311 }
0312
0313 for (old = old_memmap->map, new = buf;
0314 old < old_memmap->map_end;
0315 old += old_memmap->desc_size, new += old_memmap->desc_size) {
0316
0317
0318 memcpy(new, old, old_memmap->desc_size);
0319 md = new;
0320 start = md->phys_addr;
0321 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
0322
0323 if (m_start <= start && end <= m_end)
0324 md->attribute |= m_attr;
0325
0326 if (m_start <= start &&
0327 (start < m_end && m_end < end)) {
0328
0329 md->attribute |= m_attr;
0330 md->num_pages = (m_end - md->phys_addr + 1) >>
0331 EFI_PAGE_SHIFT;
0332
0333 new += old_memmap->desc_size;
0334 memcpy(new, old, old_memmap->desc_size);
0335 md = new;
0336 md->phys_addr = m_end + 1;
0337 md->num_pages = (end - md->phys_addr + 1) >>
0338 EFI_PAGE_SHIFT;
0339 }
0340
0341 if ((start < m_start && m_start < end) && m_end < end) {
0342
0343 md->num_pages = (m_start - md->phys_addr) >>
0344 EFI_PAGE_SHIFT;
0345
0346 new += old_memmap->desc_size;
0347 memcpy(new, old, old_memmap->desc_size);
0348 md = new;
0349 md->attribute |= m_attr;
0350 md->phys_addr = m_start;
0351 md->num_pages = (m_end - m_start + 1) >>
0352 EFI_PAGE_SHIFT;
0353
0354 new += old_memmap->desc_size;
0355 memcpy(new, old, old_memmap->desc_size);
0356 md = new;
0357 md->phys_addr = m_end + 1;
0358 md->num_pages = (end - m_end) >>
0359 EFI_PAGE_SHIFT;
0360 }
0361
0362 if ((start < m_start && m_start < end) &&
0363 (end <= m_end)) {
0364
0365 md->num_pages = (m_start - md->phys_addr) >>
0366 EFI_PAGE_SHIFT;
0367
0368 new += old_memmap->desc_size;
0369 memcpy(new, old, old_memmap->desc_size);
0370 md = new;
0371 md->phys_addr = m_start;
0372 md->num_pages = (end - md->phys_addr + 1) >>
0373 EFI_PAGE_SHIFT;
0374 md->attribute |= m_attr;
0375 }
0376 }
0377 }