xref: /openbsd/sys/arch/amd64/stand/libsa/memprobe.c (revision e72ddb44)
1*e72ddb44Sderaadt /*	$OpenBSD: memprobe.c,v 1.19 2021/01/28 18:54:52 deraadt 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 */
40*e72ddb44Sderaadt 
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 
149ae539668Sjsing /*
150ae539668Sjsing  * addrprobe(kloc): Probe memory at address kloc * 1024.
151a47f7207Smickey  *
152a47f7207Smickey  * This is a hack, but it seems to work ok.  Maybe this is
153a47f7207Smickey  * the *real* way that you are supposed to do probing???
154a47f7207Smickey  *
155a47f7207Smickey  * Modify the original a bit.  We write everything first, and
156a47f7207Smickey  * then test for the values.  This should croak on machines that
157a47f7207Smickey  * return values just written on non-existent memory...
158a47f7207Smickey  *
159a47f7207Smickey  * BTW: These machines are pretty broken IMHO.
160a47f7207Smickey  *
161a47f7207Smickey  * XXX - Does not detect aliased memory.
162a47f7207Smickey  */
163a47f7207Smickey const u_int addrprobe_pat[] = {
164a47f7207Smickey 	0x00000000, 0xFFFFFFFF,
165a47f7207Smickey 	0x01010101, 0x10101010,
166a47f7207Smickey 	0x55555555, 0xCCCCCCCC
167a47f7207Smickey };
168a47f7207Smickey static int
169a47f7207Smickey addrprobe(u_int kloc)
170a47f7207Smickey {
1712df76cc2Sguenther 	volatile u_int *loc;
172a47f7207Smickey 	register u_int i, ret = 0;
173cf92b8d0Sjasper 	u_int save[nitems(addrprobe_pat)];
174a47f7207Smickey 
175a47f7207Smickey 	/* Get location */
1767b5f1cbeSyasuoka 	loc = (int *)(intptr_t)(kloc * 1024);
177a47f7207Smickey 
178a47f7207Smickey 	save[0] = *loc;
179a47f7207Smickey 	/* Probe address */
180cf92b8d0Sjasper 	for (i = 0; i < nitems(addrprobe_pat); i++) {
181a47f7207Smickey 		*loc = addrprobe_pat[i];
182a47f7207Smickey 		if (*loc != addrprobe_pat[i])
183a47f7207Smickey 			ret++;
184a47f7207Smickey 	}
185a47f7207Smickey 	*loc = save[0];
186a47f7207Smickey 
187a47f7207Smickey 	if (!ret) {
188a47f7207Smickey 		/* Write address */
189cf92b8d0Sjasper 		for (i = 0; i < nitems(addrprobe_pat); i++) {
190a47f7207Smickey 			save[i] = loc[i];
191a47f7207Smickey 			loc[i] = addrprobe_pat[i];
192a47f7207Smickey 		}
193a47f7207Smickey 
194a47f7207Smickey 		/* Read address */
195cf92b8d0Sjasper 		for (i = 0; i < nitems(addrprobe_pat); i++) {
196a47f7207Smickey 			if (loc[i] != addrprobe_pat[i])
197a47f7207Smickey 				ret++;
198a47f7207Smickey 			loc[i] = save[i];
199a47f7207Smickey 		}
200a47f7207Smickey 	}
201a47f7207Smickey 
202a47f7207Smickey 	return ret;
203a47f7207Smickey }
204a47f7207Smickey 
205ae539668Sjsing /*
206ae539668Sjsing  * Probe for all extended memory.
207a47f7207Smickey  *
208a47f7207Smickey  * This is only used as a last resort.  If we resort to this
209a47f7207Smickey  * routine, we are getting pretty desperate.  Hopefully nobody
210a47f7207Smickey  * has to rely on this after all the work above.
211a47f7207Smickey  *
212a47f7207Smickey  * XXX - Does not detect aliased memory.
213a47f7207Smickey  * XXX - Could be destructive, as it does write.
214a47f7207Smickey  */
215a47f7207Smickey static __inline bios_memmap_t *
216a47f7207Smickey badprobe(bios_memmap_t *mp)
217a47f7207Smickey {
218a47f7207Smickey 	u_int64_t ram;
219a47f7207Smickey #ifdef DEBUG
220a47f7207Smickey 	printf("scan ");
221a47f7207Smickey #endif
222ae539668Sjsing 	/*
223ae539668Sjsing 	 * probe extended memory
224a47f7207Smickey 	 *
225a47f7207Smickey 	 * There is no need to do this in assembly language.  This is
226a47f7207Smickey 	 * much easier to debug in C anyways.
227a47f7207Smickey 	 */
228a47f7207Smickey 	for (ram = 1024; ram < 512 * 1024; ram += 4)
229a47f7207Smickey 		if (addrprobe(ram))
230a47f7207Smickey 			break;
231a47f7207Smickey 
232a47f7207Smickey 	mp->addr = 1024 * 1024;
233a47f7207Smickey 	mp->size = (ram - 1024) * 1024;
234a47f7207Smickey 	mp->type = BIOS_MAP_FREE;
235a47f7207Smickey 
236a47f7207Smickey 	return ++mp;
237a47f7207Smickey }
238a47f7207Smickey 
239a47f7207Smickey void
240a47f7207Smickey memprobe(void)
241a47f7207Smickey {
242a47f7207Smickey 	bios_memmap_t *pm = bios_memmap, *im;
243a47f7207Smickey 
244a47f7207Smickey #ifdef DEBUG
245a47f7207Smickey 	printf(" mem(");
246a47f7207Smickey #else
247a47f7207Smickey 	printf(" mem[");
248a47f7207Smickey #endif
249a47f7207Smickey 
250ae539668Sjsing 	if ((pm = bios_E820(bios_memmap)) == NULL) {
251a47f7207Smickey 		im = bios_int12(bios_memmap);
252a47f7207Smickey 		pm = bios_8800(im);
253ae539668Sjsing 		if (pm == NULL)
254a47f7207Smickey 			pm = badprobe(im);
255ae539668Sjsing 		if (pm == NULL) {
256a47f7207Smickey 			printf(" No Extended memory detected.");
257a47f7207Smickey 			pm = im;
258a47f7207Smickey 		}
259a47f7207Smickey 	}
260a47f7207Smickey 	pm->type = BIOS_MAP_END;
261a47f7207Smickey 
262a47f7207Smickey 	/* XXX - gotta peephole optimize the list */
263a47f7207Smickey 
264a47f7207Smickey #ifdef DEBUG
265a47f7207Smickey 	printf(")[");
266a47f7207Smickey #endif
267a47f7207Smickey 
268a47f7207Smickey 	/* XXX - Compatibility, remove later (smpprobe() relies on it) */
269a47f7207Smickey 	extmem = cnvmem = 0;
270a47f7207Smickey 	for (im = bios_memmap; im->type != BIOS_MAP_END; im++) {
271a47f7207Smickey 		/* Count only "good" memory chunks 12K and up in size */
272a47f7207Smickey 		if ((im->type == BIOS_MAP_FREE) && (im->size >= 12 * 1024)) {
273a47f7207Smickey 			if (im->size > 1024 * 1024)
2744fe063aeStom 				printf("%uM ", (u_int)(im->size /
2754fe063aeStom 				    (1024 * 1024)));
276a47f7207Smickey 			else
277a47f7207Smickey 				printf("%uK ", (u_int)im->size / 1024);
278a47f7207Smickey 
279a47f7207Smickey 			/*
280a47f7207Smickey 			 * Compute compatibility values:
281a47f7207Smickey 			 * cnvmem -- is the upper boundary of conventional
282a47f7207Smickey 			 *	memory (below IOM_BEGIN (=640k))
28325cde77aSjcs 			 * extmem -- is the size of the contiguous extended
284a47f7207Smickey 			 *	memory segment starting at 1M
285a47f7207Smickey 			 *
286a47f7207Smickey 			 * We ignore "good" memory in the 640K-1M hole.
287a47f7207Smickey 			 * We drop "machine {cnvmem,extmem}" commands.
288a47f7207Smickey 			 */
289a47f7207Smickey 			if (im->addr < IOM_BEGIN)
290a47f7207Smickey 				cnvmem = max(cnvmem,
291a47f7207Smickey 				    im->addr + im->size) / 1024;
292ae539668Sjsing 			if (im->addr >= IOM_END &&
293ae539668Sjsing 			    (im->addr / 1024) == (extmem + 1024))
294a47f7207Smickey 				extmem += im->size / 1024;
295a47f7207Smickey 		}
296a47f7207Smickey 	}
297c75862c4Sweingart 
298ae539668Sjsing 	/*
299ae539668Sjsing 	 * Adjust extmem to be no more than 4G (which it usually is not
300c75862c4Sweingart 	 * anyways).  In order for an x86 type machine (amd64/etc) to use
301c75862c4Sweingart 	 * more than 4GB of memory, it will need to grok and use the bios
302c75862c4Sweingart 	 * memory map we pass it.  Note that above we only count CONTIGUOUS
303c75862c4Sweingart 	 * memory from the 1MB boundary on for extmem (think I/O holes).
304c75862c4Sweingart 	 *
305c75862c4Sweingart 	 * extmem is in KB, and we have 4GB - 1MB (base/io hole) worth of it.
306c75862c4Sweingart 	 */
307c75862c4Sweingart 	if (extmem > 4 * 1024 * 1024 - 1024)
308c75862c4Sweingart 		extmem = 4 * 1024 * 1024 - 1024;
309a47f7207Smickey 
310a47f7207Smickey 	/* Check if gate A20 is on */
311a47f7207Smickey 	printf("a20=o%s] ", checkA20()? "n" : "ff!");
312a47f7207Smickey }
313a47f7207Smickey 
314a47f7207Smickey void
315a47f7207Smickey dump_biosmem(bios_memmap_t *tm)
316a47f7207Smickey {
317a47f7207Smickey 	register bios_memmap_t *p;
318a47f7207Smickey 	register u_int total = 0;
319a47f7207Smickey 
320ae539668Sjsing 	if (tm == NULL)
321a47f7207Smickey 		tm = bios_memmap;
322a47f7207Smickey 
323a47f7207Smickey 	for (p = tm; p->type != BIOS_MAP_END; p++) {
3244a9e4d17Smpf 		printf("Region %ld: type %u at 0x%llx for %uKB\n",
3254a9e4d17Smpf 		    (long)(p - tm), p->type, p->addr,
326a47f7207Smickey 		    (u_int)(p->size / 1024));
327a47f7207Smickey 
328a47f7207Smickey 		if (p->type == BIOS_MAP_FREE)
329a47f7207Smickey 			total += p->size / 1024;
330a47f7207Smickey 	}
331a47f7207Smickey 
332a47f7207Smickey 	printf("Low ram: %dKB  High ram: %dKB\n", cnvmem, extmem);
333a47f7207Smickey 	printf("Total free memory: %uKB\n", total);
334a47f7207Smickey }
335a47f7207Smickey 
336a47f7207Smickey int
3372ea094c9Sweingart mem_limit(long long ml)
3382ea094c9Sweingart {
3392ea094c9Sweingart 	register bios_memmap_t *p;
3402ea094c9Sweingart 
3412ea094c9Sweingart 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
3422ea094c9Sweingart 		register int64_t sp = p->addr, ep = p->addr + p->size;
3432ea094c9Sweingart 
3442ea094c9Sweingart 		if (p->type != BIOS_MAP_FREE)
3452ea094c9Sweingart 			continue;
3462ea094c9Sweingart 
34725cde77aSjcs 		/* Wholly above limit, nuke it */
3482ea094c9Sweingart 		if ((sp >= ml) && (ep >= ml)) {
3492ea094c9Sweingart 			bcopy (p + 1, p, (char *)bios_memmap +
3502ea094c9Sweingart 			       sizeof(bios_memmap) - (char *)p);
3512ea094c9Sweingart 		} else if ((sp < ml) && (ep >= ml)) {
3522ea094c9Sweingart 			p->size -= (ep - ml);
3532ea094c9Sweingart 		}
3542ea094c9Sweingart 	}
3552ea094c9Sweingart 	return 0;
3562ea094c9Sweingart }
3572ea094c9Sweingart 
3582ea094c9Sweingart int
3594a9e4d17Smpf mem_delete(long long sa, long long ea)
360a47f7207Smickey {
361a47f7207Smickey 	register bios_memmap_t *p;
362a47f7207Smickey 
363a47f7207Smickey 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
364a47f7207Smickey 		if (p->type == BIOS_MAP_FREE) {
365a47f7207Smickey 			register int64_t sp = p->addr, ep = p->addr + p->size;
366a47f7207Smickey 
367a47f7207Smickey 			/* can we eat it as a whole? */
36891fd972bSderaadt 			if ((sa - sp) <= PAGE_SIZE && (ep - ea) <= PAGE_SIZE) {
369a47f7207Smickey 				bcopy(p + 1, p, (char *)bios_memmap +
370a47f7207Smickey 				    sizeof(bios_memmap) - (char *)p);
371a47f7207Smickey 				break;
372a47f7207Smickey 			/* eat head or legs */
373a47f7207Smickey 			} else if (sa <= sp && sp < ea) {
374a47f7207Smickey 				p->addr = ea;
375a47f7207Smickey 				p->size = ep - ea;
376a47f7207Smickey 				break;
377a47f7207Smickey 			} else if (sa < ep && ep <= ea) {
378a47f7207Smickey 				p->size = sa - sp;
379a47f7207Smickey 				break;
380a47f7207Smickey 			} else if (sp < sa && ea < ep) {
381a47f7207Smickey 				/* bite in half */
382a47f7207Smickey 				bcopy(p, p + 1, (char *)bios_memmap +
383a47f7207Smickey 				    sizeof(bios_memmap) - (char *)p -
384a47f7207Smickey 				    sizeof(bios_memmap[0]));
385a47f7207Smickey 				p[1].addr = ea;
386a47f7207Smickey 				p[1].size = ep - ea;
387a47f7207Smickey 				p->size = sa - sp;
388a47f7207Smickey 				break;
389a47f7207Smickey 			}
390a47f7207Smickey 		}
391a47f7207Smickey 	}
392a47f7207Smickey 	return 0;
393a47f7207Smickey }
394a47f7207Smickey 
395a47f7207Smickey int
3964a9e4d17Smpf mem_add(long long sa, long long ea)
397a47f7207Smickey {
398a47f7207Smickey 	register bios_memmap_t *p;
399a47f7207Smickey 
400a47f7207Smickey 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++) {
401a47f7207Smickey 		if (p->type == BIOS_MAP_FREE) {
402a47f7207Smickey 			register int64_t sp = p->addr, ep = p->addr + p->size;
403a47f7207Smickey 
404a47f7207Smickey 			/* is it already there? */
405a47f7207Smickey 			if (sp <= sa && ea <= ep) {
406a47f7207Smickey 				break;
407a47f7207Smickey 			/* join head or legs */
408a47f7207Smickey 			} else if (sa < sp && sp <= ea) {
409a47f7207Smickey 				p->addr = sa;
410a47f7207Smickey 				p->size = ep - sa;
411a47f7207Smickey 				break;
412a47f7207Smickey 			} else if (sa <= ep && ep < ea) {
413a47f7207Smickey 				p->size = ea - sp;
414a47f7207Smickey 				break;
415a47f7207Smickey 			} else if (ea < sp) {
416a47f7207Smickey 				/* insert before */
417a47f7207Smickey 				bcopy(p, p + 1, (char *)bios_memmap +
418a47f7207Smickey 				    sizeof(bios_memmap) - (char *)(p - 1));
419a47f7207Smickey 				p->addr = sa;
420a47f7207Smickey 				p->size = ea - sa;
421a47f7207Smickey 				break;
422a47f7207Smickey 			}
423a47f7207Smickey 		}
424a47f7207Smickey 	}
425a47f7207Smickey 
426a47f7207Smickey 	/* meaning add new item at the end of the list */
427a47f7207Smickey 	if (p->type == BIOS_MAP_END) {
428a47f7207Smickey 		p[1] = p[0];
429a47f7207Smickey 		p->type = BIOS_MAP_FREE;
430a47f7207Smickey 		p->addr = sa;
431a47f7207Smickey 		p->size = ea - sa;
432a47f7207Smickey 	}
433a47f7207Smickey 
434a47f7207Smickey 	return 0;
435a47f7207Smickey }
436a47f7207Smickey 
437a47f7207Smickey void
438a47f7207Smickey mem_pass(void)
439a47f7207Smickey {
440a47f7207Smickey 	bios_memmap_t *p;
441a47f7207Smickey 
442a47f7207Smickey 	for (p = bios_memmap; p->type != BIOS_MAP_END; p++)
443a47f7207Smickey 		;
444a47f7207Smickey 	addbootarg(BOOTARG_MEMMAP, (p - bios_memmap + 1) * sizeof *bios_memmap,
445a47f7207Smickey 	    bios_memmap);
446a47f7207Smickey }
447