1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2016 Toomas Soome <tsoome@me.com> 14 */ 15 16 /* 17 * Build smap like memory map from efi memmap. 18 */ 19 20 #include <stand.h> 21 #include <inttypes.h> 22 #include <efi.h> 23 #include <efilib.h> 24 #include <sys/param.h> 25 #include <sys/linker.h> 26 #include <sys/queue.h> 27 #include <sys/stddef.h> 28 #include <machine/metadata.h> 29 #include <machine/pc/bios.h> 30 #include "bootstrap.h" 31 32 struct smap_buf { 33 struct bios_smap sb_smap; 34 STAILQ_ENTRY(smap_buf) sb_bufs; 35 }; 36 37 static struct bios_smap *smapbase; 38 static int smaplen; 39 40 /* 41 * See ACPI 6.1 Table 15-330 UEFI Memory Types and mapping to ACPI address 42 * range types. 43 */ 44 static int 45 smap_type(int type) 46 { 47 switch (type) { 48 case EfiLoaderCode: 49 case EfiLoaderData: 50 case EfiBootServicesCode: 51 case EfiBootServicesData: 52 case EfiConventionalMemory: 53 return (SMAP_TYPE_MEMORY); 54 case EfiReservedMemoryType: 55 case EfiRuntimeServicesCode: 56 case EfiRuntimeServicesData: 57 case EfiMemoryMappedIO: 58 case EfiMemoryMappedIOPortSpace: 59 case EfiPalCode: 60 case EfiUnusableMemory: 61 return (SMAP_TYPE_RESERVED); 62 case EfiACPIReclaimMemory: 63 return (SMAP_TYPE_ACPI_RECLAIM); 64 case EfiACPIMemoryNVS: 65 return (SMAP_TYPE_ACPI_NVS); 66 } 67 return (SMAP_TYPE_RESERVED); 68 } 69 70 void 71 efi_getsmap(void) 72 { 73 UINTN size, desc_size, key; 74 EFI_MEMORY_DESCRIPTOR *efi_mmap, *p; 75 EFI_PHYSICAL_ADDRESS addr; 76 EFI_STATUS status; 77 STAILQ_HEAD(smap_head, smap_buf) head = 78 STAILQ_HEAD_INITIALIZER(head); 79 struct smap_buf *cur, *next; 80 int i, n, ndesc; 81 int type = -1; 82 83 size = 0; 84 status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); 85 efi_mmap = malloc(size); 86 status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL); 87 if (EFI_ERROR(status)) { 88 printf("GetMemoryMap: error %lu\n", EFI_ERROR_CODE(status)); 89 free(efi_mmap); 90 return; 91 } 92 93 STAILQ_INIT(&head); 94 n = 0; 95 i = 0; 96 p = efi_mmap; 97 next = NULL; 98 ndesc = size / desc_size; 99 while (i < ndesc) { 100 if (next == NULL) { 101 next = malloc(sizeof(*next)); 102 if (next == NULL) 103 break; 104 105 next->sb_smap.base = p->PhysicalStart; 106 next->sb_smap.length = 107 p->NumberOfPages << EFI_PAGE_SHIFT; 108 /* 109 * ACPI 6.1 tells the lower memory should be 110 * reported as normal memory, so we enforce 111 * page 0 type even as vmware maps it as 112 * acpi reclaimable. 113 */ 114 if (next->sb_smap.base == 0) 115 type = SMAP_TYPE_MEMORY; 116 else 117 type = smap_type(p->Type); 118 next->sb_smap.type = type; 119 120 STAILQ_INSERT_TAIL(&head, next, sb_bufs); 121 n++; 122 p = NextMemoryDescriptor(p, desc_size); 123 i++; 124 continue; 125 } 126 addr = next->sb_smap.base + next->sb_smap.length; 127 if ((smap_type(p->Type) == type) && 128 (p->PhysicalStart == addr)) { 129 next->sb_smap.length += 130 (p->NumberOfPages << EFI_PAGE_SHIFT); 131 p = NextMemoryDescriptor(p, desc_size); 132 i++; 133 } else 134 next = NULL; 135 } 136 smaplen = n; 137 if (smaplen > 0) { 138 smapbase = malloc(smaplen * sizeof(*smapbase)); 139 if (smapbase != NULL) { 140 n = 0; 141 STAILQ_FOREACH(cur, &head, sb_bufs) 142 smapbase[n++] = cur->sb_smap; 143 } 144 cur = STAILQ_FIRST(&head); 145 while (cur != NULL) { 146 next = STAILQ_NEXT(cur, sb_bufs); 147 free(cur); 148 cur = next; 149 } 150 } 151 free(efi_mmap); 152 } 153 154 void 155 efi_addsmapdata(struct preloaded_file *kfp) 156 { 157 size_t size; 158 159 if (smapbase == NULL || smaplen == 0) 160 return; 161 size = smaplen * sizeof(*smapbase); 162 file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase); 163 } 164 165 COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap); 166 167 static int 168 command_smap(int argc, char *argv[]) 169 { 170 u_int i; 171 172 if (smapbase == NULL || smaplen == 0) 173 return (CMD_ERROR); 174 175 for (i = 0; i < smaplen; i++) 176 printf("SMAP type=%02" PRIx32 " base=%016" PRIx64 177 " len=%016" PRIx64 "\n", smapbase[i].type, 178 smapbase[i].base, smapbase[i].length); 179 return (CMD_OK); 180 } 181