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