#include <sys/cdefs.h>
#include <stand.h>
#include <sys/param.h>
#include <sys/multiboot2.h>
#include <sys/consplat.h>
#include <machine/metadata.h>
#include <machine/pc/bios.h>
#include "libi386.h"
#include "btxv86.h"
#include "bootstrap.h"
extern multiboot_tag_framebuffer_t gfx_fb;
static vm_offset_t
addr_verify(struct preloaded_file *fp, vm_offset_t addr, size_t size)
{
vm_offset_t f_addr;
while (fp != NULL) {
f_addr = fp->f_addr;
if ((f_addr <= addr) &&
(f_addr + fp->f_size >= addr)) {
return (0);
}
if ((f_addr >= addr) && (f_addr <= addr + size)) {
return (0);
}
fp = fp->f_next;
}
return (addr);
}
static vm_offset_t
smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size)
{
int i;
for (i = 0; i < smaplen; i++) {
if (smap[i].type != SMAP_TYPE_MEMORY)
continue;
if (smap[i].base < 0x100000)
continue;
if ((smap[i].base <= addr) &&
(smap[i].base + smap[i].length >= addr + size)) {
return (addr);
}
if ((smap[i].base > addr) && (smap[i].length >= size)) {
return (smap[i].base);
}
}
return (0);
}
vm_offset_t
i386_loadaddr(uint_t type, void *data, vm_offset_t addr)
{
struct stat st;
size_t size, smaplen;
struct preloaded_file *fp, *mfp;
struct file_metadata *md;
struct bios_smap *smap;
vm_offset_t off;
if (type == LOAD_KERN)
return (addr);
if (addr == 0)
return (addr);
if (type == LOAD_ELF)
return (0);
if (type == LOAD_MEM) {
size = *(size_t *)data;
} else {
stat(data, &st);
size = st.st_size;
}
fp = file_findfile(NULL, NULL);
if (fp == NULL)
return (0);
md = file_findmetadata(fp, MODINFOMD_SMAP);
if (md == NULL)
return (0);
smap = (struct bios_smap *)md->md_data;
smaplen = md->md_size / sizeof (struct bios_smap);
mfp = fp;
do {
if (mfp == NULL) {
off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN);
} else {
off = roundup2(mfp->f_addr + mfp->f_size + 1,
MULTIBOOT_MOD_ALIGN);
}
if (plat_stdout_is_framebuffer()) {
vm_offset_t fb_addr;
size_t fb_size;
fb_addr = gfx_fb.framebuffer_common.framebuffer_addr;
fb_size = gfx_fb.framebuffer_common.framebuffer_height *
gfx_fb.framebuffer_common.framebuffer_pitch;
if ((off >= fb_addr && off <= fb_addr + fb_size) ||
(off + size >= fb_addr &&
off + size <= fb_addr + fb_size)) {
printf("\nSkipping framebuffer memory %#x "
"size %#x\n", fb_addr, fb_size);
off = roundup2(fb_addr + fb_size + 1,
MULTIBOOT_MOD_ALIGN);
}
}
off = smap_find(smap, smaplen, off, size);
off = addr_verify(fp, off, size);
if (off != 0)
break;
if (mfp == NULL)
break;
mfp = mfp->f_next;
} while (off == 0);
return (off);
}
ssize_t
i386_copyin(const void *src, vm_offset_t dest, const size_t len)
{
if (dest + len >= memtop) {
errno = EFBIG;
return (-1);
}
bcopy(src, PTOV(dest), len);
return (len);
}
ssize_t
i386_copyout(const vm_offset_t src, void *dest, const size_t len)
{
if (src + len >= memtop) {
errno = EFBIG;
return (-1);
}
bcopy(PTOV(src), dest, len);
return (len);
}
ssize_t
i386_readin(const int fd, vm_offset_t dest, const size_t len)
{
if (dest + len >= memtop_copyin) {
errno = EFBIG;
return (-1);
}
return (read(fd, PTOV(dest), len));
}