1 /* 2 * Copyright (c) 2014 The FreeBSD Foundation 3 * Copyright (c) 2018 Andrew Turner 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 #include <sys/param.h> 8 #include <sys/systm.h> 9 #include <sys/efi.h> 10 #include <sys/efi_map.h> 11 #include <sys/physmem.h> 12 13 #include <machine/efi.h> 14 #include <machine/vmparam.h> 15 16 void 17 efi_map_foreach_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp) 18 { 19 struct efi_md *map, *p; 20 size_t efisz; 21 int ndesc, i; 22 23 /* 24 * Memory map data provided by UEFI via the GetMemoryMap 25 * Boot Services API. 26 */ 27 efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; 28 map = (struct efi_md *)((uint8_t *)efihdr + efisz); 29 30 if (efihdr->descriptor_size == 0) 31 return; 32 ndesc = efihdr->memory_size / efihdr->descriptor_size; 33 34 for (i = 0, p = map; i < ndesc; i++, 35 p = efi_next_descriptor(p, efihdr->descriptor_size)) { 36 cb(p, argp); 37 } 38 } 39 40 /* 41 * Handle the EFI memory map list. 42 * 43 * We will make two passes at this, the first (exclude == false) to populate 44 * physmem with valid physical memory ranges from recognized map entry types. 45 * In the second pass we will exclude memory ranges from physmem which must not 46 * be used for general allocations, either because they are used by runtime 47 * firmware or otherwise reserved. 48 * 49 * Adding the runtime-reserved memory ranges to physmem and excluding them 50 * later ensures that they are included in the DMAP, but excluded from 51 * phys_avail[]. 52 * 53 * Entry types not explicitly listed here are ignored and not mapped. 54 */ 55 static void 56 handle_efi_map_entry(struct efi_md *p, void *argp) 57 { 58 bool exclude = *(bool *)argp; 59 60 switch (p->md_type) { 61 case EFI_MD_TYPE_RECLAIM: 62 /* 63 * The recomended location for ACPI tables. Map into the 64 * DMAP so we can access them from userspace via /dev/mem. 65 */ 66 case EFI_MD_TYPE_RT_CODE: 67 /* 68 * Some UEFI implementations put the system table in the 69 * runtime code section. Include it in the DMAP, but will 70 * be excluded from phys_avail. 71 */ 72 case EFI_MD_TYPE_RT_DATA: 73 /* 74 * Runtime data will be excluded after the DMAP 75 * region is created to stop it from being added 76 * to phys_avail. 77 */ 78 if (exclude) { 79 physmem_exclude_region(p->md_phys, 80 p->md_pages * EFI_PAGE_SIZE, EXFLAG_NOALLOC); 81 break; 82 } 83 /* FALLTHROUGH */ 84 case EFI_MD_TYPE_CODE: 85 case EFI_MD_TYPE_DATA: 86 case EFI_MD_TYPE_BS_CODE: 87 case EFI_MD_TYPE_BS_DATA: 88 case EFI_MD_TYPE_FREE: 89 /* 90 * We're allowed to use any entry with these types. 91 */ 92 if (!exclude) 93 physmem_hardware_region(p->md_phys, 94 p->md_pages * EFI_PAGE_SIZE); 95 break; 96 default: 97 /* Other types shall not be handled by physmem. */ 98 break; 99 } 100 } 101 102 void 103 efi_map_add_entries(struct efi_map_header *efihdr) 104 { 105 bool exclude = false; 106 efi_map_foreach_entry(efihdr, handle_efi_map_entry, &exclude); 107 } 108 109 void 110 efi_map_exclude_entries(struct efi_map_header *efihdr) 111 { 112 bool exclude = true; 113 efi_map_foreach_entry(efihdr, handle_efi_map_entry, &exclude); 114 } 115 116 static void 117 print_efi_map_entry(struct efi_md *p, void *argp __unused) 118 { 119 const char *type; 120 static const char *types[] = { 121 "Reserved", 122 "LoaderCode", 123 "LoaderData", 124 "BootServicesCode", 125 "BootServicesData", 126 "RuntimeServicesCode", 127 "RuntimeServicesData", 128 "ConventionalMemory", 129 "UnusableMemory", 130 "ACPIReclaimMemory", 131 "ACPIMemoryNVS", 132 "MemoryMappedIO", 133 "MemoryMappedIOPortSpace", 134 "PalCode", 135 "PersistentMemory" 136 }; 137 138 if (p->md_type < nitems(types)) 139 type = types[p->md_type]; 140 else 141 type = "<INVALID>"; 142 printf("%23s %012jx %012jx %08jx ", type, (uintmax_t)p->md_phys, 143 (uintmax_t)p->md_virt, (uintmax_t)p->md_pages); 144 if (p->md_attr & EFI_MD_ATTR_UC) 145 printf("UC "); 146 if (p->md_attr & EFI_MD_ATTR_WC) 147 printf("WC "); 148 if (p->md_attr & EFI_MD_ATTR_WT) 149 printf("WT "); 150 if (p->md_attr & EFI_MD_ATTR_WB) 151 printf("WB "); 152 if (p->md_attr & EFI_MD_ATTR_UCE) 153 printf("UCE "); 154 if (p->md_attr & EFI_MD_ATTR_WP) 155 printf("WP "); 156 if (p->md_attr & EFI_MD_ATTR_RP) 157 printf("RP "); 158 if (p->md_attr & EFI_MD_ATTR_XP) 159 printf("XP "); 160 if (p->md_attr & EFI_MD_ATTR_NV) 161 printf("NV "); 162 if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE) 163 printf("MORE_RELIABLE "); 164 if (p->md_attr & EFI_MD_ATTR_RO) 165 printf("RO "); 166 if (p->md_attr & EFI_MD_ATTR_RT) 167 printf("RUNTIME"); 168 printf("\n"); 169 } 170 171 void 172 efi_map_print_entries(struct efi_map_header *efihdr) 173 { 174 175 printf("%23s %12s %12s %8s %4s\n", 176 "Type", "Physical", "Virtual", "#Pages", "Attr"); 177 efi_map_foreach_entry(efihdr, print_efi_map_entry, NULL); 178 } 179