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