Changeset View
Changeset View
Standalone View
Standalone View
stand/i386/libi386/i386_copy.c
Show All 27 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | /* | ||||
* MD primitives supporting placement of module data | * MD primitives supporting placement of module data | ||||
* | * | ||||
* XXX should check load address/size against memory top. | * XXX should check load address/size against memory top. | ||||
*/ | */ | ||||
#include <stand.h> | #include <stand.h> | ||||
#include <sys/param.h> | |||||
#include <machine/elf.h> | |||||
#include "bootstrap.h" | |||||
#include "libi386.h" | #include "libi386.h" | ||||
#include "btxv86.h" | #include "btxv86.h" | ||||
extern size_t elf64_obj_imagesize(void *); | |||||
/* | |||||
* Verify the address is not in use by existing modules. | |||||
*/ | |||||
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); | |||||
} | |||||
/* | |||||
* Find smap entry above 1MB, able to contain size bytes from 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; | |||||
/* We do not want address below 1MB. */ | |||||
if (smap[i].base < 0x100000) | |||||
continue; | |||||
/* Do we fit into current entry? */ | |||||
if ((smap[i].base <= addr) && | |||||
(smap[i].base + smap[i].length >= addr + size)) { | |||||
return (addr); | |||||
} | |||||
/* Do we fit into new entry? */ | |||||
if ((smap[i].base > addr) && (smap[i].length >= size)) { | |||||
return (smap[i].base); | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Find usable address for loading. The address for the kernel is fixed, as | |||||
* it is determined by kernel linker map. | |||||
* For modules, we need to consult smap, the module address has to be | |||||
* aligned to page boundary and we have to fit into smap entry. | |||||
*/ | |||||
uint64_t | |||||
i386_loadaddr(u_int type, void *data, uint64_t addr) | |||||
{ | |||||
struct stat st; | |||||
size_t size; | |||||
struct preloaded_file *fp, *mfp; | |||||
struct bios_smap *smap; | |||||
u_int smaplen; | |||||
vm_offset_t off; | |||||
/* | |||||
* For now, assume we have memory for the kernel, the | |||||
* required map is [1MB..) This assumption should be safe with x86 BIOS. | |||||
*/ | |||||
fp = file_findfile(NULL, NULL); | |||||
if (fp == NULL) { | |||||
return (roundup(addr, PAGE_SIZE)); | |||||
} | |||||
size = 0; | |||||
if (type == LOAD_RAW) { | |||||
stat(data, &st); | |||||
size = st.st_size; | |||||
} | |||||
if (type == LOAD_ELF) { | |||||
Elf_Ehdr *hdr = data; | |||||
if (hdr->e_ident[EI_CLASS] == ELFCLASS64) | |||||
size = elf64_obj_imagesize(data); | |||||
else if (hdr->e_ident[EI_CLASS] == ELFCLASS32) | |||||
size = elf32_obj_imagesize(data); | |||||
else | |||||
return (roundup(addr, PAGE_SIZE)); | |||||
} | |||||
if (size == 0) | |||||
return (roundup(addr, PAGE_SIZE)); | |||||
bios_getsmapdata(&smaplen, &smap); | |||||
/* Start from the end of the kernel. */ | |||||
mfp = fp; | |||||
do { | |||||
if (mfp == NULL) { | |||||
off = roundup2(addr + 1, PAGE_SIZE); | |||||
} else { | |||||
off = roundup2(mfp->f_addr + mfp->f_size + 1, | |||||
PAGE_SIZE); | |||||
} | |||||
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 | ssize_t | ||||
i386_copyin(const void *src, vm_offset_t dest, const size_t len) | i386_copyin(const void *src, vm_offset_t dest, const size_t len) | ||||
{ | { | ||||
if (dest + len >= memtop) { | if (dest + len >= memtop) { | ||||
errno = EFBIG; | errno = EFBIG; | ||||
return (-1); | return (-1); | ||||
} | } | ||||
Show All 29 Lines |