18600fd4dSToomas Soome /*
2199767f8SToomas Soome  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3199767f8SToomas Soome  * All rights reserved.
4199767f8SToomas Soome  *
5199767f8SToomas Soome  * Redistribution and use in source and binary forms, with or without
6199767f8SToomas Soome  * modification, are permitted provided that the following conditions
7199767f8SToomas Soome  * are met:
8199767f8SToomas Soome  * 1. Redistributions of source code must retain the above copyright
9199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer.
10199767f8SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12199767f8SToomas Soome  *    documentation and/or other materials provided with the distribution.
13199767f8SToomas Soome  *
14199767f8SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15199767f8SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16199767f8SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17199767f8SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18199767f8SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19199767f8SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20199767f8SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21199767f8SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22199767f8SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23199767f8SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24199767f8SToomas Soome  * SUCH DAMAGE.
25199767f8SToomas Soome  */
26199767f8SToomas Soome 
27199767f8SToomas Soome #include <sys/cdefs.h>
28199767f8SToomas Soome 
29199767f8SToomas Soome /*
308600fd4dSToomas Soome  * MD primitives supporting placement of module data
31199767f8SToomas Soome  *
32199767f8SToomas Soome  * XXX should check load address/size against memory top.
33199767f8SToomas Soome  */
34199767f8SToomas Soome #include <stand.h>
358600fd4dSToomas Soome #include <sys/param.h>
368600fd4dSToomas Soome #include <sys/multiboot2.h>
37cb371639SToomas Soome #include <sys/consplat.h>
388600fd4dSToomas Soome #include <machine/metadata.h>
398600fd4dSToomas Soome #include <machine/pc/bios.h>
40199767f8SToomas Soome #include "libi386.h"
41199767f8SToomas Soome #include "btxv86.h"
428600fd4dSToomas Soome #include "bootstrap.h"
438600fd4dSToomas Soome 
44cb371639SToomas Soome extern multiboot_tag_framebuffer_t gfx_fb;
45cb371639SToomas Soome 
468600fd4dSToomas Soome /*
478600fd4dSToomas Soome  * Verify the address is not in use by existing modules.
488600fd4dSToomas Soome  */
498600fd4dSToomas Soome static vm_offset_t
addr_verify(struct preloaded_file * fp,vm_offset_t addr,size_t size)508600fd4dSToomas Soome addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size)
518600fd4dSToomas Soome {
528600fd4dSToomas Soome 	vm_offset_t f_addr;
538600fd4dSToomas Soome 
548600fd4dSToomas Soome 	while (fp != NULL) {
558600fd4dSToomas Soome 		f_addr = fp->f_addr;
568600fd4dSToomas Soome 
578600fd4dSToomas Soome 		if ((f_addr <= addr) &&
58cb371639SToomas Soome 		    (f_addr + fp->f_size >= addr)) {
598600fd4dSToomas Soome 			return (0);
608600fd4dSToomas Soome 		}
618600fd4dSToomas Soome 		if ((f_addr >= addr) && (f_addr <= addr + size)) {
628600fd4dSToomas Soome 			return (0);
638600fd4dSToomas Soome 		}
648600fd4dSToomas Soome 		fp = fp->f_next;
658600fd4dSToomas Soome 	}
668600fd4dSToomas Soome 	return (addr);
678600fd4dSToomas Soome }
688600fd4dSToomas Soome 
698600fd4dSToomas Soome /*
708600fd4dSToomas Soome  * Find smap entry above 1MB, able to contain size bytes from addr.
718600fd4dSToomas Soome  */
728600fd4dSToomas Soome static vm_offset_t
smap_find(struct bios_smap * smap,int smaplen,vm_offset_t addr,size_t size)738600fd4dSToomas Soome smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size)
748600fd4dSToomas Soome {
758600fd4dSToomas Soome 	int i;
768600fd4dSToomas Soome 
778600fd4dSToomas Soome 	for (i = 0; i < smaplen; i++) {
788600fd4dSToomas Soome 		if (smap[i].type != SMAP_TYPE_MEMORY)
798600fd4dSToomas Soome 			continue;
808600fd4dSToomas Soome 
818600fd4dSToomas Soome 		/* We do not want address below 1MB. */
828600fd4dSToomas Soome 		if (smap[i].base < 0x100000)
838600fd4dSToomas Soome 			continue;
848600fd4dSToomas Soome 
858600fd4dSToomas Soome 		/* Do we fit into current entry? */
868600fd4dSToomas Soome 		if ((smap[i].base <= addr) &&
878600fd4dSToomas Soome 		    (smap[i].base + smap[i].length >= addr + size)) {
888600fd4dSToomas Soome 			return (addr);
898600fd4dSToomas Soome 		}
908600fd4dSToomas Soome 
918600fd4dSToomas Soome 		/* Do we fit into new entry? */
928600fd4dSToomas Soome 		if ((smap[i].base > addr) && (smap[i].length >= size)) {
938600fd4dSToomas Soome 			return (smap[i].base);
948600fd4dSToomas Soome 		}
958600fd4dSToomas Soome 	}
968600fd4dSToomas Soome 	return (0);
978600fd4dSToomas Soome }
988600fd4dSToomas Soome 
998600fd4dSToomas Soome /*
1008600fd4dSToomas Soome  * Find usable address for loading. The address for the kernel is fixed, as
1018600fd4dSToomas Soome  * it is determined by kernel linker map (dboot PT_LOAD address).
1028600fd4dSToomas Soome  * For modules, we need to consult smap, the module address has to be
1038600fd4dSToomas Soome  * aligned to page boundary and we have to fit into smap entry.
1048600fd4dSToomas Soome  */
1058600fd4dSToomas Soome vm_offset_t
i386_loadaddr(uint_t type,void * data,vm_offset_t addr)106cb371639SToomas Soome i386_loadaddr(uint_t type, void *data, vm_offset_t addr)
1078600fd4dSToomas Soome {
1088600fd4dSToomas Soome 	struct stat st;
1098600fd4dSToomas Soome 	size_t size, smaplen;
1108600fd4dSToomas Soome 	struct preloaded_file *fp, *mfp;
1118600fd4dSToomas Soome 	struct file_metadata *md;
1128600fd4dSToomas Soome 	struct bios_smap *smap;
1138600fd4dSToomas Soome 	vm_offset_t off;
1148600fd4dSToomas Soome 
1158600fd4dSToomas Soome 	/*
1168600fd4dSToomas Soome 	 * For now, assume we have memory for the kernel, the
1178600fd4dSToomas Soome 	 * required map is [1MB..) This assumption should be safe with x86 BIOS.
1188600fd4dSToomas Soome 	 */
1198600fd4dSToomas Soome 	if (type == LOAD_KERN)
1208600fd4dSToomas Soome 		return (addr);
1218600fd4dSToomas Soome 
1228600fd4dSToomas Soome 	if (addr == 0)
1238600fd4dSToomas Soome 		return (addr);	/* nothing to do */
1248600fd4dSToomas Soome 
1258600fd4dSToomas Soome 	if (type == LOAD_ELF)
1268600fd4dSToomas Soome 		return (0);	/* not supported */
1278600fd4dSToomas Soome 
1288600fd4dSToomas Soome 	if (type == LOAD_MEM) {
1298600fd4dSToomas Soome 		size = *(size_t *)data;
1308600fd4dSToomas Soome 	} else {
1318600fd4dSToomas Soome 		stat(data, &st);
1328600fd4dSToomas Soome 		size = st.st_size;
1338600fd4dSToomas Soome 	}
1348600fd4dSToomas Soome 
1358600fd4dSToomas Soome 	/*
1368600fd4dSToomas Soome 	 * Find our kernel, from it we will find the smap and the list of
1378600fd4dSToomas Soome 	 * loaded modules.
1388600fd4dSToomas Soome 	 */
1398600fd4dSToomas Soome 	fp = file_findfile(NULL, NULL);
1408600fd4dSToomas Soome 	if (fp == NULL)
1418600fd4dSToomas Soome 		return (0);
1428600fd4dSToomas Soome 	md = file_findmetadata(fp, MODINFOMD_SMAP);
1438600fd4dSToomas Soome 	if (md == NULL)
1448600fd4dSToomas Soome 		return (0);
1458600fd4dSToomas Soome 
1468600fd4dSToomas Soome 	smap = (struct bios_smap *)md->md_data;
147cb371639SToomas Soome 	smaplen = md->md_size / sizeof (struct bios_smap);
1488600fd4dSToomas Soome 
1498600fd4dSToomas Soome 	/* Start from the end of the kernel. */
1508600fd4dSToomas Soome 	mfp = fp;
1518600fd4dSToomas Soome 	do {
1528600fd4dSToomas Soome 		if (mfp == NULL) {
1538600fd4dSToomas Soome 			off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN);
1548600fd4dSToomas Soome 		} else {
1558600fd4dSToomas Soome 			off = roundup2(mfp->f_addr + mfp->f_size + 1,
1568600fd4dSToomas Soome 			    MULTIBOOT_MOD_ALIGN);
1578600fd4dSToomas Soome 		}
158cb371639SToomas Soome 		/* Avoid possible framebuffer memory */
159cb371639SToomas Soome 		if (plat_stdout_is_framebuffer()) {
160cb371639SToomas Soome 			vm_offset_t fb_addr;
161cb371639SToomas Soome 			size_t fb_size;
162cb371639SToomas Soome 
163cb371639SToomas Soome 			fb_addr = gfx_fb.framebuffer_common.framebuffer_addr;
164cb371639SToomas Soome 			fb_size = gfx_fb.framebuffer_common.framebuffer_height *
165cb371639SToomas Soome 			    gfx_fb.framebuffer_common.framebuffer_pitch;
166cb371639SToomas Soome 
167cb371639SToomas Soome 			if ((off >= fb_addr && off <= fb_addr + fb_size) ||
168cb371639SToomas Soome 			    (off + size >= fb_addr &&
169cb371639SToomas Soome 			    off + size <= fb_addr + fb_size)) {
170cb371639SToomas Soome 				printf("\nSkipping framebuffer memory %#x "
171cb371639SToomas Soome 				    "size %#x\n", fb_addr, fb_size);
172cb371639SToomas Soome 				off = roundup2(fb_addr + fb_size + 1,
173cb371639SToomas Soome 				    MULTIBOOT_MOD_ALIGN);
174cb371639SToomas Soome 			}
175cb371639SToomas Soome 		}
1768600fd4dSToomas Soome 		off = smap_find(smap, smaplen, off, size);
1778600fd4dSToomas Soome 		off = addr_verify(fp, off, size);
1788600fd4dSToomas Soome 		if (off != 0)
1798600fd4dSToomas Soome 			break;
1808600fd4dSToomas Soome 
1818600fd4dSToomas Soome 		if (mfp == NULL)
1828600fd4dSToomas Soome 			break;
1838600fd4dSToomas Soome 		mfp = mfp->f_next;
1848600fd4dSToomas Soome 	} while (off == 0);
1858600fd4dSToomas Soome 
1868600fd4dSToomas Soome 	return (off);
1878600fd4dSToomas Soome }
188199767f8SToomas Soome 
189199767f8SToomas Soome ssize_t
i386_copyin(const void * src,vm_offset_t dest,const size_t len)190199767f8SToomas Soome i386_copyin(const void *src, vm_offset_t dest, const size_t len)
191199767f8SToomas Soome {
1928600fd4dSToomas Soome 	if (dest + len >= memtop) {
1938600fd4dSToomas Soome 		errno = EFBIG;
1948600fd4dSToomas Soome 		return (-1);
1958600fd4dSToomas Soome 	}
196199767f8SToomas Soome 
1978600fd4dSToomas Soome 	bcopy(src, PTOV(dest), len);
1988600fd4dSToomas Soome 	return (len);
199199767f8SToomas Soome }
200199767f8SToomas Soome 
201199767f8SToomas Soome ssize_t
i386_copyout(const vm_offset_t src,void * dest,const size_t len)202199767f8SToomas Soome i386_copyout(const vm_offset_t src, void *dest, const size_t len)
203199767f8SToomas Soome {
2048600fd4dSToomas Soome 	if (src + len >= memtop) {
2058600fd4dSToomas Soome 		errno = EFBIG;
2068600fd4dSToomas Soome 		return (-1);
2078600fd4dSToomas Soome 	}
2088600fd4dSToomas Soome 
2098600fd4dSToomas Soome 	bcopy(PTOV(src), dest, len);
2108600fd4dSToomas Soome 	return (len);
211199767f8SToomas Soome }
212199767f8SToomas Soome 
213199767f8SToomas Soome 
214199767f8SToomas Soome ssize_t
i386_readin(const int fd,vm_offset_t dest,const size_t len)215199767f8SToomas Soome i386_readin(const int fd, vm_offset_t dest, const size_t len)
216199767f8SToomas Soome {
2178600fd4dSToomas Soome 	if (dest + len >= memtop_copyin) {
2188600fd4dSToomas Soome 		errno = EFBIG;
2198600fd4dSToomas Soome 		return (-1);
2208600fd4dSToomas Soome 	}
221199767f8SToomas Soome 
2228600fd4dSToomas Soome 	return (read(fd, PTOV(dest), len));
223199767f8SToomas Soome }
224