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 #include <sys/cdefs.h>
28 
29 /*
30  * MD primitives supporting placement of module data
31  *
32  * XXX should check load address/size against memory top.
33  */
34 #include <stand.h>
35 #include <sys/param.h>
36 #include <sys/multiboot2.h>
37 #include <sys/consplat.h>
38 #include <machine/metadata.h>
39 #include <machine/pc/bios.h>
40 #include "libi386.h"
41 #include "btxv86.h"
42 #include "bootstrap.h"
43 
44 extern multiboot_tag_framebuffer_t gfx_fb;
45 
46 /*
47  * Verify the address is not in use by existing modules.
48  */
49 static vm_offset_t
addr_verify(struct preloaded_file * fp,vm_offset_t addr,size_t size)50 addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size)
51 {
52 	vm_offset_t f_addr;
53 
54 	while (fp != NULL) {
55 		f_addr = fp->f_addr;
56 
57 		if ((f_addr <= addr) &&
58 		    (f_addr + fp->f_size >= addr)) {
59 			return (0);
60 		}
61 		if ((f_addr >= addr) && (f_addr <= addr + size)) {
62 			return (0);
63 		}
64 		fp = fp->f_next;
65 	}
66 	return (addr);
67 }
68 
69 /*
70  * Find smap entry above 1MB, able to contain size bytes from addr.
71  */
72 static vm_offset_t
smap_find(struct bios_smap * smap,int smaplen,vm_offset_t addr,size_t size)73 smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size)
74 {
75 	int i;
76 
77 	for (i = 0; i < smaplen; i++) {
78 		if (smap[i].type != SMAP_TYPE_MEMORY)
79 			continue;
80 
81 		/* We do not want address below 1MB. */
82 		if (smap[i].base < 0x100000)
83 			continue;
84 
85 		/* Do we fit into current entry? */
86 		if ((smap[i].base <= addr) &&
87 		    (smap[i].base + smap[i].length >= addr + size)) {
88 			return (addr);
89 		}
90 
91 		/* Do we fit into new entry? */
92 		if ((smap[i].base > addr) && (smap[i].length >= size)) {
93 			return (smap[i].base);
94 		}
95 	}
96 	return (0);
97 }
98 
99 /*
100  * Find usable address for loading. The address for the kernel is fixed, as
101  * it is determined by kernel linker map (dboot PT_LOAD address).
102  * For modules, we need to consult smap, the module address has to be
103  * aligned to page boundary and we have to fit into smap entry.
104  */
105 vm_offset_t
i386_loadaddr(uint_t type,void * data,vm_offset_t addr)106 i386_loadaddr(uint_t type, void *data, vm_offset_t addr)
107 {
108 	struct stat st;
109 	size_t size, smaplen;
110 	struct preloaded_file *fp, *mfp;
111 	struct file_metadata *md;
112 	struct bios_smap *smap;
113 	vm_offset_t off;
114 
115 	/*
116 	 * For now, assume we have memory for the kernel, the
117 	 * required map is [1MB..) This assumption should be safe with x86 BIOS.
118 	 */
119 	if (type == LOAD_KERN)
120 		return (addr);
121 
122 	if (addr == 0)
123 		return (addr);	/* nothing to do */
124 
125 	if (type == LOAD_ELF)
126 		return (0);	/* not supported */
127 
128 	if (type == LOAD_MEM) {
129 		size = *(size_t *)data;
130 	} else {
131 		stat(data, &st);
132 		size = st.st_size;
133 	}
134 
135 	/*
136 	 * Find our kernel, from it we will find the smap and the list of
137 	 * loaded modules.
138 	 */
139 	fp = file_findfile(NULL, NULL);
140 	if (fp == NULL)
141 		return (0);
142 	md = file_findmetadata(fp, MODINFOMD_SMAP);
143 	if (md == NULL)
144 		return (0);
145 
146 	smap = (struct bios_smap *)md->md_data;
147 	smaplen = md->md_size / sizeof (struct bios_smap);
148 
149 	/* Start from the end of the kernel. */
150 	mfp = fp;
151 	do {
152 		if (mfp == NULL) {
153 			off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN);
154 		} else {
155 			off = roundup2(mfp->f_addr + mfp->f_size + 1,
156 			    MULTIBOOT_MOD_ALIGN);
157 		}
158 		/* Avoid possible framebuffer memory */
159 		if (plat_stdout_is_framebuffer()) {
160 			vm_offset_t fb_addr;
161 			size_t fb_size;
162 
163 			fb_addr = gfx_fb.framebuffer_common.framebuffer_addr;
164 			fb_size = gfx_fb.framebuffer_common.framebuffer_height *
165 			    gfx_fb.framebuffer_common.framebuffer_pitch;
166 
167 			if ((off >= fb_addr && off <= fb_addr + fb_size) ||
168 			    (off + size >= fb_addr &&
169 			    off + size <= fb_addr + fb_size)) {
170 				printf("\nSkipping framebuffer memory %#x "
171 				    "size %#x\n", fb_addr, fb_size);
172 				off = roundup2(fb_addr + fb_size + 1,
173 				    MULTIBOOT_MOD_ALIGN);
174 			}
175 		}
176 		off = smap_find(smap, smaplen, off, size);
177 		off = addr_verify(fp, off, size);
178 		if (off != 0)
179 			break;
180 
181 		if (mfp == NULL)
182 			break;
183 		mfp = mfp->f_next;
184 	} while (off == 0);
185 
186 	return (off);
187 }
188 
189 ssize_t
i386_copyin(const void * src,vm_offset_t dest,const size_t len)190 i386_copyin(const void *src, vm_offset_t dest, const size_t len)
191 {
192 	if (dest + len >= memtop) {
193 		errno = EFBIG;
194 		return (-1);
195 	}
196 
197 	bcopy(src, PTOV(dest), len);
198 	return (len);
199 }
200 
201 ssize_t
i386_copyout(const vm_offset_t src,void * dest,const size_t len)202 i386_copyout(const vm_offset_t src, void *dest, const size_t len)
203 {
204 	if (src + len >= memtop) {
205 		errno = EFBIG;
206 		return (-1);
207 	}
208 
209 	bcopy(PTOV(src), dest, len);
210 	return (len);
211 }
212 
213 
214 ssize_t
i386_readin(const int fd,vm_offset_t dest,const size_t len)215 i386_readin(const int fd, vm_offset_t dest, const size_t len)
216 {
217 	if (dest + len >= memtop_copyin) {
218 		errno = EFBIG;
219 		return (-1);
220 	}
221 
222 	return (read(fd, PTOV(dest), len));
223 }
224