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
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.
13 * Copyright 2016 Toomas Soome <tsoome@me.com>
17 * Build smap like memory map from efi memmap.
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"
33 struct bios_smap sb_smap
;
34 STAILQ_ENTRY(smap_buf
) sb_bufs
;
37 static struct bios_smap
*smapbase
;
41 * See ACPI 6.1 Table 15-330 UEFI Memory Types and mapping to ACPI address
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
:
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
);
67 return (SMAP_TYPE_RESERVED
);
73 UINTN size
, desc_size
, key
;
74 EFI_MEMORY_DESCRIPTOR
*efi_mmap
, *p
;
75 EFI_PHYSICAL_ADDRESS addr
;
77 STAILQ_HEAD(smap_head
, smap_buf
) head
=
78 STAILQ_HEAD_INITIALIZER(head
);
79 struct smap_buf
*cur
, *next
;
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
));
98 ndesc
= size
/ desc_size
;
101 next
= malloc(sizeof(*next
));
105 next
->sb_smap
.base
= p
->PhysicalStart
;
106 next
->sb_smap
.length
=
107 p
->NumberOfPages
<< EFI_PAGE_SHIFT
;
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
114 if (next
->sb_smap
.base
== 0)
115 type
= SMAP_TYPE_MEMORY
;
117 type
= smap_type(p
->Type
);
118 next
->sb_smap
.type
= type
;
120 STAILQ_INSERT_TAIL(&head
, next
, sb_bufs
);
122 p
= NextMemoryDescriptor(p
, desc_size
);
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
);
138 smapbase
= malloc(smaplen
* sizeof(*smapbase
));
139 if (smapbase
!= NULL
) {
141 STAILQ_FOREACH(cur
, &head
, sb_bufs
)
142 smapbase
[n
++] = cur
->sb_smap
;
144 cur
= STAILQ_FIRST(&head
);
145 while (cur
!= NULL
) {
146 next
= STAILQ_NEXT(cur
, sb_bufs
);
155 efi_addsmapdata(struct preloaded_file
*kfp
)
159 if (smapbase
== NULL
|| smaplen
== 0)
161 size
= smaplen
* sizeof(*smapbase
);
162 file_addmetadata(kfp
, MODINFOMD_SMAP
, size
, smapbase
);
165 COMMAND_SET(smap
, "smap", "show BIOS SMAP", command_smap
);
168 command_smap(int argc
, char *argv
[])
172 if (smapbase
== NULL
|| smaplen
== 0)
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
);