1*22028508SToomas Soome /*
2*22028508SToomas Soome  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3*22028508SToomas Soome  * All rights reserved.
4*22028508SToomas Soome  *
5*22028508SToomas Soome  * Redistribution and use in source and binary forms, with or without
6*22028508SToomas Soome  * modification, are permitted provided that the following conditions
7*22028508SToomas Soome  * are met:
8*22028508SToomas Soome  * 1. Redistributions of source code must retain the above copyright
9*22028508SToomas Soome  *    notice, this list of conditions and the following disclaimer.
10*22028508SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11*22028508SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12*22028508SToomas Soome  *    documentation and/or other materials provided with the distribution.
13*22028508SToomas Soome  *
14*22028508SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*22028508SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*22028508SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*22028508SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*22028508SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*22028508SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*22028508SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*22028508SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*22028508SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*22028508SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*22028508SToomas Soome  * SUCH DAMAGE.
25*22028508SToomas Soome  */
26*22028508SToomas Soome 
27*22028508SToomas Soome #include <sys/cdefs.h>
28*22028508SToomas Soome 
29*22028508SToomas Soome /*
30*22028508SToomas Soome  * MD primitives supporting placement of module data
31*22028508SToomas Soome  *
32*22028508SToomas Soome  * XXX should check load address/size against memory top.
33*22028508SToomas Soome  */
34*22028508SToomas Soome #include <stand.h>
35*22028508SToomas Soome #include <sys/param.h>
36*22028508SToomas Soome #include <sys/multiboot2.h>
37*22028508SToomas Soome #include <sys/consplat.h>
38*22028508SToomas Soome #include <machine/metadata.h>
39*22028508SToomas Soome #include <machine/pc/bios.h>
40*22028508SToomas Soome #include "libi386.h"
41*22028508SToomas Soome #include "btxv86.h"
42*22028508SToomas Soome #include "bootstrap.h"
43*22028508SToomas Soome 
44*22028508SToomas Soome extern multiboot_tag_framebuffer_t gfx_fb;
45*22028508SToomas Soome 
46*22028508SToomas Soome /*
47*22028508SToomas Soome  * Verify the address is not in use by existing modules.
48*22028508SToomas Soome  */
49*22028508SToomas Soome static vm_offset_t
addr_verify(struct preloaded_file * fp,vm_offset_t addr,size_t size)50*22028508SToomas Soome addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size)
51*22028508SToomas Soome {
52*22028508SToomas Soome 	vm_offset_t f_addr;
53*22028508SToomas Soome 
54*22028508SToomas Soome 	while (fp != NULL) {
55*22028508SToomas Soome 		f_addr = fp->f_addr;
56*22028508SToomas Soome 
57*22028508SToomas Soome 		if ((f_addr <= addr) &&
58*22028508SToomas Soome 		    (f_addr + fp->f_size >= addr)) {
59*22028508SToomas Soome 			return (0);
60*22028508SToomas Soome 		}
61*22028508SToomas Soome 		if ((f_addr >= addr) && (f_addr <= addr + size)) {
62*22028508SToomas Soome 			return (0);
63*22028508SToomas Soome 		}
64*22028508SToomas Soome 		fp = fp->f_next;
65*22028508SToomas Soome 	}
66*22028508SToomas Soome 	return (addr);
67*22028508SToomas Soome }
68*22028508SToomas Soome 
69*22028508SToomas Soome /*
70*22028508SToomas Soome  * Find smap entry above 1MB, able to contain size bytes from addr.
71*22028508SToomas Soome  */
72*22028508SToomas Soome static vm_offset_t
smap_find(struct bios_smap * smap,int smaplen,vm_offset_t addr,size_t size)73*22028508SToomas Soome smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size)
74*22028508SToomas Soome {
75*22028508SToomas Soome 	int i;
76*22028508SToomas Soome 
77*22028508SToomas Soome 	for (i = 0; i < smaplen; i++) {
78*22028508SToomas Soome 		if (smap[i].type != SMAP_TYPE_MEMORY)
79*22028508SToomas Soome 			continue;
80*22028508SToomas Soome 
81*22028508SToomas Soome 		/* We do not want address below 1MB. */
82*22028508SToomas Soome 		if (smap[i].base < 0x100000)
83*22028508SToomas Soome 			continue;
84*22028508SToomas Soome 
85*22028508SToomas Soome 		/* Do we fit into current entry? */
86*22028508SToomas Soome 		if ((smap[i].base <= addr) &&
87*22028508SToomas Soome 		    (smap[i].base + smap[i].length >= addr + size)) {
88*22028508SToomas Soome 			return (addr);
89*22028508SToomas Soome 		}
90*22028508SToomas Soome 
91*22028508SToomas Soome 		/* Do we fit into new entry? */
92*22028508SToomas Soome 		if ((smap[i].base > addr) && (smap[i].length >= size)) {
93*22028508SToomas Soome 			return (smap[i].base);
94*22028508SToomas Soome 		}
95*22028508SToomas Soome 	}
96*22028508SToomas Soome 	return (0);
97*22028508SToomas Soome }
98*22028508SToomas Soome 
99*22028508SToomas Soome /*
100*22028508SToomas Soome  * Find usable address for loading. The address for the kernel is fixed, as
101*22028508SToomas Soome  * it is determined by kernel linker map (dboot PT_LOAD address).
102*22028508SToomas Soome  * For modules, we need to consult smap, the module address has to be
103*22028508SToomas Soome  * aligned to page boundary and we have to fit into smap entry.
104*22028508SToomas Soome  */
105*22028508SToomas Soome vm_offset_t
i386_loadaddr(uint_t type,void * data,vm_offset_t addr)106*22028508SToomas Soome i386_loadaddr(uint_t type, void *data, vm_offset_t addr)
107*22028508SToomas Soome {
108*22028508SToomas Soome 	struct stat st;
109*22028508SToomas Soome 	size_t size, smaplen;
110*22028508SToomas Soome 	struct preloaded_file *fp, *mfp;
111*22028508SToomas Soome 	struct file_metadata *md;
112*22028508SToomas Soome 	struct bios_smap *smap;
113*22028508SToomas Soome 	vm_offset_t off;
114*22028508SToomas Soome 
115*22028508SToomas Soome 	/*
116*22028508SToomas Soome 	 * For now, assume we have memory for the kernel, the
117*22028508SToomas Soome 	 * required map is [1MB..) This assumption should be safe with x86 BIOS.
118*22028508SToomas Soome 	 */
119*22028508SToomas Soome 	if (type == LOAD_KERN)
120*22028508SToomas Soome 		return (addr);
121*22028508SToomas Soome 
122*22028508SToomas Soome 	if (addr == 0)
123*22028508SToomas Soome 		return (addr);	/* nothing to do */
124*22028508SToomas Soome 
125*22028508SToomas Soome 	if (type == LOAD_ELF)
126*22028508SToomas Soome 		return (0);	/* not supported */
127*22028508SToomas Soome 
128*22028508SToomas Soome 	if (type == LOAD_MEM) {
129*22028508SToomas Soome 		size = *(size_t *)data;
130*22028508SToomas Soome 	} else {
131*22028508SToomas Soome 		stat(data, &st);
132*22028508SToomas Soome 		size = st.st_size;
133*22028508SToomas Soome 	}
134*22028508SToomas Soome 
135*22028508SToomas Soome 	/*
136*22028508SToomas Soome 	 * Find our kernel, from it we will find the smap and the list of
137*22028508SToomas Soome 	 * loaded modules.
138*22028508SToomas Soome 	 */
139*22028508SToomas Soome 	fp = file_findfile(NULL, NULL);
140*22028508SToomas Soome 	if (fp == NULL)
141*22028508SToomas Soome 		return (0);
142*22028508SToomas Soome 	md = file_findmetadata(fp, MODINFOMD_SMAP);
143*22028508SToomas Soome 	if (md == NULL)
144*22028508SToomas Soome 		return (0);
145*22028508SToomas Soome 
146*22028508SToomas Soome 	smap = (struct bios_smap *)md->md_data;
147*22028508SToomas Soome 	smaplen = md->md_size / sizeof (struct bios_smap);
148*22028508SToomas Soome 
149*22028508SToomas Soome 	/* Start from the end of the kernel. */
150*22028508SToomas Soome 	mfp = fp;
151*22028508SToomas Soome 	do {
152*22028508SToomas Soome 		if (mfp == NULL) {
153*22028508SToomas Soome 			off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN);
154*22028508SToomas Soome 		} else {
155*22028508SToomas Soome 			off = roundup2(mfp->f_addr + mfp->f_size + 1,
156*22028508SToomas Soome 			    MULTIBOOT_MOD_ALIGN);
157*22028508SToomas Soome 		}
158*22028508SToomas Soome 		/* Avoid possible framebuffer memory */
159*22028508SToomas Soome 		if (plat_stdout_is_framebuffer()) {
160*22028508SToomas Soome 			vm_offset_t fb_addr;
161*22028508SToomas Soome 			size_t fb_size;
162*22028508SToomas Soome 
163*22028508SToomas Soome 			fb_addr = gfx_fb.framebuffer_common.framebuffer_addr;
164*22028508SToomas Soome 			fb_size = gfx_fb.framebuffer_common.framebuffer_height *
165*22028508SToomas Soome 			    gfx_fb.framebuffer_common.framebuffer_pitch;
166*22028508SToomas Soome 
167*22028508SToomas Soome 			if ((off >= fb_addr && off <= fb_addr + fb_size) ||
168*22028508SToomas Soome 			    (off + size >= fb_addr &&
169*22028508SToomas Soome 			    off + size <= fb_addr + fb_size)) {
170*22028508SToomas Soome 				printf("\nSkipping framebuffer memory %#x "
171*22028508SToomas Soome 				    "size %#x\n", fb_addr, fb_size);
172*22028508SToomas Soome 				off = roundup2(fb_addr + fb_size + 1,
173*22028508SToomas Soome 				    MULTIBOOT_MOD_ALIGN);
174*22028508SToomas Soome 			}
175*22028508SToomas Soome 		}
176*22028508SToomas Soome 		off = smap_find(smap, smaplen, off, size);
177*22028508SToomas Soome 		off = addr_verify(fp, off, size);
178*22028508SToomas Soome 		if (off != 0)
179*22028508SToomas Soome 			break;
180*22028508SToomas Soome 
181*22028508SToomas Soome 		if (mfp == NULL)
182*22028508SToomas Soome 			break;
183*22028508SToomas Soome 		mfp = mfp->f_next;
184*22028508SToomas Soome 	} while (off == 0);
185*22028508SToomas Soome 
186*22028508SToomas Soome 	return (off);
187*22028508SToomas Soome }
188*22028508SToomas Soome 
189*22028508SToomas Soome ssize_t
i386_copyin(const void * src,vm_offset_t dest,const size_t len)190*22028508SToomas Soome i386_copyin(const void *src, vm_offset_t dest, const size_t len)
191*22028508SToomas Soome {
192*22028508SToomas Soome 	if (dest + len >= memtop) {
193*22028508SToomas Soome 		errno = EFBIG;
194*22028508SToomas Soome 		return (-1);
195*22028508SToomas Soome 	}
196*22028508SToomas Soome 
197*22028508SToomas Soome 	bcopy(src, PTOV(dest), len);
198*22028508SToomas Soome 	return (len);
199*22028508SToomas Soome }
200*22028508SToomas Soome 
201*22028508SToomas Soome ssize_t
i386_copyout(const vm_offset_t src,void * dest,const size_t len)202*22028508SToomas Soome i386_copyout(const vm_offset_t src, void *dest, const size_t len)
203*22028508SToomas Soome {
204*22028508SToomas Soome 	if (src + len >= memtop) {
205*22028508SToomas Soome 		errno = EFBIG;
206*22028508SToomas Soome 		return (-1);
207*22028508SToomas Soome 	}
208*22028508SToomas Soome 
209*22028508SToomas Soome 	bcopy(PTOV(src), dest, len);
210*22028508SToomas Soome 	return (len);
211*22028508SToomas Soome }
212*22028508SToomas Soome 
213*22028508SToomas Soome 
214*22028508SToomas Soome ssize_t
i386_readin(const int fd,vm_offset_t dest,const size_t len)215*22028508SToomas Soome i386_readin(const int fd, vm_offset_t dest, const size_t len)
216*22028508SToomas Soome {
217*22028508SToomas Soome 	if (dest + len >= memtop_copyin) {
218*22028508SToomas Soome 		errno = EFBIG;
219*22028508SToomas Soome 		return (-1);
220*22028508SToomas Soome 	}
221*22028508SToomas Soome 
222*22028508SToomas Soome 	return (read(fd, PTOV(dest), len));
223*22028508SToomas Soome }
224