xref: /openbsd/sys/arch/amd64/stand/libsa/memprobe.c (revision 25cde77a)
1*25cde77aSjcs /*	$OpenBSD: memprobe.c,v 1.17 2016/06/10 18:36:06 jcs Exp $	*/
2a47f7207Smickey 
3a47f7207Smickey /*
4a47f7207Smickey  * Copyright (c) 1997-1999 Michael Shalayeff
5a47f7207Smickey  * Copyright (c) 1997-1999 Tobias Weingartner
6a47f7207Smickey  * All rights reserved.
7a47f7207Smickey  *
8a47f7207Smickey  * Redistribution and use in source and binary forms, with or without
9a47f7207Smickey  * modification, are permitted provided that the following conditions
10a47f7207Smickey  * are met:
11a47f7207Smickey  * 1. Redistributions of source code must retain the above copyright
12a47f7207Smickey  *    notice, this list of conditions and the following disclaimer.
13a47f7207Smickey  * 2. Redistributions in binary form must reproduce the above copyright
14a47f7207Smickey  *    notice, this list of conditions and the following disclaimer in the
15a47f7207Smickey  *    documentation and/or other materials provided with the distribution.
16a47f7207Smickey  *
17a47f7207Smickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18a47f7207Smickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19a47f7207Smickey  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20a47f7207Smickey  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21a47f7207Smickey  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22a47f7207Smickey  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23a47f7207Smickey  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24a47f7207Smickey  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25a47f7207Smickey  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26a47f7207Smickey  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27a47f7207Smickey  * SUCH DAMAGE.
28a47f7207Smickey  *
29a47f7207Smickey  */
30a47f7207Smickey 
31a47f7207Smickey #include <sys/param.h>
32a47f7207Smickey #include <machine/biosvar.h>
33a47f7207Smickey #include <dev/isa/isareg.h>
34a47f7207Smickey #include <stand/boot/bootarg.h>
35a47f7207Smickey #include "libsa.h"
36a47f7207Smickey 
37a47f7207Smickey u_int cnvmem, extmem;		/* XXX - compatibility */
38a47f7207Smickey 
397b5f1cbeSyasuoka bios_memmap_t bios_memmap[64];	/* This is easier */
407b5f1cbeSyasuoka #ifndef EFIBOOT
41ae539668Sjsing /*
42ae539668Sjsing  * Check gateA20
43a47f7207Smickey  *
44a47f7207Smickey  * A sanity check.
45a47f7207Smickey  */
46a47f7207Smickey static __inline int
47a47f7207Smickey checkA20(void)
48a47f7207Smickey {
49a47f7207Smickey 	register char *p = (char *)0x100000;
50a47f7207Smickey 	register char *q = (char *)0x000000;
51a47f7207Smickey 	int st;
52a47f7207Smickey 
53a47f7207Smickey 	/* Simple check */
54a47f7207Smickey 	if (*p != *q)
55ae539668Sjsing 		return 1;
56a47f7207Smickey 
57a47f7207Smickey 	/* Complex check */
58a47f7207Smickey 	*p = ~(*p);
59a47f7207Smickey 	st = (*p != *q);
60a47f7207Smickey 	*p = ~(*p);
61a47f7207Smickey 
62ae539668Sjsing 	return st;
63a47f7207Smickey }
64a47f7207Smickey 
65ae539668Sjsing /*
66ae539668Sjsing  * BIOS int 15, AX=E820
67a47f7207Smickey  *
68a47f7207Smickey  * This is the "preferred" method.
69a47f7207Smickey  */
70a47f7207Smickey static __inline bios_memmap_t *
71a47f7207Smickey bios_E820(bios_memmap_t *mp)
72a47f7207Smickey {
73a47f7207Smickey 	int rc, off = 0, sig, gotcha = 0;
74a47f7207Smickey 
75a47f7207Smickey 	do {
76a47f7207Smickey 		BIOS_regs.biosr_es = ((u_int)(mp) >> 4);
772df76cc2Sguenther 		__asm volatile(DOINT(0x15) "; setc %b1"
78a47f7207Smickey 		    : "=a" (sig), "=d" (rc), "=b" (off)
79a47f7207Smickey 		    : "0" (0xE820), "1" (0x534d4150), "b" (off),
80ae539668Sjsing 		      "c" (sizeof(*mp)), "D" (((u_int)mp) & 0xf)
81a47f7207Smickey 		    : "cc", "memory");
82a47f7207Smickey 		off = BIOS_regs.biosr_bx;
83a47f7207Smickey 
84a47f7207Smickey 		if (rc & 0xff || sig != 0x534d4150)
85a47f7207Smickey 			break;
86a47f7207Smickey 		gotcha++;
87a47f7207Smickey 		if (!mp->type)
88a47f7207Smickey 			mp->type = BIOS_MAP_RES;
89a47f7207Smickey 		mp++;
90a47f7207Smickey 	} while (off);
91a47f7207Smickey 
92a47f7207Smickey 	if (!gotcha)
93ae539668Sjsing 		return NULL;
94a47f7207Smickey #ifdef DEBUG
95a47f7207Smickey 	printf("0x15[E820] ");
96a47f7207Smickey #endif
97ae539668Sjsing 	return mp;
98a47f7207Smickey }
99a47f7207Smickey 
100ae539668Sjsing /*
101ae539668Sjsing  * BIOS int 15, AX=8800
102a47f7207Smickey  *
103a47f7207Smickey  * Only used if int 15, AX=E801 does not work.
104a47f7207Smickey  * Machines with this are restricted to 64MB.
105a47f7207Smickey  */
106a47f7207Smickey static __inline bios_memmap_t *
107a47f7207Smickey bios_8800(bios_memmap_t *mp)
108a47f7207Smickey {
109a47f7207Smickey 	int rc, mem;
110a47f7207Smickey 
1112df76cc2Sguenther 	__asm volatile(DOINT(0x15) "; setc %b0"
112a47f7207Smickey 	    : "=c" (rc), "=a" (mem) : "a" (0x8800));
113a47f7207Smickey 
114a47f7207Smickey 	if (rc & 0xff)
115ae539668Sjsing 		return NULL;
116a47f7207Smickey #ifdef DEBUG
117a47f7207Smickey 	printf("0x15[8800] ");
118a47f7207Smickey #endif
119a47f7207Smickey 	/* Fill out a BIOS_MAP */
120a47f7207Smickey 	mp->addr = 1024 * 1024;		/* 1MB */
121a47f7207Smickey 	mp->size = (mem & 0xffff) * 1024;
122a47f7207Smickey 	mp->type = BIOS_MAP_FREE;
123a47f7207Smickey 
124a47f7207Smickey 	return ++mp;
125a47f7207Smickey }
126a47f7207Smickey 
127ae539668Sjsing /*
128ae539668Sjsing  * BIOS int 0x12 Get Conventional Memory
129a47f7207Smickey  *
130a47f7207Smickey  * Only used if int 15, AX=E820 does not work.
131a47f7207Smickey  */
132a47f7207Smickey static __inline bios_memmap_t *
133a47f7207Smickey bios_int12(bios_memmap_t *mp)
134a47f7207Smickey {
135a47f7207Smickey 	int mem;
136a47f7207Smickey #ifdef DEBUG
137a47f7207Smickey 	printf("0x12 ");
138a47f7207Smickey #endif
1392df76cc2Sguenther 	__asm volatile(DOINT(0x12) : "=a" (mem) :: "%ecx", "%edx", "cc");
140a47f7207Smickey 
141a47f7207Smickey 	/* Fill out a bios_memmap_t */
142a47f7207Smickey 	mp->addr = 0;
143a47f7207Smickey 	mp->size = (mem & 0xffff) * 1024;
144a47f7207Smickey 	mp->type = BIOS_MAP_FREE;
145a47f7207Smickey 
146a47f7207Smickey 	return ++mp;
147a47f7207Smickey }
148a47f7207Smickey 
149a47f7207Smickey 
150ae539668Sjsing /*
151ae539668Sjsing  * addrprobe(kloc): Probe memory at address kloc * 1024.
152a47f7207Smickey  *
153a47f7207Smickey  * This is a hack, but it seems to work ok.  Maybe this is
154a47f7207Smickey  * the *real* way that you are supposed to do probing???
155a47f7207Smickey  *
156a47f7207Smickey  * Modify the original a bit.  We write everything first, and
157a47f7207Smickey  * then test for the values.  This should croak on machines that
158a47f7207Smickey  * return values just written on non-existent memory...
159a47f7207Smickey  *
160a47f7207Smickey  * BTW: These machines are pretty broken IMHO.
161a47f7207Smickey  *
162a47f7207Smickey  * XXX - Does not detect aliased memory.
163a47f7207Smickey  */
164a47f7207Smickey const u_int addrprobe_pat[] = {
165a47f7207Smickey 	0x00000000, 0xFFFFFFFF,
166a47f7207Smickey 	0x01010101, 0x10101010,
167a47f7207Smickey 	0x55555555, 0xCCCCCCCC
168a47f7207Smickey };
169a47f7207Smickey static int
170a47f7207Smickey addrprobe(u_int kloc)
171a47f7207Smickey {
1722df76cc2Sguenther 	volatile u_int *loc;
173a47f7207Smickey 	register u_int i, ret = 0;
174cf92b8d0Sjasper 	u_int save[nitems(addrprobe_pat)];
175a47f7207Smickey 
176a47f7207Smickey 	/* Get location */
1777b5f1cbeSyasuoka 	loc = (int *)(intptr_t)(kloc * 1024);
178a47f7207Smickey 
179a47f7207Smickey 	save[0] = *loc;
180a47f7207Smickey 	/* Probe address */
181cf92b8d0Sjasper 	for (i = 0; i < nitems(addrprobe_pat); i++) {
182a47f7207Smickey 		*loc = addrprobe_pat[i];
183a47f7207Smickey 		if (*loc != addrprobe_pat[i])
184a47f7207Smickey 			ret++;
185a47f7207Smickey 	}
186a47f7207Smickey 	*loc = save[0];
187a47f7207Smickey 
188a47f7207Smickey 	if (!ret) {
189a47f7207Smickey 		/* Write address */
190cf92b8d0Sjasper 		for (i = 0; i < nitems(addrprobe_pat); i++) {
191a47f7207Smickey 			save[i] = loc[i];
192a47f7207Smickey 			loc[i] = addrprobe_pat[i];
193a47f7207Smickey 		}
194a47f7207Smickey 
195a47f7207Smickey 		/* Read address */
196cf92b8d0Sjasper 		for (i = 0; i < nitems(addrprobe_pat); i++) {
197a47f7207Smickey 			if (loc[i] != addrprobe_pat[i])
198a47f7207Smickey 				ret++;
199a47f7207Smickey 			loc[i] = save[i];
200a47f7207Smickey 		}
201a47f7207Smickey 	}
202a47f7207Smickey 
203a47f7207Smickey 	return ret;
204a47f7207Smickey }
205a47f7207Smickey 
206ae539668Sjsing /*
207ae539668Sjsing  * Probe for all extended memory.
208a47f7207Smickey  *
209a47f7207Smickey  * This is only used as a last resort.  If we resort to this
210a47f7207Smickey  * routine, we are getting pretty desperate.  Hopefully nobody
211a47f7207Smickey  * has to rely on this after all the work above.
212a47f7207Smickey  *
213a47f7207Smickey  * XXX - Does not detect aliased memory.
214a47f7207Smickey  * XXX - Could be destructive, as it does write.
215a47f7207Smickey  */
216a47f7207Smickey static __inline bios_memmap_t *
217a47f7207Smickey badprobe(bios_memmap_t *mp)
218a47f7207Smickey {
219a47f7207Smickey 	u_int64_t ram;
220a47f7207Smickey #ifdef DEBUG
221a47f7207Smickey 	printf("scan ");
222a47f7207Smickey #endif
223ae539668Sjsing 	/*
224ae539668Sjsing 	 * probe extended memory
225a47f7207Smickey 	 *
226a47f7207Smickey 	 * There is no need to do this in assembly language.  This is
227a47f7207Smickey 	 * much easier to debug in C anyways.
228a47f7207Smickey 	 */
229a47f7207Smickey 	for (ram = 1024; ram < 512 * 1024; ram += 4)
230a47f7207Smickey 		if (addrprobe(ram))
231a47f7207Smickey 			break;
232a47f7207Smickey 
233a47f7207Smickey 	mp->addr = 1024 * 1024;
234a47f7207Smickey 	mp->size = (ram - 1024) * 1024;
235a47f7207Smickey 	mp->type = BIOS_MAP_FREE;
236a47f7207Smickey 
237a47f7207Smickey 	return ++mp;
238a47f7207Smickey }
239a47f7207Smickey 
240a47f7207Smickey void
241a47f7207Smickey memprobe(void)
242a47f7207Smickey {
243a47f7207Smickey 	bios_memmap_t *pm = bios_memmap, *im;
244a47f7207Smickey 
245a47f7207Smickey #ifdef DEBUG
246a47f7207Smickey 	printf(" mem(");
247a47f7207Smickey #else
248a47f7207Smickey 	printf(" mem[");
249a47f7207Smickey #endif
250a47f7207Smickey 
251ae539668Sjsing 	if ((pm = bios_E820(bios_memmap)) == NULL) {
252a47f7207Smickey 		im = bios_int12(bios_memmap);
253a47f7207Smickey 		pm = bios_8800(im);
254ae539668Sjsing 		if (pm == NULL)
255a47f7207Smickey 			pm = badprobe(im);
256ae539668Sjsing 		if (pm == NULL) {
257a47f7207Smickey 			printf(" No Extended memory detected.");
258a47f7207Smickey 			pm = im;
259a47f7207Smickey 		}
260a47f7207Smickey 	}
261a47f7207Smickey 	pm->type = BIOS_MAP_END;
262a47f7207Smickey 
263a47f7207Smickey 	/* XXX - gotta peephole optimize the list */
264a47f7207Smickey 
265a47f7207Smickey #ifdef DEBUG
266a47f7207Smickey 	printf(")[");
267a47f7207Smickey #endif
268a47f7207Smickey 
269a47f7207Smickey 	/* XXX - Compatibility, remove later (smpprobe() relies on it) */
270a47f7207Smickey 	extmem = cnvmem = 0;
271a47f7207Smickey 	for (im = bios_memmap; im->type != BIOS_MAP_END; im++) {
272a47f7207Smickey 		/* Count only "good" memory chunks 12K and up in size */
273a47f7207Smickey 		if ((im->type == BIOS_MAP_FREE) && (im->size >= 12 * 1024)) {
274a47f7207Smickey 			if (im->size > 1024 * 1024)
2754fe063aeStom 				printf("%uM ", (u_int)(im->size /
2764fe063aeStom 				    (1024 * 1024)));
277a47f7207Smickey 			else
278a47f7207Smickey 				printf("%uK ", (u_int)im->size / 1024);
279a47f7207Smickey 
280a47f7207Smickey 			/*
281a47f7207Smickey 			 * Compute compatibility values:
282a47f7207Smickey 			 * cnvmem -- is the upper boundary of conventional
283a47f7207Smickey 			 *	memory (below IOM_BEGIN (=640k))
284*25cde77aSjcs 			 * extmem -- is the size of the contiguous extended
285a47f7207Smickey 			 *	memory segment starting at 1M
286a47f7207Smickey 			 *
287a47f7207Smickey 			 * We ignore "good" memory in the 640K-1M hole.
288a47f7207Smickey 			 * We drop "machine {cnvmem,extmem}" commands.
289a47f7207Smickey 			 */
290a47f7207Smickey 			if (im->addr < IOM_BEGIN)
291a47f7207Smickey 				cnvmem = max(cnvmem,
292a47f7207Smickey 				    im->addr + im->size) / 1024;
293ae539668Sjsing 			if (im->addr >= IOM_END &&
294ae539668Sjsing 			    (im->addr / 1024) == (extmem + 1024))
295a47f7207Smickey 				extmem += im->size / 1024;
296a47f7207Smickey 		}
297a47f7207Smickey 	}
298c75862c4Sweingart 
299ae539668Sjsing 	/*
300ae539668Sjsing 	 * Adjust extmem to be no more than 4G (which it usually is not
301c75862c4Sweingart 	 * anyways).  In order for an x86 type machine (amd64/etc) to use
302c75862c4Sweingart 	 * more than 4GB of memory, it will need to grok and use the bios
303c75862c4Sweingart 	 * memory map we pass it.  Note that above we only count CONTIGUOUS
304c75862c4Sweingart 	 * memory from the 1MB boundary on for extmem (think I/O holes).
305c75862c4Sweingart 	 *
306c75862c4Sweingart 	 * extmem is in KB, and we have 4GB - 1MB (base/io hole) worth of it.
307c75862c4Sweingart 	 */
308c75862c4Sweingart 	if (extmem > 4 * 1024 * 1024 - 1024)
309c75862c4Sweingart 		extmem = 4 * 1024 * 1024 - 1024;
310a47f7207Smickey 
311a47f7207Smickey 	/* Check if gate A20 is on */
312a47f7207Smickey 	printf("a20=o%s] ", checkA20()? "n" : "ff!");
313a47f7207Smickey }
314a47f7207Smickey #endif
315a47f7207Smickey 
316a47f7207Smickey void
317a47f7207Smickey dump_biosmem(bios_memmap_t *tm)
318a47f7207Smickey {
319a47f7207Smickey 	register bios_memmap_t *p;
320a47f7207Smickey 	register u_int total = 0;
321a47f7207Smickey 
322ae539668Sjsing 	if (tm == NULL)
323a47f7207Smickey 		tm = bios_memmap;
324a47f7207Smickey 
325a47f7207Smickey 	for (p = tm; p->type != BIOS_MAP_END; p++) {
3264a9e4d17Smpf 		printf("Region %ld: type %u at 0x%llx for %uKB\n",
3274a9e4d17Smpf 		    (long)(p - tm), p->type, p->addr,
328a47f7207Smickey 		    (u_int)(p->size / 1024));
329a47f7207Smickey 
330a47f7207Smickey 		if (p->type == BIOS_MAP_FREE)
331a47f7207Smickey 			total += p->size / 1024;
332a47f7207Smickey 	}
333a47f7207Smickey 
334a47f7207Smickey 	printf("Low ram: %dKB  High ram: %dKB\n", cnvmem, extmem);
335a47f7207Smickey 	printf("Total free memory: %uKB\n", total);
336a47f7207Smickey }
337a47f7207Smickey 
338a47f7207Smickey int
3392ea094c9Sweingart mem_limit(long long ml)
3402ea094c9Sweingart {
3412ea094c9Sweingart 	register bios_memmap_t *p;
3422ea094c9Sweingart 
3432ea094c9Sweingart 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
3442ea094c9Sweingart 		register int64_t sp = p->addr, ep = p->addr + p->size;
3452ea094c9Sweingart 
3462ea094c9Sweingart 		if (p->type != BIOS_MAP_FREE)
3472ea094c9Sweingart 			continue;
3482ea094c9Sweingart 
349*25cde77aSjcs 		/* Wholly above limit, nuke it */
3502ea094c9Sweingart 		if ((sp >= ml) && (ep >= ml)) {
3512ea094c9Sweingart 			bcopy (p + 1, p, (char *)bios_memmap +
3522ea094c9Sweingart 			       sizeof(bios_memmap) - (char *)p);
3532ea094c9Sweingart 		} else if ((sp < ml) && (ep >= ml)) {
3542ea094c9Sweingart 			p->size -= (ep - ml);
3552ea094c9Sweingart 		}
3562ea094c9Sweingart 	}
3572ea094c9Sweingart 	return 0;
3582ea094c9Sweingart }
3592ea094c9Sweingart 
3602ea094c9Sweingart int
3614a9e4d17Smpf mem_delete(long long sa, long long ea)
362a47f7207Smickey {
363a47f7207Smickey 	register bios_memmap_t *p;
364a47f7207Smickey 
365a47f7207Smickey 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
366a47f7207Smickey 		if (p->type == BIOS_MAP_FREE) {
367a47f7207Smickey 			register int64_t sp = p->addr, ep = p->addr + p->size;
368a47f7207Smickey 
369a47f7207Smickey 			/* can we eat it as a whole? */
37091fd972bSderaadt 			if ((sa - sp) <= PAGE_SIZE && (ep - ea) <= PAGE_SIZE) {
371a47f7207Smickey 				bcopy(p + 1, p, (char *)bios_memmap +
372a47f7207Smickey 				    sizeof(bios_memmap) - (char *)p);
373a47f7207Smickey 				break;
374a47f7207Smickey 			/* eat head or legs */
375a47f7207Smickey 			} else if (sa <= sp && sp < ea) {
376a47f7207Smickey 				p->addr = ea;
377a47f7207Smickey 				p->size = ep - ea;
378a47f7207Smickey 				break;
379a47f7207Smickey 			} else if (sa < ep && ep <= ea) {
380a47f7207Smickey 				p->size = sa - sp;
381a47f7207Smickey 				break;
382a47f7207Smickey 			} else if (sp < sa && ea < ep) {
383a47f7207Smickey 				/* bite in half */
384a47f7207Smickey 				bcopy(p, p + 1, (char *)bios_memmap +
385a47f7207Smickey 				    sizeof(bios_memmap) - (char *)p -
386a47f7207Smickey 				    sizeof(bios_memmap[0]));
387a47f7207Smickey 				p[1].addr = ea;
388a47f7207Smickey 				p[1].size = ep - ea;
389a47f7207Smickey 				p->size = sa - sp;
390a47f7207Smickey 				break;
391a47f7207Smickey 			}
392a47f7207Smickey 		}
393a47f7207Smickey 	}
394a47f7207Smickey 	return 0;
395a47f7207Smickey }
396a47f7207Smickey 
397a47f7207Smickey int
3984a9e4d17Smpf mem_add(long long sa, long long ea)
399a47f7207Smickey {
400a47f7207Smickey 	register bios_memmap_t *p;
401a47f7207Smickey 
402a47f7207Smickey 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
403a47f7207Smickey 		if (p->type == BIOS_MAP_FREE) {
404a47f7207Smickey 			register int64_t sp = p->addr, ep = p->addr + p->size;
405a47f7207Smickey 
406a47f7207Smickey 			/* is it already there? */
407a47f7207Smickey 			if (sp <= sa && ea <= ep) {
408a47f7207Smickey 				break;
409a47f7207Smickey 			/* join head or legs */
410a47f7207Smickey 			} else if (sa < sp && sp <= ea) {
411a47f7207Smickey 				p->addr = sa;
412a47f7207Smickey 				p->size = ep - sa;
413a47f7207Smickey 				break;
414a47f7207Smickey 			} else if (sa <= ep && ep < ea) {
415a47f7207Smickey 				p->size = ea - sp;
416a47f7207Smickey 				break;
417a47f7207Smickey 			} else if (ea < sp) {
418a47f7207Smickey 				/* insert before */
419a47f7207Smickey 				bcopy(p, p + 1, (char *)bios_memmap +
420a47f7207Smickey 				    sizeof(bios_memmap) - (char *)(p - 1));
421a47f7207Smickey 				p->addr = sa;
422a47f7207Smickey 				p->size = ea - sa;
423a47f7207Smickey 				break;
424a47f7207Smickey 			}
425a47f7207Smickey 		}
426a47f7207Smickey 	}
427a47f7207Smickey 
428a47f7207Smickey 	/* meaning add new item at the end of the list */
429a47f7207Smickey 	if (p->type == BIOS_MAP_END) {
430a47f7207Smickey 		p[1] = p[0];
431a47f7207Smickey 		p->type = BIOS_MAP_FREE;
432a47f7207Smickey 		p->addr = sa;
433a47f7207Smickey 		p->size = ea - sa;
434a47f7207Smickey 	}
435a47f7207Smickey 
436a47f7207Smickey 	return 0;
437a47f7207Smickey }
438a47f7207Smickey 
439a47f7207Smickey void
440a47f7207Smickey mem_pass(void)
441a47f7207Smickey {
442a47f7207Smickey 	bios_memmap_t *p;
443a47f7207Smickey 
444a47f7207Smickey 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++)
445a47f7207Smickey 		;
446a47f7207Smickey 	addbootarg(BOOTARG_MEMMAP, (p - bios_memmap + 1) * sizeof *bios_memmap,
447a47f7207Smickey 	    bios_memmap);
448a47f7207Smickey }
449