MFC r277215, r277291, r277418, r280953 and r280954:
loader: implement multiboot support for Xen Dom0 Note that only the subset of the multiboot specification needed in order to boot a Xen Dom0 is implemented. Sponsored by: Citrix Systems R&D
This commit is contained in:
parent
2f8109724f
commit
0ad0bd3893
@ -231,9 +231,9 @@ int mod_load(char *name, struct mod_depend *verinfo, int argc, char *argv[]);
|
||||
int mod_loadkld(const char *name, int argc, char *argv[]);
|
||||
|
||||
struct preloaded_file *file_alloc(void);
|
||||
struct preloaded_file *file_findfile(char *name, char *type);
|
||||
struct preloaded_file *file_findfile(const char *name, const char *type);
|
||||
struct file_metadata *file_findmetadata(struct preloaded_file *fp, int type);
|
||||
struct preloaded_file *file_loadraw(char *name, char *type);
|
||||
struct preloaded_file *file_loadraw(char *name, char *type, int insert);
|
||||
void file_discard(struct preloaded_file *fp);
|
||||
void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p);
|
||||
int file_addmodule(struct preloaded_file *fp, char *modname, int version,
|
||||
@ -257,6 +257,9 @@ int __elfN(obj_loadfile)(char *filename, u_int64_t dest,
|
||||
int __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr,
|
||||
const void *reldata, int reltype, Elf_Addr relbase,
|
||||
Elf_Addr dataaddr, void *data, size_t len);
|
||||
int __elfN(loadfile_raw)(char *filename, u_int64_t dest,
|
||||
struct preloaded_file **result, int multiboot);
|
||||
int __elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -76,7 +76,8 @@ static int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, u_int64_t
|
||||
static int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym);
|
||||
static int __elfN(reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
|
||||
Elf_Addr p, void *val, size_t len);
|
||||
static int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef);
|
||||
static int __elfN(parse_modmetadata)(struct preloaded_file *mp, elf_file_t ef,
|
||||
Elf_Addr p_start, Elf_Addr p_end);
|
||||
static symaddr_fn __elfN(symaddr);
|
||||
static char *fake_modname(const char *name);
|
||||
|
||||
@ -85,6 +86,61 @@ const char *__elfN(moduletype) = "elf module";
|
||||
|
||||
u_int64_t __elfN(relocation_offset) = 0;
|
||||
|
||||
static int
|
||||
__elfN(load_elf_header)(char *filename, elf_file_t ef)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
Elf_Ehdr *ehdr;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Open the image, read and validate the ELF header
|
||||
*/
|
||||
if (filename == NULL) /* can't handle nameless */
|
||||
return (EFTYPE);
|
||||
if ((ef->fd = open(filename, O_RDONLY)) == -1)
|
||||
return (errno);
|
||||
ef->firstpage = malloc(PAGE_SIZE);
|
||||
if (ef->firstpage == NULL) {
|
||||
close(ef->fd);
|
||||
return (ENOMEM);
|
||||
}
|
||||
bytes_read = read(ef->fd, ef->firstpage, PAGE_SIZE);
|
||||
ef->firstlen = (size_t)bytes_read;
|
||||
if (bytes_read < 0 || ef->firstlen <= sizeof(Elf_Ehdr)) {
|
||||
err = EFTYPE; /* could be EIO, but may be small file */
|
||||
goto error;
|
||||
}
|
||||
ehdr = ef->ehdr = (Elf_Ehdr *)ef->firstpage;
|
||||
|
||||
/* Is it ELF? */
|
||||
if (!IS_ELF(*ehdr)) {
|
||||
err = EFTYPE;
|
||||
goto error;
|
||||
}
|
||||
if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
|
||||
ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
|
||||
ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
|
||||
ehdr->e_version != EV_CURRENT ||
|
||||
ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */
|
||||
err = EFTYPE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
if (ef->firstpage != NULL) {
|
||||
free(ef->firstpage);
|
||||
ef->firstpage = NULL;
|
||||
}
|
||||
if (ef->fd != -1) {
|
||||
close(ef->fd);
|
||||
ef->fd = -1;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to load the file (file) as an ELF module. It will be stored at
|
||||
* (dest), and a pointer to a module structure describing the loaded object
|
||||
@ -92,55 +148,33 @@ u_int64_t __elfN(relocation_offset) = 0;
|
||||
*/
|
||||
int
|
||||
__elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
|
||||
{
|
||||
return (__elfN(loadfile_raw)(filename, dest, result, 0));
|
||||
}
|
||||
|
||||
int
|
||||
__elfN(loadfile_raw)(char *filename, u_int64_t dest,
|
||||
struct preloaded_file **result, int multiboot)
|
||||
{
|
||||
struct preloaded_file *fp, *kfp;
|
||||
struct elf_file ef;
|
||||
Elf_Ehdr *ehdr;
|
||||
int err;
|
||||
ssize_t bytes_read;
|
||||
|
||||
fp = NULL;
|
||||
bzero(&ef, sizeof(struct elf_file));
|
||||
ef.fd = -1;
|
||||
|
||||
/*
|
||||
* Open the image, read and validate the ELF header
|
||||
*/
|
||||
if (filename == NULL) /* can't handle nameless */
|
||||
return(EFTYPE);
|
||||
if ((ef.fd = open(filename, O_RDONLY)) == -1)
|
||||
return(errno);
|
||||
ef.firstpage = malloc(PAGE_SIZE);
|
||||
if (ef.firstpage == NULL) {
|
||||
close(ef.fd);
|
||||
return(ENOMEM);
|
||||
}
|
||||
bytes_read = read(ef.fd, ef.firstpage, PAGE_SIZE);
|
||||
ef.firstlen = (size_t)bytes_read;
|
||||
if (bytes_read < 0 || ef.firstlen <= sizeof(Elf_Ehdr)) {
|
||||
err = EFTYPE; /* could be EIO, but may be small file */
|
||||
goto oerr;
|
||||
}
|
||||
ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage;
|
||||
|
||||
/* Is it ELF? */
|
||||
if (!IS_ELF(*ehdr)) {
|
||||
err = EFTYPE;
|
||||
goto oerr;
|
||||
}
|
||||
if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
|
||||
ehdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
|
||||
ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
|
||||
ehdr->e_version != EV_CURRENT ||
|
||||
ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */
|
||||
err = EFTYPE;
|
||||
goto oerr;
|
||||
}
|
||||
err = __elfN(load_elf_header)(filename, &ef);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
ehdr = ef.ehdr;
|
||||
|
||||
/*
|
||||
* Check to see what sort of module we are.
|
||||
*/
|
||||
kfp = file_findfile(NULL, NULL);
|
||||
kfp = file_findfile(NULL, __elfN(kerneltype));
|
||||
#ifdef __powerpc__
|
||||
/*
|
||||
* Kernels can be ET_DYN, so just assume the first loaded object is the
|
||||
@ -177,6 +211,11 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
|
||||
|
||||
} else if (ehdr->e_type == ET_DYN) {
|
||||
/* Looks like a kld module */
|
||||
if (multiboot != 0) {
|
||||
printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n");
|
||||
err = EPERM;
|
||||
goto oerr;
|
||||
}
|
||||
if (kfp == NULL) {
|
||||
printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module before kernel\n");
|
||||
err = EPERM;
|
||||
@ -209,10 +248,14 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
|
||||
err = EPERM;
|
||||
goto out;
|
||||
}
|
||||
if (ef.kernel)
|
||||
if (ef.kernel == 1 && multiboot == 0)
|
||||
setenv("kernelname", filename, 1);
|
||||
fp->f_name = strdup(filename);
|
||||
fp->f_type = strdup(ef.kernel ? __elfN(kerneltype) : __elfN(moduletype));
|
||||
if (multiboot == 0)
|
||||
fp->f_type = strdup(ef.kernel ?
|
||||
__elfN(kerneltype) : __elfN(moduletype));
|
||||
else
|
||||
fp->f_type = strdup("elf multiboot kernel");
|
||||
|
||||
#ifdef ELF_VERBOSE
|
||||
if (ef.kernel)
|
||||
@ -240,7 +283,8 @@ __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result)
|
||||
out:
|
||||
if (ef.firstpage)
|
||||
free(ef.firstpage);
|
||||
close(ef.fd);
|
||||
if (ef.fd != -1)
|
||||
close(ef.fd);
|
||||
return(err);
|
||||
}
|
||||
|
||||
@ -269,6 +313,8 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off)
|
||||
int symtabindex;
|
||||
Elf_Size size;
|
||||
u_int fpcopy;
|
||||
Elf_Sym sym;
|
||||
Elf_Addr p_start, p_end;
|
||||
|
||||
dp = NULL;
|
||||
shdr = NULL;
|
||||
@ -571,7 +617,15 @@ nosyms:
|
||||
COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains));
|
||||
ef->buckets = ef->hashtab + 2;
|
||||
ef->chains = ef->buckets + ef->nbuckets;
|
||||
if (__elfN(parse_modmetadata)(fp, ef) == 0)
|
||||
|
||||
if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
|
||||
return 0;
|
||||
p_start = sym.st_value + ef->off;
|
||||
if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
|
||||
return ENOENT;
|
||||
p_end = sym.st_value + ef->off;
|
||||
|
||||
if (__elfN(parse_modmetadata)(fp, ef, p_start, p_end) == 0)
|
||||
goto out;
|
||||
|
||||
if (ef->kernel) /* kernel must not depend on anything */
|
||||
@ -634,7 +688,123 @@ struct mod_metadata32 {
|
||||
#endif
|
||||
|
||||
int
|
||||
__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
|
||||
__elfN(load_modmetadata)(struct preloaded_file *fp, u_int64_t dest)
|
||||
{
|
||||
struct elf_file ef;
|
||||
int err, i, j;
|
||||
Elf_Shdr *sh_meta, *shdr = NULL;
|
||||
Elf_Shdr *sh_data[2];
|
||||
char *shstrtab = NULL;
|
||||
size_t size;
|
||||
Elf_Addr p_start, p_end;
|
||||
|
||||
bzero(&ef, sizeof(struct elf_file));
|
||||
ef.fd = -1;
|
||||
|
||||
err = __elfN(load_elf_header)(fp->f_name, &ef);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
if (ef.ehdr->e_type == ET_EXEC) {
|
||||
ef.kernel = 1;
|
||||
} else if (ef.ehdr->e_type != ET_DYN) {
|
||||
err = EFTYPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = ef.ehdr->e_shnum * ef.ehdr->e_shentsize;
|
||||
shdr = alloc_pread(ef.fd, ef.ehdr->e_shoff, size);
|
||||
if (shdr == NULL) {
|
||||
err = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Load shstrtab. */
|
||||
shstrtab = alloc_pread(ef.fd, shdr[ef.ehdr->e_shstrndx].sh_offset,
|
||||
shdr[ef.ehdr->e_shstrndx].sh_size);
|
||||
if (shstrtab == NULL) {
|
||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"load_modmetadata: unable to load shstrtab\n");
|
||||
err = EFTYPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Find set_modmetadata_set and data sections. */
|
||||
sh_data[0] = sh_data[1] = sh_meta = NULL;
|
||||
for (i = 0, j = 0; i < ef.ehdr->e_shnum; i++) {
|
||||
if (strcmp(&shstrtab[shdr[i].sh_name],
|
||||
"set_modmetadata_set") == 0) {
|
||||
sh_meta = &shdr[i];
|
||||
}
|
||||
if ((strcmp(&shstrtab[shdr[i].sh_name], ".data") == 0) ||
|
||||
(strcmp(&shstrtab[shdr[i].sh_name], ".rodata") == 0)) {
|
||||
sh_data[j++] = &shdr[i];
|
||||
}
|
||||
}
|
||||
if (sh_meta == NULL || sh_data[0] == NULL || sh_data[1] == NULL) {
|
||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"load_modmetadata: unable to find set_modmetadata_set or data sections\n");
|
||||
err = EFTYPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Load set_modmetadata_set into memory */
|
||||
err = kern_pread(ef.fd, dest, sh_meta->sh_size, sh_meta->sh_offset);
|
||||
if (err != 0) {
|
||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"load_modmetadata: unable to load set_modmetadata_set: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
p_start = dest;
|
||||
p_end = dest + sh_meta->sh_size;
|
||||
dest += sh_meta->sh_size;
|
||||
|
||||
/* Load data sections into memory. */
|
||||
err = kern_pread(ef.fd, dest, sh_data[0]->sh_size,
|
||||
sh_data[0]->sh_offset);
|
||||
if (err != 0) {
|
||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"load_modmetadata: unable to load data: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to increment the dest, so that the offset is the same into
|
||||
* both the .rodata and .data sections.
|
||||
*/
|
||||
ef.off = -(sh_data[0]->sh_addr - dest);
|
||||
dest += (sh_data[1]->sh_addr - sh_data[0]->sh_addr);
|
||||
|
||||
err = kern_pread(ef.fd, dest, sh_data[1]->sh_size,
|
||||
sh_data[1]->sh_offset);
|
||||
if (err != 0) {
|
||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"load_modmetadata: unable to load data: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = __elfN(parse_modmetadata)(fp, &ef, p_start, p_end);
|
||||
if (err != 0) {
|
||||
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"load_modmetadata: unable to parse metadata: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (shstrtab != NULL)
|
||||
free(shstrtab);
|
||||
if (shdr != NULL)
|
||||
free(shdr);
|
||||
if (ef.firstpage != NULL)
|
||||
free(ef.firstpage);
|
||||
if (ef.fd != -1)
|
||||
close(ef.fd);
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
__elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef,
|
||||
Elf_Addr p_start, Elf_Addr p_end)
|
||||
{
|
||||
struct mod_metadata md;
|
||||
#if (defined(__i386__) || defined(__powerpc__)) && __ELF_WORD_SIZE == 64
|
||||
@ -644,20 +814,13 @@ __elfN(parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
|
||||
#endif
|
||||
struct mod_depend *mdepend;
|
||||
struct mod_version mver;
|
||||
Elf_Sym sym;
|
||||
char *s;
|
||||
int error, modcnt, minfolen;
|
||||
Elf_Addr v, p, p_stop;
|
||||
|
||||
if (__elfN(lookup_symbol)(fp, ef, "__start_set_modmetadata_set", &sym) != 0)
|
||||
return 0;
|
||||
p = sym.st_value + ef->off;
|
||||
if (__elfN(lookup_symbol)(fp, ef, "__stop_set_modmetadata_set", &sym) != 0)
|
||||
return ENOENT;
|
||||
p_stop = sym.st_value + ef->off;
|
||||
Elf_Addr v, p;
|
||||
|
||||
modcnt = 0;
|
||||
while (p < p_stop) {
|
||||
p = p_start;
|
||||
while (p < p_end) {
|
||||
COPYOUT(p, &v, sizeof(v));
|
||||
error = __elfN(reloc_ptr)(fp, ef, p, &v, sizeof(v));
|
||||
if (error == EOPNOTSUPP)
|
||||
|
@ -129,20 +129,13 @@ __elfN(obj_loadfile)(char *filename, u_int64_t dest,
|
||||
goto oerr;
|
||||
}
|
||||
|
||||
kfp = file_findfile(NULL, NULL);
|
||||
kfp = file_findfile(NULL, __elfN(obj_kerneltype));
|
||||
if (kfp == NULL) {
|
||||
printf("elf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"_obj_loadfile: can't load module before kernel\n");
|
||||
err = EPERM;
|
||||
goto oerr;
|
||||
}
|
||||
if (strcmp(__elfN(obj_kerneltype), kfp->f_type)) {
|
||||
printf("elf" __XSTRING(__ELF_WORD_SIZE)
|
||||
"_obj_loadfile: can't load module with kernel type '%s'\n",
|
||||
kfp->f_type);
|
||||
err = EPERM;
|
||||
goto oerr;
|
||||
}
|
||||
|
||||
if (archsw.arch_loadaddr != NULL)
|
||||
dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest);
|
||||
|
@ -138,7 +138,7 @@ command_load(int argc, char *argv[])
|
||||
command_errmsg = "invalid load type";
|
||||
return(CMD_ERROR);
|
||||
}
|
||||
return(file_loadraw(argv[1], typestr) ? CMD_OK : CMD_ERROR);
|
||||
return (file_loadraw(argv[1], typestr, 1) ? CMD_OK : CMD_ERROR);
|
||||
}
|
||||
/*
|
||||
* Do we have explicit KLD load ?
|
||||
@ -193,7 +193,7 @@ command_load_geli(int argc, char *argv[])
|
||||
argv += (optind - 1);
|
||||
argc -= (optind - 1);
|
||||
sprintf(typestr, "%s:geli_keyfile%d", argv[1], num);
|
||||
return(file_loadraw(argv[2], typestr) ? CMD_OK : CMD_ERROR);
|
||||
return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR);
|
||||
}
|
||||
|
||||
COMMAND_SET(unload, "unload", "unload all modules", command_unload);
|
||||
@ -362,7 +362,7 @@ file_load_dependencies(struct preloaded_file *base_file)
|
||||
* no arguments or anything.
|
||||
*/
|
||||
struct preloaded_file *
|
||||
file_loadraw(char *name, char *type)
|
||||
file_loadraw(char *name, char *type, int insert)
|
||||
{
|
||||
struct preloaded_file *fp;
|
||||
char *cp;
|
||||
@ -421,7 +421,8 @@ file_loadraw(char *name, char *type)
|
||||
loadaddr = laddr;
|
||||
|
||||
/* Add to the list of loaded files */
|
||||
file_insert_tail(fp);
|
||||
if (insert != 0)
|
||||
file_insert_tail(fp);
|
||||
close(fd);
|
||||
return(fp);
|
||||
}
|
||||
@ -524,7 +525,7 @@ mod_loadkld(const char *kldname, int argc, char *argv[])
|
||||
* NULL may be passed as a wildcard to either.
|
||||
*/
|
||||
struct preloaded_file *
|
||||
file_findfile(char *name, char *type)
|
||||
file_findfile(const char *name, const char *type)
|
||||
{
|
||||
struct preloaded_file *fp;
|
||||
|
||||
|
@ -261,7 +261,7 @@ fdt_load_dtb_file(const char * filename)
|
||||
oldbfp = file_findfile(NULL, "dtb");
|
||||
|
||||
/* Attempt to load and validate a new dtb from a file. */
|
||||
if ((bfp = file_loadraw(filename, "dtb")) == NULL) {
|
||||
if ((bfp = file_loadraw(filename, "dtb", 1)) == NULL) {
|
||||
sprintf(command_errbuf, "failed to load file '%s'", filename);
|
||||
return (1);
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ also support-functions
|
||||
s" beastie_disable" getenv dup -1 <> if
|
||||
s" YES" compare-insensitive 0= if
|
||||
any_conf_read? if
|
||||
load_xen_throw
|
||||
load_kernel
|
||||
load_modules
|
||||
then
|
||||
|
@ -147,13 +147,14 @@ only forth definitions also support-functions
|
||||
\ was succesfully loaded!
|
||||
any_conf_read? if
|
||||
s" loader_delay" getenv -1 = if
|
||||
load_xen_throw
|
||||
load_kernel
|
||||
load_modules
|
||||
else
|
||||
drop
|
||||
." Loading Kernel and Modules (Ctrl-C to Abort)" cr
|
||||
s" also support-functions" evaluate
|
||||
s" set delay_command='load_kernel load_modules'" evaluate
|
||||
s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate
|
||||
s" set delay_showdots" evaluate
|
||||
delay_execute
|
||||
then
|
||||
|
@ -1460,6 +1460,20 @@ also builtins
|
||||
abort" Unable to load a kernel!"
|
||||
;
|
||||
|
||||
: load_xen ( -- )
|
||||
s" xen_kernel" getenv dup -1 <> if
|
||||
1 1 load
|
||||
else
|
||||
drop
|
||||
0
|
||||
then
|
||||
;
|
||||
|
||||
: load_xen_throw ( -- ) ( throws: abort )
|
||||
load_xen
|
||||
abort" Unable to load Xen!"
|
||||
;
|
||||
|
||||
: set_defaultoptions ( -- )
|
||||
s" kernel_options" getenv dup -1 = if
|
||||
drop
|
||||
@ -1578,12 +1592,15 @@ also builtins
|
||||
else
|
||||
drop
|
||||
then
|
||||
r> if ( a path was passed )
|
||||
load_directory_or_file
|
||||
else
|
||||
standard_kernel_search
|
||||
load_xen
|
||||
?dup 0= if ( success )
|
||||
r> if ( a path was passed )
|
||||
load_directory_or_file
|
||||
else
|
||||
standard_kernel_search
|
||||
then
|
||||
?dup 0= if ['] load_modules catch then
|
||||
then
|
||||
?dup 0= if ['] load_modules catch then
|
||||
;
|
||||
|
||||
only forth definitions
|
||||
|
@ -6,7 +6,7 @@ INTERNALLIB=
|
||||
SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c biospnp.c \
|
||||
biospci.c biossmap.c bootinfo.c bootinfo32.c bootinfo64.c \
|
||||
comconsole.c devicename.c elf32_freebsd.c \
|
||||
elf64_freebsd.c \
|
||||
elf64_freebsd.c multiboot.c multiboot_tramp.S \
|
||||
i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \
|
||||
smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c
|
||||
.PATH: ${.CURDIR}/../../zfs
|
||||
@ -65,6 +65,7 @@ machine:
|
||||
|
||||
# XXX: clang integrated-as doesn't grok .codeNN directives yet
|
||||
CFLAGS.amd64_tramp.S= ${CLANG_NO_IAS}
|
||||
CFLAGS.multiboot_tramp.S= ${CLANG_NO_IAS}
|
||||
CFLAGS+= ${CFLAGS.${.IMPSRC:T}}
|
||||
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
|
@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/linker.h>
|
||||
#include <machine/bootinfo.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/metadata.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/specialreg.h>
|
||||
#include "bootstrap.h"
|
||||
@ -176,14 +177,15 @@ bi_checkcpu(void)
|
||||
* - Module metadata are formatted and placed in kernel space.
|
||||
*/
|
||||
int
|
||||
bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
|
||||
bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
|
||||
vm_offset_t *kernendp, int add_smap)
|
||||
{
|
||||
struct preloaded_file *xp, *kfp;
|
||||
struct i386_devdesc *rootdev;
|
||||
struct file_metadata *md;
|
||||
vm_offset_t addr;
|
||||
u_int64_t kernend;
|
||||
u_int64_t envp;
|
||||
u_int64_t module;
|
||||
vm_offset_t size;
|
||||
char *rootdevname;
|
||||
int howto;
|
||||
@ -210,21 +212,18 @@ bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
|
||||
/* Try reading the /etc/fstab file to select the root device */
|
||||
getrootmount(i386_fmtdev((void *)rootdev));
|
||||
|
||||
/* find the last module in the chain */
|
||||
addr = 0;
|
||||
for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
|
||||
if (addr < (xp->f_addr + xp->f_size))
|
||||
addr = xp->f_addr + xp->f_size;
|
||||
if (addr == 0) {
|
||||
/* find the last module in the chain */
|
||||
for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
|
||||
if (addr < (xp->f_addr + xp->f_size))
|
||||
addr = xp->f_addr + xp->f_size;
|
||||
}
|
||||
}
|
||||
/* pad to a page boundary */
|
||||
addr = roundup(addr, PAGE_SIZE);
|
||||
|
||||
/* copy our environment */
|
||||
envp = addr;
|
||||
addr = bi_copyenv(addr);
|
||||
|
||||
/* pad to a page boundary */
|
||||
addr = roundup(addr, PAGE_SIZE);
|
||||
/* place the metadata before anything */
|
||||
module = *modulep = addr;
|
||||
|
||||
kfp = file_findfile(NULL, "elf kernel");
|
||||
if (kfp == NULL)
|
||||
@ -235,20 +234,30 @@ bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp)
|
||||
file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
|
||||
file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
|
||||
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
|
||||
bios_addsmapdata(kfp);
|
||||
file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof module, &module);
|
||||
if (add_smap != 0)
|
||||
bios_addsmapdata(kfp);
|
||||
|
||||
/* Figure out the size and location of the metadata */
|
||||
*modulep = addr;
|
||||
size = bi_copymodules64(0);
|
||||
kernend = roundup(addr + size, PAGE_SIZE);
|
||||
|
||||
/* copy our environment */
|
||||
envp = roundup(addr + size, PAGE_SIZE);
|
||||
addr = bi_copyenv(envp);
|
||||
|
||||
/* set kernend */
|
||||
kernend = roundup(addr, PAGE_SIZE);
|
||||
*kernendp = kernend;
|
||||
|
||||
/* patch MODINFOMD_KERNEND */
|
||||
md = file_findmetadata(kfp, MODINFOMD_KERNEND);
|
||||
bcopy(&kernend, md->md_data, sizeof kernend);
|
||||
|
||||
/* patch MODINFOMD_ENVP */
|
||||
md = file_findmetadata(kfp, MODINFOMD_ENVP);
|
||||
bcopy(&envp, md->md_data, sizeof envp);
|
||||
|
||||
/* copy module list and metadata */
|
||||
(void)bi_copymodules64(addr);
|
||||
(void)bi_copymodules64(*modulep);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ elf64_exec(struct preloaded_file *fp)
|
||||
return(EFTYPE);
|
||||
ehdr = (Elf_Ehdr *)&(md->md_data);
|
||||
|
||||
err = bi_load64(fp->f_args, &modulep, &kernend);
|
||||
err = bi_load64(fp->f_args, 0, &modulep, &kernend, 1);
|
||||
if (err != 0)
|
||||
return(err);
|
||||
|
||||
|
@ -117,6 +117,7 @@ void bi_setboothowto(int howto);
|
||||
vm_offset_t bi_copyenv(vm_offset_t addr);
|
||||
int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip,
|
||||
vm_offset_t *modulep, vm_offset_t *kernend);
|
||||
int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernend);
|
||||
int bi_load64(char *args, vm_offset_t addr, vm_offset_t *modulep,
|
||||
vm_offset_t *kernend, int add_smap);
|
||||
|
||||
void pxe_enable(void *pxeinfo);
|
||||
|
425
sys/boot/i386/libi386/multiboot.c
Normal file
425
sys/boot/i386/libi386/multiboot.c
Normal file
@ -0,0 +1,425 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This multiboot implementation only implements a subset of the full
|
||||
* multiboot specification in order to be able to boot Xen and a
|
||||
* FreeBSD Dom0. Trying to use it to boot other multiboot compliant
|
||||
* kernels will most surely fail.
|
||||
*
|
||||
* The full multiboot specification can be found here:
|
||||
* http://www.gnu.org/software/grub/manual/multiboot/multiboot.html
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/stdint.h>
|
||||
#define _MACHINE_ELF_WANT_32BIT
|
||||
#include <machine/elf.h>
|
||||
#include <string.h>
|
||||
#include <stand.h>
|
||||
|
||||
#include "bootstrap.h"
|
||||
#include "multiboot.h"
|
||||
#include "../i386/libi386/libi386.h"
|
||||
#include "../i386/btx/lib/btxv86.h"
|
||||
|
||||
#define MULTIBOOT_SUPPORTED_FLAGS \
|
||||
(MULTIBOOT_PAGE_ALIGN|MULTIBOOT_MEMORY_INFO)
|
||||
#define NUM_MODULES 2
|
||||
#define METADATA_FIXED_SIZE (PAGE_SIZE*4)
|
||||
#define METADATA_MODULE_SIZE PAGE_SIZE
|
||||
|
||||
#define METADATA_RESV_SIZE(mod_num) \
|
||||
roundup(METADATA_FIXED_SIZE + METADATA_MODULE_SIZE * mod_num, PAGE_SIZE)
|
||||
|
||||
extern int elf32_loadfile_raw(char *filename, u_int64_t dest,
|
||||
struct preloaded_file **result, int multiboot);
|
||||
extern int elf64_load_modmetadata(struct preloaded_file *fp, u_int64_t dest);
|
||||
extern int elf64_obj_loadfile(char *filename, u_int64_t dest,
|
||||
struct preloaded_file **result);
|
||||
|
||||
static int multiboot_loadfile(char *, u_int64_t, struct preloaded_file **);
|
||||
static int multiboot_exec(struct preloaded_file *);
|
||||
|
||||
static int multiboot_obj_loadfile(char *, u_int64_t, struct preloaded_file **);
|
||||
static int multiboot_obj_exec(struct preloaded_file *fp);
|
||||
|
||||
struct file_format multiboot = { multiboot_loadfile, multiboot_exec };
|
||||
struct file_format multiboot_obj =
|
||||
{ multiboot_obj_loadfile, multiboot_obj_exec };
|
||||
|
||||
extern void multiboot_tramp();
|
||||
|
||||
static const char mbl_name[] = "FreeBSD Loader";
|
||||
|
||||
static int
|
||||
num_modules(struct preloaded_file *kfp)
|
||||
{
|
||||
struct kernel_module *kmp;
|
||||
int mod_num = 0;
|
||||
|
||||
for (kmp = kfp->f_modules; kmp != NULL; kmp = kmp->m_next)
|
||||
mod_num++;
|
||||
|
||||
return (mod_num);
|
||||
}
|
||||
|
||||
static vm_offset_t
|
||||
max_addr(void)
|
||||
{
|
||||
struct preloaded_file *fp;
|
||||
vm_offset_t addr = 0;
|
||||
|
||||
for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
|
||||
if (addr < (fp->f_addr + fp->f_size))
|
||||
addr = fp->f_addr + fp->f_size;
|
||||
}
|
||||
|
||||
return (addr);
|
||||
}
|
||||
|
||||
static int
|
||||
multiboot_loadfile(char *filename, u_int64_t dest,
|
||||
struct preloaded_file **result)
|
||||
{
|
||||
uint32_t *magic;
|
||||
int i, error;
|
||||
caddr_t header_search;
|
||||
ssize_t search_size;
|
||||
int fd;
|
||||
struct multiboot_header *header;
|
||||
char *cmdline;
|
||||
|
||||
/*
|
||||
* Read MULTIBOOT_SEARCH size in order to search for the
|
||||
* multiboot magic header.
|
||||
*/
|
||||
if (filename == NULL)
|
||||
return (EFTYPE);
|
||||
if ((fd = open(filename, O_RDONLY)) == -1)
|
||||
return (errno);
|
||||
header_search = malloc(MULTIBOOT_SEARCH);
|
||||
if (header_search == NULL) {
|
||||
close(fd);
|
||||
return (ENOMEM);
|
||||
}
|
||||
search_size = read(fd, header_search, MULTIBOOT_SEARCH);
|
||||
magic = (uint32_t *)header_search;
|
||||
|
||||
header = NULL;
|
||||
for (i = 0; i < (search_size / sizeof(uint32_t)); i++) {
|
||||
if (magic[i] == MULTIBOOT_HEADER_MAGIC) {
|
||||
header = (struct multiboot_header *)&magic[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (header == NULL) {
|
||||
error = EFTYPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Valid multiboot header has been found, validate checksum */
|
||||
if (header->magic + header->flags + header->checksum != 0) {
|
||||
printf(
|
||||
"Multiboot checksum failed, magic: 0x%x flags: 0x%x checksum: 0x%x\n",
|
||||
header->magic, header->flags, header->checksum);
|
||||
error = EFTYPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((header->flags & ~MULTIBOOT_SUPPORTED_FLAGS) != 0) {
|
||||
printf("Unsupported multiboot flags found: 0x%x\n",
|
||||
header->flags);
|
||||
error = EFTYPE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = elf32_loadfile_raw(filename, dest, result, 1);
|
||||
if (error != 0) {
|
||||
printf(
|
||||
"elf32_loadfile_raw failed: %d unable to load multiboot kernel\n",
|
||||
error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* f_addr is already aligned to PAGE_SIZE, make sure
|
||||
* f_size it's also aligned so when the modules are loaded
|
||||
* they are aligned to PAGE_SIZE.
|
||||
*/
|
||||
(*result)->f_size = roundup((*result)->f_size, PAGE_SIZE);
|
||||
|
||||
out:
|
||||
free(header_search);
|
||||
close(fd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
multiboot_exec(struct preloaded_file *fp)
|
||||
{
|
||||
vm_offset_t module_start, last_addr, metadata_size;
|
||||
vm_offset_t modulep, kernend, entry;
|
||||
struct file_metadata *md;
|
||||
Elf_Ehdr *ehdr;
|
||||
struct multiboot_info *mb_info = NULL;
|
||||
struct multiboot_mod_list *mb_mod = NULL;
|
||||
char *cmdline = NULL;
|
||||
size_t len;
|
||||
int error, mod_num;
|
||||
|
||||
/*
|
||||
* Don't pass the memory size found by the bootloader, the memory
|
||||
* available to Dom0 will be lower than that.
|
||||
*/
|
||||
unsetenv("smbios.memory.enabled");
|
||||
|
||||
/* Allocate the multiboot struct and fill the basic details. */
|
||||
mb_info = malloc(sizeof(struct multiboot_info));
|
||||
if (mb_info == NULL) {
|
||||
error = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
bzero(mb_info, sizeof(struct multiboot_info));
|
||||
mb_info->flags = MULTIBOOT_INFO_MEMORY|MULTIBOOT_INFO_BOOT_LOADER_NAME;
|
||||
mb_info->mem_lower = bios_basemem / 1024;
|
||||
mb_info->mem_upper = bios_extmem / 1024;
|
||||
mb_info->boot_loader_name = VTOP(mbl_name);
|
||||
|
||||
/* Set the Xen command line. */
|
||||
if (fp->f_args == NULL) {
|
||||
/* Add the Xen command line if it is set. */
|
||||
cmdline = getenv("xen_cmdline");
|
||||
if (cmdline != NULL) {
|
||||
fp->f_args = strdup(cmdline);
|
||||
if (fp->f_args == NULL) {
|
||||
error = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fp->f_args != NULL) {
|
||||
len = strlen(fp->f_name) + 1 + strlen(fp->f_args) + 1;
|
||||
cmdline = malloc(len);
|
||||
if (cmdline == NULL) {
|
||||
error = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
|
||||
mb_info->cmdline = VTOP(cmdline);
|
||||
mb_info->flags |= MULTIBOOT_INFO_CMDLINE;
|
||||
}
|
||||
|
||||
/* Find the entry point of the Xen kernel and save it for later */
|
||||
if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) {
|
||||
printf("Unable to find %s entry point\n", fp->f_name);
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
ehdr = (Elf_Ehdr *)&(md->md_data);
|
||||
entry = ehdr->e_entry & 0xffffff;
|
||||
|
||||
/*
|
||||
* Prepare the multiboot module list, Xen assumes the first
|
||||
* module is the Dom0 kernel, and the second one is the initramfs.
|
||||
* This is not optimal for FreeBSD, that doesn't have a initramfs
|
||||
* but instead loads modules dynamically and creates the metadata
|
||||
* info on-the-fly.
|
||||
*
|
||||
* As expected, the first multiboot module is going to be the
|
||||
* FreeBSD kernel loaded as a raw file. The second module is going
|
||||
* to contain the metadata info and the loaded modules.
|
||||
*
|
||||
* On native FreeBSD loads all the modules and then places the
|
||||
* metadata info at the end, but this is painful when running on Xen,
|
||||
* because it relocates the second multiboot module wherever it
|
||||
* likes. In order to workaround this limitation the metadata
|
||||
* information is placed at the start of the second module and
|
||||
* the original modulep value is saved together with the other
|
||||
* metadata, so we can relocate everything.
|
||||
*/
|
||||
fp = file_findfile(NULL, "elf kernel");
|
||||
if (fp == NULL) {
|
||||
printf("No FreeBSD kernel provided, aborting\n");
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
mb_mod = malloc(sizeof(struct multiboot_mod_list) * NUM_MODULES);
|
||||
if (mb_mod == NULL) {
|
||||
error = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
bzero(mb_mod, sizeof(struct multiboot_mod_list) * NUM_MODULES);
|
||||
|
||||
/*
|
||||
* Calculate how much memory is needed for the metatdata. We did
|
||||
* an approximation of the maximum size when loading the kernel,
|
||||
* but now we know the exact size, so we can release some of this
|
||||
* preallocated memory if not needed.
|
||||
*/
|
||||
last_addr = roundup(max_addr(), PAGE_SIZE);
|
||||
mod_num = num_modules(fp);
|
||||
|
||||
/*
|
||||
* Place the metadata after the last used address in order to
|
||||
* calculate it's size, this will not be used.
|
||||
*/
|
||||
error = bi_load64(fp->f_args, last_addr, &modulep, &kernend, 0);
|
||||
if (error != 0) {
|
||||
printf("bi_load64 failed: %d\n", error);
|
||||
goto error;
|
||||
}
|
||||
metadata_size = roundup(kernend - last_addr, PAGE_SIZE);
|
||||
|
||||
/* Check that the size is not greater than what we have reserved */
|
||||
if (metadata_size > METADATA_RESV_SIZE(mod_num)) {
|
||||
printf("Required memory for metadata is greater than reserved "
|
||||
"space, please increase METADATA_FIXED_SIZE and "
|
||||
"METADATA_MODULE_SIZE and rebuild the loader\n");
|
||||
error = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the position where the second multiboot module
|
||||
* will be placed.
|
||||
*/
|
||||
module_start = fp->f_addr + fp->f_size - metadata_size;
|
||||
|
||||
error = bi_load64(fp->f_args, module_start, &modulep, &kernend, 0);
|
||||
if (error != 0) {
|
||||
printf("bi_load64 failed: %d\n", error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
mb_mod[0].mod_start = fp->f_addr;
|
||||
mb_mod[0].mod_end = fp->f_addr + fp->f_size;
|
||||
mb_mod[0].mod_end -= METADATA_RESV_SIZE(mod_num);
|
||||
|
||||
mb_mod[1].mod_start = module_start;
|
||||
mb_mod[1].mod_end = last_addr;
|
||||
|
||||
mb_info->mods_count = NUM_MODULES;
|
||||
mb_info->mods_addr = VTOP(mb_mod);
|
||||
mb_info->flags |= MULTIBOOT_INFO_MODS;
|
||||
|
||||
dev_cleanup();
|
||||
__exec((void *)VTOP(multiboot_tramp), (void *)entry,
|
||||
(void *)VTOP(mb_info));
|
||||
|
||||
panic("exec returned");
|
||||
|
||||
error:
|
||||
if (mb_mod)
|
||||
free(mb_mod);
|
||||
if (mb_info)
|
||||
free(mb_info);
|
||||
if (cmdline)
|
||||
free(cmdline);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
multiboot_obj_loadfile(char *filename, u_int64_t dest,
|
||||
struct preloaded_file **result)
|
||||
{
|
||||
struct preloaded_file *mfp, *kfp, *rfp;
|
||||
struct kernel_module *kmp;
|
||||
int error, mod_num;
|
||||
|
||||
/* See if there's a multiboot kernel loaded */
|
||||
mfp = file_findfile(NULL, "elf multiboot kernel");
|
||||
if (mfp == NULL)
|
||||
return (EFTYPE);
|
||||
|
||||
/*
|
||||
* We have a multiboot kernel loaded, see if there's a FreeBSD
|
||||
* kernel loaded also.
|
||||
*/
|
||||
kfp = file_findfile(NULL, "elf kernel");
|
||||
if (kfp == NULL) {
|
||||
/*
|
||||
* No kernel loaded, this must be it. The kernel has to
|
||||
* be loaded as a raw file, it will be processed by
|
||||
* Xen and correctly loaded as an ELF file.
|
||||
*/
|
||||
rfp = file_loadraw(filename, "elf kernel", 0);
|
||||
if (rfp == NULL) {
|
||||
printf(
|
||||
"Unable to load %s as a multiboot payload kernel\n",
|
||||
filename);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Load kernel metadata... */
|
||||
setenv("kernelname", filename, 1);
|
||||
error = elf64_load_modmetadata(rfp, rfp->f_addr + rfp->f_size);
|
||||
if (error) {
|
||||
printf("Unable to load kernel %s metadata error: %d\n",
|
||||
rfp->f_name, error);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save space at the end of the kernel in order to place
|
||||
* the metadata information. We do an approximation of the
|
||||
* max metadata size, this is not optimal but it's probably
|
||||
* the best we can do at this point. Once all modules are
|
||||
* loaded and the size of the metadata is known this
|
||||
* space will be recovered if not used.
|
||||
*/
|
||||
mod_num = num_modules(rfp);
|
||||
rfp->f_size = roundup(rfp->f_size, PAGE_SIZE);
|
||||
rfp->f_size += METADATA_RESV_SIZE(mod_num);
|
||||
*result = rfp;
|
||||
} else {
|
||||
/* The rest should be loaded as regular modules */
|
||||
error = elf64_obj_loadfile(filename, dest, result);
|
||||
if (error != 0) {
|
||||
printf("Unable to load %s as an object file, error: %d",
|
||||
filename, error);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
multiboot_obj_exec(struct preloaded_file *fp)
|
||||
{
|
||||
|
||||
return (EFTYPE);
|
||||
}
|
225
sys/boot/i386/libi386/multiboot.h
Normal file
225
sys/boot/i386/libi386/multiboot.h
Normal file
@ -0,0 +1,225 @@
|
||||
/* multiboot.h - Multiboot header file. */
|
||||
/* Copyright (C) 1999,2003,2007,2008,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
|
||||
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef MULTIBOOT_HEADER
|
||||
#define MULTIBOOT_HEADER 1
|
||||
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
#define MULTIBOOT_SEARCH 8192
|
||||
|
||||
/* The magic field should contain this. */
|
||||
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
||||
|
||||
/* This should be in %eax. */
|
||||
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
|
||||
|
||||
/* The bits in the required part of flags field we don't support. */
|
||||
#define MULTIBOOT_UNSUPPORTED 0x0000fffc
|
||||
|
||||
/* Alignment of multiboot modules. */
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
|
||||
/* Alignment of the multiboot info structure. */
|
||||
#define MULTIBOOT_INFO_ALIGN 0x00000004
|
||||
|
||||
/* Flags set in the 'flags' member of the multiboot header. */
|
||||
|
||||
/* Align all boot modules on i386 page (4KB) boundaries. */
|
||||
#define MULTIBOOT_PAGE_ALIGN 0x00000001
|
||||
|
||||
/* Must pass memory information to OS. */
|
||||
#define MULTIBOOT_MEMORY_INFO 0x00000002
|
||||
|
||||
/* Must pass video information to OS. */
|
||||
#define MULTIBOOT_VIDEO_MODE 0x00000004
|
||||
|
||||
/* This flag indicates the use of the address fields in the header. */
|
||||
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
|
||||
|
||||
/* Flags to be set in the 'flags' member of the multiboot info structure. */
|
||||
|
||||
/* is there basic lower/upper memory information? */
|
||||
#define MULTIBOOT_INFO_MEMORY 0x00000001
|
||||
/* is there a boot device set? */
|
||||
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
|
||||
/* is the command-line defined? */
|
||||
#define MULTIBOOT_INFO_CMDLINE 0x00000004
|
||||
/* are there modules to do something with? */
|
||||
#define MULTIBOOT_INFO_MODS 0x00000008
|
||||
|
||||
/* These next two are mutually exclusive */
|
||||
|
||||
/* is there a symbol table loaded? */
|
||||
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
|
||||
/* is there an ELF section header table? */
|
||||
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
|
||||
|
||||
/* is there a full memory map? */
|
||||
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
|
||||
|
||||
/* Is there drive info? */
|
||||
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
|
||||
|
||||
/* Is there a config table? */
|
||||
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
|
||||
|
||||
/* Is there a boot loader name? */
|
||||
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
|
||||
|
||||
/* Is there a APM table? */
|
||||
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
|
||||
|
||||
/* Is there video information? */
|
||||
#define MULTIBOOT_INFO_VIDEO_INFO 0x00000800
|
||||
|
||||
#ifndef ASM_FILE
|
||||
|
||||
typedef unsigned short multiboot_uint16_t;
|
||||
typedef unsigned int multiboot_uint32_t;
|
||||
typedef unsigned long long multiboot_uint64_t;
|
||||
|
||||
struct multiboot_header
|
||||
{
|
||||
/* Must be MULTIBOOT_MAGIC - see above. */
|
||||
multiboot_uint32_t magic;
|
||||
|
||||
/* Feature flags. */
|
||||
multiboot_uint32_t flags;
|
||||
|
||||
/* The above fields plus this one must equal 0 mod 2^32. */
|
||||
multiboot_uint32_t checksum;
|
||||
|
||||
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
|
||||
multiboot_uint32_t header_addr;
|
||||
multiboot_uint32_t load_addr;
|
||||
multiboot_uint32_t load_end_addr;
|
||||
multiboot_uint32_t bss_end_addr;
|
||||
multiboot_uint32_t entry_addr;
|
||||
|
||||
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
|
||||
multiboot_uint32_t mode_type;
|
||||
multiboot_uint32_t width;
|
||||
multiboot_uint32_t height;
|
||||
multiboot_uint32_t depth;
|
||||
};
|
||||
|
||||
/* The symbol table for a.out. */
|
||||
struct multiboot_aout_symbol_table
|
||||
{
|
||||
multiboot_uint32_t tabsize;
|
||||
multiboot_uint32_t strsize;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t reserved;
|
||||
};
|
||||
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
|
||||
|
||||
/* The section header table for ELF. */
|
||||
struct multiboot_elf_section_header_table
|
||||
{
|
||||
multiboot_uint32_t num;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t shndx;
|
||||
};
|
||||
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
|
||||
|
||||
struct multiboot_info
|
||||
{
|
||||
/* Multiboot info version number */
|
||||
multiboot_uint32_t flags;
|
||||
|
||||
/* Available memory from BIOS */
|
||||
multiboot_uint32_t mem_lower;
|
||||
multiboot_uint32_t mem_upper;
|
||||
|
||||
/* "root" partition */
|
||||
multiboot_uint32_t boot_device;
|
||||
|
||||
/* Kernel command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/* Boot-Module list */
|
||||
multiboot_uint32_t mods_count;
|
||||
multiboot_uint32_t mods_addr;
|
||||
|
||||
union
|
||||
{
|
||||
multiboot_aout_symbol_table_t aout_sym;
|
||||
multiboot_elf_section_header_table_t elf_sec;
|
||||
} u;
|
||||
|
||||
/* Memory Mapping buffer */
|
||||
multiboot_uint32_t mmap_length;
|
||||
multiboot_uint32_t mmap_addr;
|
||||
|
||||
/* Drive Info buffer */
|
||||
multiboot_uint32_t drives_length;
|
||||
multiboot_uint32_t drives_addr;
|
||||
|
||||
/* ROM configuration table */
|
||||
multiboot_uint32_t config_table;
|
||||
|
||||
/* Boot Loader Name */
|
||||
multiboot_uint32_t boot_loader_name;
|
||||
|
||||
/* APM table */
|
||||
multiboot_uint32_t apm_table;
|
||||
|
||||
/* Video */
|
||||
multiboot_uint32_t vbe_control_info;
|
||||
multiboot_uint32_t vbe_mode_info;
|
||||
multiboot_uint16_t vbe_mode;
|
||||
multiboot_uint16_t vbe_interface_seg;
|
||||
multiboot_uint16_t vbe_interface_off;
|
||||
multiboot_uint16_t vbe_interface_len;
|
||||
};
|
||||
typedef struct multiboot_info multiboot_info_t;
|
||||
|
||||
struct multiboot_mmap_entry
|
||||
{
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint64_t addr;
|
||||
multiboot_uint64_t len;
|
||||
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||
multiboot_uint32_t type;
|
||||
} __attribute__((packed));
|
||||
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
|
||||
|
||||
struct multiboot_mod_list
|
||||
{
|
||||
/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
|
||||
multiboot_uint32_t mod_start;
|
||||
multiboot_uint32_t mod_end;
|
||||
|
||||
/* Module command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/* padding to take it to 16 bytes (must be zero) */
|
||||
multiboot_uint32_t pad;
|
||||
};
|
||||
typedef struct multiboot_mod_list multiboot_module_t;
|
||||
|
||||
#endif /* ! ASM_FILE */
|
||||
|
||||
#endif /* ! MULTIBOOT_HEADER */
|
51
sys/boot/i386/libi386/multiboot_tramp.S
Normal file
51
sys/boot/i386/libi386/multiboot_tramp.S
Normal file
@ -0,0 +1,51 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Roger Pau Monné <royger@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define ASM_FILE
|
||||
#include "multiboot.h"
|
||||
|
||||
/*
|
||||
* The multiboot specification requires the executable to be launched
|
||||
* with %cs set to a flat read/execute segment with offset 0 and limit
|
||||
* 0xFFFFFFFF, and the rest of the segment registers (%ds, %es, %fs,
|
||||
* %gs, %ss) to flat read/write segments with the same offset and limit.
|
||||
* This is already done by the BTX code before calling multiboot_tramp,
|
||||
* so there is no need to do anything here.
|
||||
*/
|
||||
|
||||
.globl multiboot_tramp
|
||||
multiboot_tramp:
|
||||
/* Be sure that interrupts are disabled. */
|
||||
cli
|
||||
|
||||
movl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
|
||||
/* Get the entry point and address of the multiboot_info parameter. */
|
||||
movl 8(%esp), %ebx
|
||||
movl 4(%esp), %ecx
|
||||
|
||||
call *%ecx
|
@ -107,8 +107,12 @@ extern struct file_format i386_elf;
|
||||
extern struct file_format i386_elf_obj;
|
||||
extern struct file_format amd64_elf;
|
||||
extern struct file_format amd64_elf_obj;
|
||||
extern struct file_format multiboot;
|
||||
extern struct file_format multiboot_obj;
|
||||
|
||||
struct file_format *file_formats[] = {
|
||||
&multiboot,
|
||||
&multiboot_obj,
|
||||
#ifdef LOADER_PREFER_AMD64
|
||||
&amd64_elf,
|
||||
&amd64_elf_obj,
|
||||
|
Loading…
x
Reference in New Issue
Block a user