Page MenuHomeFreeBSD

D22309.id64155.diff
No OneTemporary

D22309.id64155.diff

Index: stand/common/bootstrap.h
===================================================================
--- stand/common/bootstrap.h
+++ stand/common/bootstrap.h
@@ -257,6 +257,7 @@
typedef Elf_Addr (symaddr_fn)(struct elf_file *ef, Elf_Size symidx);
int __elfN(loadfile)(char *filename, uint64_t dest, struct preloaded_file **result);
+size_t __elfN(obj_imagesize)(void *);
int __elfN(obj_loadfile)(char *filename, uint64_t dest,
struct preloaded_file **result);
int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr,
Index: stand/common/load_elf_obj.c
===================================================================
--- stand/common/load_elf_obj.c
+++ stand/common/load_elf_obj.c
@@ -144,8 +144,18 @@
goto oerr;
}
+ /* Read in the section headers. */
+ ef.e_shdr = alloc_pread(ef.fd, (off_t)hdr->e_shoff,
+ hdr->e_shnum * hdr->e_shentsize);
+ if (ef.e_shdr == NULL) {
+ printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
+ "_obj_loadfile: read section headers failed\n");
+ err = errno;
+ goto oerr;
+ }
+
if (archsw.arch_loadaddr != NULL)
- dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest);
+ dest = archsw.arch_loadaddr(LOAD_ELF, &ef, dest);
else
dest = roundup(dest, PAGE_SIZE);
@@ -188,6 +198,91 @@
return(err);
}
+size_t
+__elfN(obj_imagesize)(void *ptr)
+{
+ elf_file_t ef = ptr;
+ Elf_Ehdr *hdr;
+ Elf_Shdr *shdr;
+ size_t size;
+ int i, nsym, symstrindex;
+
+ hdr = &ef->hdr;
+ shdr = ef->e_shdr;
+ size = 0;
+ for (i = 0; i < hdr->e_shnum; i++) {
+ if (shdr[i].sh_size == 0)
+ continue;
+ switch (shdr[i].sh_type) {
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+#if defined(__i386__) || defined(__amd64__)
+ case SHT_X86_64_UNWIND:
+#endif
+ if ((shdr[i].sh_flags & SHF_ALLOC) == 0)
+ break;
+ size = roundup(size, shdr[i].sh_addralign);
+ size += shdr[i].sh_size;
+ break;
+ }
+ }
+
+ /* Symbols. */
+ nsym = 0;
+ for (i = 0; i < hdr->e_shnum; i++) {
+ switch (shdr[i].sh_type) {
+ case SHT_SYMTAB:
+ nsym++;
+ ef->symtabindex = i;
+ size += shdr[i].sh_size;
+ break;
+ }
+ }
+ if (nsym != 1) {
+ printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
+ "_obj_imagesize: file has no valid symbol table\n");
+ goto out;
+ }
+ size = roundup(size, shdr[ef->symtabindex].sh_addralign);
+ size += shdr[ef->symtabindex].sh_size;
+
+ symstrindex = shdr[ef->symtabindex].sh_link;
+ if (symstrindex < 0 || symstrindex >= hdr->e_shnum ||
+ shdr[symstrindex].sh_type != SHT_STRTAB) {
+ printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
+ "_obj_imagesize: file has invalid symbol strings\n");
+ goto out;
+ }
+ size = roundup(size, shdr[symstrindex].sh_addralign);
+ size += shdr[symstrindex].sh_size;
+
+ /* Section names. */
+ if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum ||
+ shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) {
+ printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
+ "_obj_imagesize: file has no section names\n");
+ goto out;
+ }
+ ef->shstrindex = hdr->e_shstrndx;
+ size = roundup(size, shdr[ef->shstrindex].sh_addralign);
+ size += shdr[ef->shstrindex].sh_size;
+
+ /* Relocation tables. */
+ for (i = 0; i < hdr->e_shnum; i++) {
+ switch (shdr[i].sh_type) {
+ case SHT_REL:
+ case SHT_RELA:
+ if ((shdr[shdr[i].sh_info].sh_flags & SHF_ALLOC) == 0)
+ break;
+ size = roundup(size, shdr[i].sh_addralign);
+ size += shdr[i].sh_size;
+ break;
+ }
+ }
+out:
+ return (size);
+}
+
/*
* With the file (fd) open on the image, and (ehdr) containing
* the Elf header, load the image at (off)
@@ -198,22 +293,14 @@
Elf_Ehdr *hdr;
Elf_Shdr *shdr, *cshdr, *lshdr;
vm_offset_t firstaddr, lastaddr;
- int i, nsym, res, ret, shdrbytes, symstrindex;
+ int i, nsym, res, ret, shdrbytes, symstrindex;
ret = 0;
firstaddr = lastaddr = (vm_offset_t)off;
hdr = &ef->hdr;
+ shdr = ef->e_shdr;
ef->off = (vm_offset_t)off;
-
- /* Read in the section headers. */
shdrbytes = hdr->e_shnum * hdr->e_shentsize;
- shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes);
- if (shdr == NULL) {
- printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
- "_obj_loadimage: read section headers failed\n");
- goto out;
- }
- ef->e_shdr = shdr;
/*
* Decide where to load everything, but don't read it yet.
Index: stand/common/misc.c
===================================================================
--- stand/common/misc.c
+++ stand/common/misc.c
@@ -149,6 +149,7 @@
#ifdef DEBUG
printf("\nmalloc(%d) failed\n", (int)len);
#endif
+ errno = ENOMEM;
return (NULL);
}
if (lseek(fd, off, SEEK_SET) == -1) {
Index: stand/i386/libi386/biossmap.c
===================================================================
--- stand/i386/libi386/biossmap.c
+++ stand/i386/libi386/biossmap.c
@@ -119,6 +119,13 @@
}
void
+bios_getsmapdata(u_int *smaplenp, struct bios_smap **smapbasep)
+{
+ *smaplenp = smaplen;
+ *smapbasep = smapbase;
+}
+
+void
bios_addsmapdata(struct preloaded_file *kfp)
{
size_t size;
Index: stand/i386/libi386/i386_copy.c
===================================================================
--- stand/i386/libi386/i386_copy.c
+++ stand/i386/libi386/i386_copy.c
@@ -33,9 +33,133 @@
* XXX should check load address/size against memory top.
*/
#include <stand.h>
-
+#include <sys/param.h>
+#include <machine/elf.h>
+#include "bootstrap.h"
#include "libi386.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
i386_copyin(const void *src, vm_offset_t dest, const size_t len)
Index: stand/i386/libi386/libi386.h
===================================================================
--- stand/i386/libi386/libi386.h
+++ stand/i386/libi386/libi386.h
@@ -26,6 +26,8 @@
* $FreeBSD$
*/
+#include <sys/cdefs.h>
+#include <machine/pc/bios.h>
/*
* i386 fully-qualified device descriptor.
@@ -108,6 +110,7 @@
struct preloaded_file;
void bios_addsmapdata(struct preloaded_file *);
+void bios_getsmapdata(u_int *, struct bios_smap **);
void bios_getsmap(void);
void bios_getmem(void);
@@ -142,6 +145,7 @@
void biosacpi_detect(void);
int i386_autoload(void);
+uint64_t i386_loadaddr(u_int type, void *data, uint64_t addr);
int bi_getboothowto(char *kargs);
void bi_setboothowto(int howto);
Index: stand/i386/loader/main.c
===================================================================
--- stand/i386/loader/main.c
+++ stand/i386/loader/main.c
@@ -167,6 +167,7 @@
archsw.arch_readin = i386_readin;
archsw.arch_isainb = isa_inb;
archsw.arch_isaoutb = isa_outb;
+ archsw.arch_loadaddr = i386_loadaddr;
archsw.arch_hypervisor = x86_hypervisor;
#ifdef LOADER_ZFS_SUPPORT
archsw.arch_zfs_probe = i386_zfs_probe;

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 16, 10:16 AM (1 m, 19 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31534686
Default Alt Text
D22309.id64155.diff (9 KB)

Event Timeline