xref: /freebsd/stand/i386/libi386/biossmap.c (revision 8a802df1de2d77fd0a62996bd785ca3f1326887f)
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * Obtain memory configuration information from the BIOS
29  */
30 #include <stand.h>
31 #include <sys/param.h>
32 #include <sys/linker.h>
33 #include <sys/queue.h>
34 #include <sys/stddef.h>
35 #include <machine/metadata.h>
36 #include <machine/pc/bios.h>
37 #include "bootstrap.h"
38 #include "libi386.h"
39 #include "btxv86.h"
40 
41 struct smap_buf {
42 	struct bios_smap	smap;
43 	uint32_t		xattr;	/* Extended attribute from ACPI 3.0 */
44 	STAILQ_ENTRY(smap_buf)	bufs;
45 };
46 
47 #define	SMAP_BUFSIZE		offsetof(struct smap_buf, bufs)
48 
49 static struct bios_smap		*smapbase;
50 static uint32_t			*smapattr;
51 static u_int			smaplen;
52 
53 void
54 bios_getsmap(void)
55 {
56 	struct smap_buf		buf;
57 	STAILQ_HEAD(smap_head, smap_buf) head =
58 	    STAILQ_HEAD_INITIALIZER(head);
59 	struct smap_buf		*cur, *next;
60 	u_int			n, x;
61 
62 	STAILQ_INIT(&head);
63 	n = 0;
64 	x = 0;
65 	v86.ebx = 0;
66 	do {
67 		v86.ctl = V86_FLAGS;
68 		v86.addr = 0x15;
69 		v86.eax = 0xe820;	/* int 0x15 function 0xe820 */
70 		v86.ecx = SMAP_BUFSIZE;
71 		v86.edx = SMAP_SIG;
72 		v86.es = VTOPSEG(&buf);
73 		v86.edi = VTOPOFF(&buf);
74 		v86int();
75 		if (V86_CY(v86.efl) || v86.eax != SMAP_SIG ||
76 		    v86.ecx < sizeof(buf.smap) || v86.ecx > SMAP_BUFSIZE)
77 			break;
78 
79 		next = malloc(sizeof(*next));
80 		if (next == NULL)
81 			break;
82 		next->smap = buf.smap;
83 		if (v86.ecx == SMAP_BUFSIZE) {
84 			next->xattr = buf.xattr;
85 			x++;
86 		}
87 		STAILQ_INSERT_TAIL(&head, next, bufs);
88 		n++;
89 	} while (v86.ebx != 0);
90 	smaplen = n;
91 
92 	if (smaplen > 0) {
93 		smapbase = malloc(smaplen * sizeof(*smapbase));
94 		if (smapbase != NULL) {
95 			n = 0;
96 			STAILQ_FOREACH(cur, &head, bufs)
97 				smapbase[n++] = cur->smap;
98 		}
99 		if (smaplen == x) {
100 			smapattr = malloc(smaplen * sizeof(*smapattr));
101 			if (smapattr != NULL) {
102 				n = 0;
103 				STAILQ_FOREACH(cur, &head, bufs)
104 					smapattr[n++] = cur->xattr &
105 					    SMAP_XATTR_MASK;
106 			}
107 		} else
108 			smapattr = NULL;
109 		cur = STAILQ_FIRST(&head);
110 		while (cur != NULL) {
111 			next = STAILQ_NEXT(cur, bufs);
112 			free(cur);
113 			cur = next;
114 		}
115 	}
116 }
117 
118 void
119 bios_addsmapdata(struct preloaded_file *kfp)
120 {
121 	size_t			size;
122 
123 	if (smapbase == NULL || smaplen == 0)
124 		return;
125 	size = smaplen * sizeof(*smapbase);
126 	file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase);
127 	if (smapattr != NULL) {
128 		size = smaplen * sizeof(*smapattr);
129 		file_addmetadata(kfp, MODINFOMD_SMAP_XATTR, size, smapattr);
130 	}
131 }
132 
133 COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap);
134 
135 static int
136 command_smap(int argc, char *argv[])
137 {
138 	u_int			i;
139 
140 	if (smapbase == NULL || smaplen == 0)
141 		return (CMD_ERROR);
142 	if (smapattr != NULL)
143 		for (i = 0; i < smaplen; i++)
144 			printf("SMAP type=%02x base=%016llx len=%016llx attr=%02x\n",
145 			    (unsigned int)smapbase[i].type,
146 			    (unsigned long long)smapbase[i].base,
147 			    (unsigned long long)smapbase[i].length,
148 			    (unsigned int)smapattr[i]);
149 	else
150 		for (i = 0; i < smaplen; i++)
151 			printf("SMAP type=%02x base=%016llx len=%016llx\n",
152 			    (unsigned int)smapbase[i].type,
153 			    (unsigned long long)smapbase[i].base,
154 			    (unsigned long long)smapbase[i].length);
155 	return (CMD_OK);
156 }
157