#include <stand.h>
#include <sys/param.h>
#include <sys/reboot.h>
#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"
#include "modinfo.h"
#include "libi386.h"
#include "btxv86.h"
#ifdef LOADER_GELI_SUPPORT
#include "geliboot.h"
#endif
static int
bi_checkcpu(void)
{
char *cpu_vendor;
int vendor[3];
int eflags;
unsigned int regs[4];
eflags = read_eflags();
write_eflags(eflags ^ PSL_ID);
if (!((eflags ^ read_eflags()) & PSL_ID))
return (0);
do_cpuid(0, regs);
vendor[0] = regs[1];
vendor[1] = regs[3];
vendor[2] = regs[2];
cpu_vendor = (char *)vendor;
if (strncmp(cpu_vendor, INTEL_VENDOR_ID, 12) != 0 &&
strncmp(cpu_vendor, AMD_VENDOR_ID, 12) != 0 &&
strncmp(cpu_vendor, HYGON_VENDOR_ID, 12) != 0 &&
strncmp(cpu_vendor, CENTAUR_VENDOR_ID, 12) != 0)
return (0);
do_cpuid(0x80000000, regs);
if (!(regs[0] >= 0x80000001))
return (0);
do_cpuid(0x80000001, regs);
return (regs[3] & AMDID_LM);
}
int
bi_load64(char *args, vm_offset_t *modulep,
vm_offset_t *kernendp, int add_smap)
{
struct preloaded_file *xp, *kfp;
struct i386_devdesc *rootdev;
struct file_metadata *md;
uint64_t kernend;
uint64_t envp;
uint64_t module;
uint64_t addr;
vm_offset_t size;
char *rootdevname;
int howto;
if (!bi_checkcpu()) {
printf("CPU doesn't support long mode\n");
return (EINVAL);
}
howto = bi_getboothowto(args);
rootdevname = getenv("rootdev");
i386_getdev((void **)(&rootdev), rootdevname, NULL);
if (rootdev == NULL) {
printf("can't determine root device\n");
return(EINVAL);
}
getrootmount(devformat(&rootdev->dd));
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;
}
addr = md_align(addr);
addr = build_font_module(addr);
module = *modulep = addr;
kfp = file_findfile(NULL, md_kerntype);
if (kfp == NULL)
panic("can't find kernel file");
kernend = 0;
file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
file_addmetadata(kfp, MODINFOMD_MODULEP, sizeof module, &module);
if (add_smap != 0)
bios_addsmapdata(kfp);
#ifdef LOADER_GELI_SUPPORT
geli_export_key_metadata(kfp);
#endif
bi_load_vbe_data(kfp);
size = md_copymodules(0, true);
envp = md_align(addr + size);
addr = md_copyenv(envp);
kernend = md_align(addr);
*kernendp = kernend;
md = file_findmetadata(kfp, MODINFOMD_KERNEND);
bcopy(&kernend, md->md_data, sizeof kernend);
md = file_findmetadata(kfp, MODINFOMD_ENVP);
bcopy(&envp, md->md_data, sizeof envp);
(void)md_copymodules(*modulep, true);
return(0);
}