Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/i386/libi386/biosmem.c
34869 views
1
/*-
2
* Copyright (c) 1998 Michael Smith <[email protected]>
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 <machine/pc/bios.h>
32
#include "bootstrap.h"
33
#include "libi386.h"
34
#include "btxv86.h"
35
#include "smbios.h"
36
37
vm_offset_t memtop, memtop_copyin, high_heap_base;
38
uint32_t bios_basemem, bios_extmem, high_heap_size;
39
40
static struct bios_smap_xattr smap;
41
42
/*
43
* Used to track which method was used to set BIOS memory
44
* regions.
45
*/
46
static uint8_t b_bios_probed;
47
#define B_BASEMEM_E820 0x1
48
#define B_BASEMEM_12 0x2
49
#define B_EXTMEM_E820 0x4
50
#define B_EXTMEM_E801 0x8
51
#define B_EXTMEM_8800 0x10
52
53
/*
54
* The minimum amount of memory to reserve in bios_extmem for the heap.
55
*/
56
#define HEAP_MIN (64 * 1024 * 1024)
57
58
/*
59
* Products in this list need quirks to detect
60
* memory correctly. You need both maker and product as
61
* reported by smbios.
62
*/
63
/* e820 might not return useful extended memory */
64
#define BQ_DISTRUST_E820_EXTMEM 0x1
65
struct bios_getmem_quirks {
66
const char *bios_vendor;
67
const char *maker;
68
const char *product;
69
int quirk;
70
};
71
72
static struct bios_getmem_quirks quirks[] = {
73
{"coreboot", "Acer", "Peppy", BQ_DISTRUST_E820_EXTMEM},
74
{"coreboot", "Dell", "Wolf", BQ_DISTRUST_E820_EXTMEM},
75
{NULL, NULL, NULL, 0}
76
};
77
78
static int
79
bios_getquirks(void)
80
{
81
int i;
82
83
for (i = 0; quirks[i].quirk != 0; ++i) {
84
if (smbios_match(quirks[i].bios_vendor, quirks[i].maker,
85
quirks[i].product))
86
return (quirks[i].quirk);
87
}
88
89
return (0);
90
}
91
92
void
93
bios_getmem(void)
94
{
95
uint64_t size;
96
97
/* Parse system memory map */
98
v86.ebx = 0;
99
do {
100
v86.ctl = V86_FLAGS;
101
v86.addr = 0x15; /* int 0x15 function 0xe820 */
102
v86.eax = 0xe820;
103
v86.ecx = sizeof(struct bios_smap_xattr);
104
v86.edx = SMAP_SIG;
105
v86.es = VTOPSEG(&smap);
106
v86.edi = VTOPOFF(&smap);
107
v86int();
108
if ((V86_CY(v86.efl)) || (v86.eax != SMAP_SIG))
109
break;
110
/* look for a low-memory segment that's large enough */
111
if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) &&
112
(smap.length >= (512 * 1024))) {
113
bios_basemem = smap.length;
114
b_bios_probed |= B_BASEMEM_E820;
115
}
116
117
/* look for the first segment in 'extended' memory */
118
if ((smap.type == SMAP_TYPE_MEMORY) &&
119
(smap.base == 0x100000) &&
120
!(bios_getquirks() & BQ_DISTRUST_E820_EXTMEM)) {
121
bios_extmem = smap.length;
122
b_bios_probed |= B_EXTMEM_E820;
123
}
124
125
/*
126
* Look for the highest segment in 'extended' memory beyond
127
* 1MB but below 4GB.
128
*/
129
if ((smap.type == SMAP_TYPE_MEMORY) &&
130
(smap.base > 0x100000) &&
131
(smap.base < 0x100000000ull)) {
132
size = smap.length;
133
134
/*
135
* If this segment crosses the 4GB boundary,
136
* truncate it.
137
*/
138
if (smap.base + size > 0x100000000ull)
139
size = 0x100000000ull - smap.base;
140
141
/*
142
* To make maximum space for the kernel and the modules,
143
* set heap to use highest HEAP_MIN bytes below 4GB.
144
*/
145
if (high_heap_base < smap.base && size >= HEAP_MIN) {
146
high_heap_base = smap.base + size - HEAP_MIN;
147
high_heap_size = HEAP_MIN;
148
}
149
}
150
} while (v86.ebx != 0);
151
152
/* Fall back to the old compatibility function for base memory */
153
if (bios_basemem == 0) {
154
v86.ctl = 0;
155
v86.addr = 0x12; /* int 0x12 */
156
v86int();
157
158
bios_basemem = (v86.eax & 0xffff) * 1024;
159
b_bios_probed |= B_BASEMEM_12;
160
}
161
162
/*
163
* Fall back through several compatibility functions for extended
164
* memory.
165
*/
166
if (bios_extmem == 0) {
167
v86.ctl = V86_FLAGS;
168
v86.addr = 0x15; /* int 0x15 function 0xe801 */
169
v86.eax = 0xe801;
170
v86int();
171
if (!(V86_CY(v86.efl))) {
172
/*
173
* Clear high_heap; it may end up overlapping
174
* with the segment we're determining here.
175
* Let the default "steal stuff from top of
176
* bios_extmem" code below pick up on it.
177
*/
178
high_heap_size = 0;
179
high_heap_base = 0;
180
181
/*
182
* %cx is the number of 1KiB blocks between 1..16MiB.
183
* It can only be up to 0x3c00; if it's smaller then
184
* there's a PC AT memory hole so we can't treat
185
* it as contiguous.
186
*/
187
bios_extmem = (v86.ecx & 0xffff) * 1024;
188
if (bios_extmem == (1024 * 0x3c00))
189
bios_extmem += (v86.edx & 0xffff) * 64 * 1024;
190
191
/* truncate bios_extmem */
192
if (bios_extmem > 0x3ff00000)
193
bios_extmem = 0x3ff00000;
194
195
b_bios_probed |= B_EXTMEM_E801;
196
}
197
}
198
if (bios_extmem == 0) {
199
v86.ctl = 0;
200
v86.addr = 0x15; /* int 0x15 function 0x88 */
201
v86.eax = 0x8800;
202
v86int();
203
bios_extmem = (v86.eax & 0xffff) * 1024;
204
b_bios_probed |= B_EXTMEM_8800;
205
}
206
207
/* Set memtop to actual top of memory */
208
if (high_heap_size != 0) {
209
memtop = memtop_copyin = high_heap_base;
210
} else {
211
memtop = memtop_copyin = 0x100000 + bios_extmem;
212
}
213
214
/*
215
* If we have extended memory and did not find a suitable heap
216
* region in the SMAP, use the last HEAP_MIN of 'extended' memory as a
217
* high heap candidate.
218
*/
219
if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) {
220
high_heap_size = HEAP_MIN;
221
high_heap_base = memtop - HEAP_MIN;
222
memtop = memtop_copyin = high_heap_base;
223
}
224
}
225
226
static int
227
command_biosmem(int argc, char *argv[])
228
{
229
int bq = bios_getquirks();
230
231
printf("bios_basemem: 0x%llx\n", (unsigned long long)bios_basemem);
232
printf("bios_extmem: 0x%llx\n", (unsigned long long)bios_extmem);
233
printf("memtop: 0x%llx\n", (unsigned long long)memtop);
234
printf("high_heap_base: 0x%llx\n", (unsigned long long)high_heap_base);
235
printf("high_heap_size: 0x%llx\n", (unsigned long long)high_heap_size);
236
printf("bios_quirks: 0x%02x", bq);
237
if (bq & BQ_DISTRUST_E820_EXTMEM)
238
printf(" BQ_DISTRUST_E820_EXTMEM");
239
printf("\n");
240
printf("b_bios_probed: 0x%02x", (int)b_bios_probed);
241
if (b_bios_probed & B_BASEMEM_E820)
242
printf(" B_BASEMEM_E820");
243
if (b_bios_probed & B_BASEMEM_12)
244
printf(" B_BASEMEM_12");
245
if (b_bios_probed & B_EXTMEM_E820)
246
printf(" B_EXTMEM_E820");
247
if (b_bios_probed & B_EXTMEM_E801)
248
printf(" B_EXTMEM_E801");
249
if (b_bios_probed & B_EXTMEM_8800)
250
printf(" B_EXTMEM_8800");
251
printf("\n");
252
253
return (CMD_OK);
254
}
255
256
COMMAND_SET(biosmem, "biosmem", "show BIOS memory setup", command_biosmem);
257
258