Exemple #1
0
/* Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
int main(int argc, char **argv)
{
  int i;
  VM *vm = malloc(sizeof(VM));
  strcpy(vm->filename, "retroImage");

  init_vm(vm);
  dev_init_input();

  /* Parse the command line arguments */
  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "--with") == 0)
      dev_include(argv[++i]);
    if (strcmp(argv[i], "--image") == 0)
      strcpy(vm->filename, argv[++i]);
    if (strcmp(argv[i], "--shrink") == 0)
      vm->shrink = 1;
  }

  dev_init_output();

  if (vm_load_image(vm, vm->filename) == -1) {
    dev_cleanup();
    printf("Sorry, unable to find %s\n", vm->filename);
    exit(1);
  }

  for (vm->ip = 0; vm->ip < IMAGE_SIZE; vm->ip++)
    vm_process(vm);

  dev_cleanup();
  return 0;
}
int
__elfN(ofw_exec)(struct preloaded_file *fp)
{
	struct file_metadata	*fmp;
	vm_offset_t		mdp;
	Elf_Ehdr		*e;
	int			error;
	intptr_t		entry;

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) {
		return(EFTYPE);
	}
	e = (Elf_Ehdr *)&fmp->md_data;
	entry = e->e_entry;

	if ((error = md_load(fp->f_args, &mdp)) != 0)
		return (error);

	printf("Kernel entry at 0x%lx ...\n", e->e_entry);

	dev_cleanup();
	ofw_release_heap();
	OF_chain((void *)reloc, end - (char *)reloc, (void *)entry,
	    (void *)mdp, sizeof(mdp));

	panic("exec returned");
}
Exemple #3
0
static int
beri_elf64_exec(struct preloaded_file *fp)
{
	void (*entry)(register_t, register_t, register_t, register_t);
	struct file_metadata *md;
	vm_offset_t mdp;
	Elf_Ehdr *ehdr;
	int error;

	md = file_findmetadata(fp, MODINFOMD_ELFHDR);
	if (md == NULL) {
		printf("%s: file_findmetadata failed\n");
		return (EFTYPE);
	}
	ehdr = (Elf_Ehdr *)md->md_data;

	error = md_load64(fp->f_args, &mdp);
	if (error) {
		printf("%s: md_load64 failed\n");
		return (error);
	}

	entry = (void *)ehdr->e_entry;
	printf("Kernel entry at %p\n", entry);

	dev_cleanup();		/* XXXRW: Required? */
	printf("Kernel args: %s\n", fp->f_args);

	/*
	 * Configure bootinfo for the loaded kernel.  Some values are
	 * inherited from the bootinfo passed to us by boot2 (e.g., DTB
	 * pointer); others are local to the loader (e.g., kernel boot flags).
	 */
	bzero(&bootinfo, sizeof(bootinfo));
	bootinfo.bi_version = BOOTINFO_VERSION;
	bootinfo.bi_size = sizeof(bootinfo);
	bootinfo.bi_boot2opts = boot2_bootinfo.bi_boot2opts;
	/* NB: bi_kernelname used only by boot2. */
	/* NB: bi_nfs_diskless not yet. */
	bootinfo.bi_dtb = boot2_bootinfo.bi_dtb;
	bootinfo.bi_memsize = boot2_bootinfo.bi_memsize;
	bootinfo.bi_modulep = mdp;

	/*
	 * Flush the instruction cache before running any instructions from
	 * the loaded kernel.
	 */
	beri_icache_sync();

	/*
	 * XXXRW: For now, pass 'memsize' rather than dtb or bootinfo.  This
	 * is the 'old' ABI spoken by Miniboot and the kernel.  To pass in
	 * boot2opts, modules, etc, we will need to fix this to pass in at
	 * least bootinfop.
	 */
	(*entry)(boot2_argc, (register_t)boot2_argv, (register_t)boot2_envv,
	    &bootinfo);

	panic("exec returned");
}
Exemple #4
0
/*
 * There is an ELF kernel and one or more ELF modules loaded.  
 * We wish to start executing the kernel image, so make such 
 * preparations as are required, and do so.
 */
static int
elf32_exec(struct preloaded_file *fp)
{
    struct file_metadata	*md;
    Elf_Ehdr 			*ehdr;
    vm_offset_t			entry, bootinfop, modulep, kernend;
    int				boothowto, err, bootdev;

    if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
	return(EFTYPE);
    ehdr = (Elf_Ehdr *)&(md->md_data);

    err = bi_load32(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend);
    if (err != 0)
	return(err);
    entry = ehdr->e_entry & 0xffffff;

#ifdef DEBUG
    printf("Start @ 0x%lx ...\n", entry);
#endif

    dev_cleanup();
    __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop, modulep, kernend);

    panic("exec returned");
}
Exemple #5
0
static int
__elfN(arm_exec)(struct preloaded_file *fp)
{
	struct file_metadata *fmp;
	vm_offset_t modulep, kernend;
	Elf_Ehdr *e;
	int error;
	void (*entry)(void *);

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return (EFTYPE);

	e = (Elf_Ehdr *)&fmp->md_data;

	if ((error = bi_load(fp->f_args, &modulep, &kernend)) != 0)
		return (error);

	entry = efi_translate(e->e_entry);
	printf("Kernel entry at 0x%x...\n", (unsigned)entry);
	printf("Kernel args: %s\n", fp->f_args);
	printf("modulep: %#x\n", modulep);
	printf("relocation_offset %llx\n", __elfN(relocation_offset));

	dev_cleanup();

	(*entry)((void *)modulep);
	panic("exec returned");
}
Exemple #6
0
int
__elfN(uboot_exec)(struct preloaded_file *fp)
{
	struct file_metadata *fmp;
	vm_offset_t mdp;
	Elf_Ehdr *e;
	int error;
	void (*entry)(void *);

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return (EFTYPE);

	e = (Elf_Ehdr *)&fmp->md_data;

	if ((error = md_load(fp->f_args, &mdp)) != 0)
		return (error);

	entry = (void *)e->e_entry;
	printf("Kernel entry at 0x%p...\n", entry);

	dev_cleanup();
	printf("Kernel args: %s\n", fp->f_args);

	(*entry)((void *)mdp);
	panic("exec returned");
}
Exemple #7
0
int
ppc64_elf_exec(struct preloaded_file *fp)
{
	struct file_metadata	*fmp;
	vm_offset_t		mdp;
	Elf_Ehdr		*e;
	int			error;
	int (*entry)(u_long, u_long, u_long, void *, u_long);

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) {
		return(EFTYPE);
	}
	e = (Elf_Ehdr *)&fmp->md_data;
	
	/* Handle function descriptor for ELFv1 kernels */
	if ((e->e_flags & 3) == 2)
		entry = e->e_entry;
	else
		entry = (void *)(uintptr_t)(*(uint64_t *)e->e_entry);

	if ((error = md_load64(fp->f_args, &mdp)) != 0)
		return (error);

	printf("Kernel entry at %p ...\n", entry);

	dev_cleanup();

	entry(0 /* FDT */, 0 /* Phys. mem offset */, 0 /* OF entry */,
	     (void *)mdp, sizeof(mdp));

	panic("exec returned");
}
Exemple #8
0
int vm_save_image(VM *vm, char *image) {
  FILE *fp;
  int x;

  if ((fp = fopen(image, "wb")) == NULL)
  {
    fprintf(stderr, "Sorry, but I couldn't open %s\n", image);
    dev_cleanup();
    exit(-1);
  }

  if (vm->shrink == 0)
    x = fwrite(&vm->image, sizeof(int), IMAGE_SIZE, fp);
  else
    x = fwrite(&vm->image, sizeof(int), vm->image[3], fp);
  fclose(fp);

  return x;
}
Exemple #9
0
/*
 * There is an ELF kernel and one or more ELF modules loaded.  
 * We wish to start executing the kernel image, so make such 
 * preparations as are required, and do so.
 */
static int
elf32_exec(struct preloaded_file *fp)
{
	struct file_metadata	*md;
	Elf_Ehdr 		*ehdr;
	vm_offset_t		entry, bootinfop, modulep, kernend;
	int			boothowto, err, bootdev;
	uint32_t		stack[1024];


	if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return(EFTYPE);
	ehdr = (Elf_Ehdr *)&(md->md_data);

	err = bi_load32(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend);
	if (err != 0)
		return(err);
	entry = ehdr->e_entry & 0xffffff;

#ifdef DEBUG
	printf("Start @ 0x%lx ...\n", entry);
#endif

	dev_cleanup();

	/*
	 * Build a scratch stack at physical 0x1000
	 */
	stack[0] = boothowto;
	stack[1] = bootdev;
	stack[2] = 0;
	stack[3] = 0;
	stack[4] = 0;
	stack[5] = bootinfop;
	stack[6] = modulep;
	stack[7] = kernend;
	CALLBACK(copyin, stack, 0x1000, sizeof(stack));
	CALLBACK(setreg, 4, 0x1000);
        CALLBACK(exec, entry);

	panic("exec returned");
}
Exemple #10
0
int
ppc64_ofw_elf_exec(struct preloaded_file *fp)
{
	struct file_metadata	*fmp;
	vm_offset_t		mdp, dtbp;
	Elf_Ehdr		*e;
	int			error;
	intptr_t		entry;

	if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) {
		return(EFTYPE);
	}
	e = (Elf_Ehdr *)&fmp->md_data;
	
	/* Handle function descriptor for ELFv1 kernels */
	if ((e->e_flags & 3) == 2)
		entry = e->e_entry;
	else
		entry = *(uint64_t *)e->e_entry;

	if ((error = md_load64(fp->f_args, &mdp, &dtbp)) != 0)
		return (error);

	printf("Kernel entry at 0x%lx ...\n", entry);

	dev_cleanup();
	ofw_release_heap();

	if (dtbp != 0) {
		OF_quiesce();
		((int (*)(u_long, u_long, u_long, void *, u_long))entry)(dtbp, 0, 0,
		    mdp, sizeof(mdp));
	} else {
		OF_chain((void *)reloc, end - (char *)reloc, (void *)entry,
		    (void *)mdp, sizeof(mdp));
	}

	panic("exec returned");
}
Exemple #11
0
/******************************************************
 * Main entry point into the VM
 ******************************************************/
int main(int argc, char **argv)
{
  int a, i, endian;
  char *opstat_path = 0;
  FILE *opstats = 0;

  VM *vm = malloc(sizeof(VM));

  endian = 0;

  strcpy(vm->filename, "retroImage");

  init_vm(vm);
  dev_init(INPUT);

  vm->shrink = 0;
  vm->trace = 0;
  vm->trace_stacks = 0;

  /* Parse the command line arguments */
  for (i = 1; i < argc; i++)
  {
    if (strcmp(argv[i], "--trace") == 0)
    {
      vm->trace = -1;
    }
    else if (strcmp(argv[i], "--trace-stacks") == 0)
    {
      vm->trace_stacks = -1;
    }
    else if (strcmp(argv[i], "--endian") == 0)
    {
      endian = -1;
    }
    else if (strcmp(argv[i], "--with") == 0)
    {
      i++; dev_include(argv[i]);
    }
    else if (strcmp(argv[i], "--opstats") == 0)
    {
      i++; opstat_path = argv[i];
      init_stats(&opstats, opstat_path, call_stats_please);
    }
    else if (strcmp(argv[i], "--callstats") == 0)
    {
      call_stats_please = 1;
      if (opstat_path)
      {
        init_stats(&opstats, opstat_path, call_stats_please);
      }
    }
    else if (strcmp(argv[i], "--shrink") == 0)
    {
      vm->shrink = 1;
    }
    else if ((strcmp(argv[i], "--help") == 0) ||
             (strcmp(argv[i], "-help") == 0)  ||
             (strcmp(argv[i], "/help") == 0)  ||
             (strcmp(argv[i], "/?") == 0)     ||
             (strcmp(argv[i], "/h") == 0)     ||
             (strcmp(argv[i], "-h") == 0))
    {
      fprintf(stderr, "%s [options] [imagename]\n", argv[0]);
      fprintf(stderr, "Valid options are:\n");
      fprintf(stderr, "   --about          Display some information about Ngaro\n");
      fprintf(stderr, "   --trace          Trace instructions being executed\n");
      fprintf(stderr, "     --trace-stacks Also trace data and return stack contents\n");
      fprintf(stderr, "   --endian         Load an image with a different endianness\n");
      fprintf(stderr, "   --shrink         Shrink the image to the current heap size when saving\n");
      fprintf(stderr, "   --with [file]    Treat [file] as an input source\n");
      fprintf(stderr, "   --opstats [file] Write statistics about VM operations to [file]\n");
      fprintf(stderr, "      --callstats      Include how many times each address is called (slow)\n");
      fprintf(stderr, "                       Also includes distribution of stack depths.\n");
      exit(0);
    }
    else if ((strcmp(argv[i], "--about") == 0) ||
             (strcmp(argv[i], "--version") == 0))
    {
      fprintf(stderr, "Retro Language  [VM: C, console]\n\n");
      exit(0);
    }
    else
    {
      strcpy(vm->filename, argv[i]);
    }
  }

  dev_init(OUTPUT);

  a = vm_load_image(vm, vm->filename);
  if (a == -1)
  {
    dev_cleanup();
    printf("Sorry, unable to find %s\n", vm->filename);
    exit(1);
  }

  /* Swap endian if --endian was passed */
  if (endian == -1)
    swapEndian(vm);

  /* Process the image */
  if (opstats == 0)
  {
    for (vm->ip = 0; vm->ip < IMAGE_SIZE; vm->ip++)
      vm_process(vm);
  }
  else
  {
    for (vm->ip = 0; vm->ip < IMAGE_SIZE; vm->ip++)
    {
      collect_stats(vm);
      vm_process(vm);
    }
    report_stats(opstats);
  }

  /* Once done, cleanup */
  dev_cleanup();
  return 0;
}
Exemple #12
0
static int
elf64_exec(struct preloaded_file *fp)
{
	vm_offset_t modulep, kernendp;
	vm_offset_t clean_addr;
	size_t clean_size;
	struct file_metadata *md;
	ACPI_TABLE_RSDP *rsdp;
	Elf_Ehdr *ehdr;
	char buf[24];
	int err, revision;
	void (*entry)(vm_offset_t);

	rsdp = efi_get_table(&acpi20_guid);
	if (rsdp == NULL) {
		rsdp = efi_get_table(&acpi_guid);
	}
	if (rsdp != NULL) {
		sprintf(buf, "0x%016llx", (unsigned long long)rsdp);
		setenv("hint.acpi.0.rsdp", buf, 1);
		revision = rsdp->Revision;
		if (revision == 0)
			revision = 1;
		sprintf(buf, "%d", revision);
		setenv("hint.acpi.0.revision", buf, 1);
		strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId));
		buf[sizeof(rsdp->OemId)] = '\0';
		setenv("hint.acpi.0.oem", buf, 1);
		sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress);
		setenv("hint.acpi.0.rsdt", buf, 1);
		if (revision >= 2) {
			/* XXX extended checksum? */
			sprintf(buf, "0x%016llx",
			    (unsigned long long)rsdp->XsdtPhysicalAddress);
			setenv("hint.acpi.0.xsdt", buf, 1);
			sprintf(buf, "%d", rsdp->Length);
			setenv("hint.acpi.0.xsdt_length", buf, 1);
		}
	}

	if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
        	return(EFTYPE);

	ehdr = (Elf_Ehdr *)&(md->md_data);
	entry = efi_translate(ehdr->e_entry);

	err = bi_load(fp->f_args, &modulep, &kernendp);
	if (err != 0)
		return (err);

	dev_cleanup();

	/* Clean D-cache under kernel area and invalidate whole I-cache */
	clean_addr = (vm_offset_t)efi_translate(fp->f_addr);
	clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr;

	cpu_flush_dcache((void *)clean_addr, clean_size);
	cpu_inval_icache(NULL, 0);

	(*entry)(modulep);
	panic("exec returned");
}
Exemple #13
0
static int
multiboot_exec(struct preloaded_file *fp)
{
	struct preloaded_file		*mfp;
	vm_offset_t			 entry;
	struct file_metadata		*md;
	struct multiboot_info		*mb_info = NULL;
	struct multiboot_mod_list	*mb_mod = NULL;
	multiboot_memory_map_t		*mmap;
	struct bios_smap		*smap;
	struct devdesc			*rootdev;
	char				*cmdline = NULL;
	size_t				 len;
	int				 error, num, i;
	int				 rootfs = 0;	/* flag for rootfs */
	int				 xen = 0;	/* flag for xen */
	int				 kernel = 0;	/* flag for kernel */

	/* Set up base for mb_malloc. */
	for (mfp = fp; mfp->f_next != NULL; mfp = mfp->f_next);

	/* Start info block from new page. */
	last_addr = roundup(mfp->f_addr + mfp->f_size, MULTIBOOT_MOD_ALIGN);

	/* Allocate the multiboot struct and fill the basic details. */
	mb_info = (struct multiboot_info *)PTOV(mb_malloc(sizeof (*mb_info)));

	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 = mb_malloc(strlen(bootprog_info) + 1);

	i386_copyin(bootprog_info, mb_info->boot_loader_name,
	    strlen(bootprog_info) + 1);

	i386_getdev((void **)(&rootdev), NULL, NULL);
	if (rootdev == NULL) {
		printf("can't determine root device\n");
		error = EINVAL;
		goto error;
	}

	/*
	 * Boot image command line. If args were not provided, we need to set
	 * args here, and that depends on image type...
	 * Fortunately we only have following options:
	 * 64 or 32 bit unix or xen. So we just check if f_name has unix.
	 */
	/* Do we boot xen? */
	if (strstr(fp->f_name, "unix") == NULL)
		xen = 1;

	entry = fp->f_addr;

	num = 0;
	for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
		num++;
		if (mfp->f_type != NULL && strcmp(mfp->f_type, "rootfs") == 0)
			rootfs++;
		if (mfp->f_type != NULL && strcmp(mfp->f_type, "kernel") == 0)
			kernel++;
	}

	if (num == 0 || rootfs == 0) {
		/* We need at least one module - rootfs. */
		printf("No rootfs module provided, aborting\n");
		error = EINVAL;
		goto error;
	}
	if (xen == 1 && kernel == 0) {
		printf("No kernel module provided for xen, aborting\n");
		error = EINVAL;
		goto error;
	}
	mb_mod = (struct multiboot_mod_list *) PTOV(last_addr);
	last_addr += roundup(sizeof(*mb_mod) * num, MULTIBOOT_INFO_ALIGN);

	bzero(mb_mod, sizeof(*mb_mod) * num);

	num = 0;
	for (mfp = fp->f_next; mfp != NULL; mfp = mfp->f_next) {
		mb_mod[num].mod_start = mfp->f_addr;
		mb_mod[num].mod_end = mfp->f_addr + mfp->f_size;

		if (strcmp(mfp->f_type, "kernel") == 0) {
			cmdline = NULL;
			error = mb_kernel_cmdline(mfp, rootdev, &cmdline);
			if (error != 0)
				goto error;
		} else {
			len = strlen(mfp->f_name) + 1;
			len += strlen(mfp->f_type) + 5 + 1;
			if (mfp->f_args != NULL) {
				len += strlen(mfp->f_args) + 1;
			}
			cmdline = malloc(len);
			if (cmdline == NULL) {
				error = ENOMEM;
				goto error;
			}

			if (mfp->f_args != NULL)
				snprintf(cmdline, len, "%s type=%s %s",
				    mfp->f_name, mfp->f_type, mfp->f_args);
			else
				snprintf(cmdline, len, "%s type=%s",
				    mfp->f_name, mfp->f_type);
		}

		mb_mod[num].cmdline = mb_malloc(strlen(cmdline)+1);
		i386_copyin(cmdline, mb_mod[num].cmdline, strlen(cmdline)+1);
		free(cmdline);
		num++;
	}

	mb_info->mods_count = num;
	mb_info->mods_addr = VTOP(mb_mod);
	mb_info->flags |= MULTIBOOT_INFO_MODS;

	md = file_findmetadata(fp, MODINFOMD_SMAP);
	if (md == NULL) {
		printf("no memory smap\n");
		error = EINVAL;
		goto error;
	}

	num = md->md_size / sizeof(struct bios_smap); /* number of entries */
	mmap = (multiboot_memory_map_t *)PTOV(mb_malloc(sizeof(*mmap) * num));

	mb_info->mmap_length = num * sizeof(*mmap);
	smap = (struct bios_smap *)md->md_data;

	for (i = 0; i < num; i++) {
		mmap[i].size = sizeof(*smap);
		mmap[i].addr = smap[i].base;
		mmap[i].len = smap[i].length;
		mmap[i].type = smap[i].type;
	}
	mb_info->mmap_addr = VTOP(mmap);
	mb_info->flags |= MULTIBOOT_INFO_MEM_MAP;

	if (strstr(getenv("loaddev"), "net") != NULL &&
	    bootp_response != NULL) {
		mb_info->drives_length = bootp_response_size;
		mb_info->drives_addr = mb_malloc(bootp_response_size);
		i386_copyin(bootp_response, mb_info->drives_addr,
		    bootp_response_size);
		mb_info->flags &= ~MULTIBOOT_INFO_DRIVE_INFO;
	}
	/*
	 * Set the image command line. Need to do this as last thing,
	 * as illumos kernel dboot_startkern will check cmdline
	 * address as last check to find first free address.
	 */
	if (fp->f_args == NULL) {
		if (xen)
			cmdline = getenv("xen_cmdline");
		else
			cmdline = getenv("boot-args");
		if (cmdline != NULL) {
			fp->f_args = strdup(cmdline);
			if (fp->f_args == NULL) {
				error = ENOMEM;
				goto error;
			}
		}
	}

	/*
	 * If the image is xen, we just use f_name + f_args for commandline
	 * for unix, we need to add zfs-bootfs.
	 */
	if (xen) {
		len = strlen(fp->f_name) + 1;
		if (fp->f_args != NULL)
			len += strlen(fp->f_args) + 1;

		if (fp->f_args != NULL) {
			if((cmdline = malloc(len)) == NULL) {
				error = ENOMEM;
				goto error;
			}
			snprintf(cmdline, len, "%s %s", fp->f_name, fp->f_args);
		} else {
			cmdline = strdup(fp->f_name);
			if (cmdline == NULL) {
				error = ENOMEM;
				goto error;
			}
		}
	} else {
		cmdline = NULL;
		if ((error = mb_kernel_cmdline(fp, rootdev, &cmdline)) != 0)
			goto error;
	}

	mb_info->cmdline = mb_malloc(strlen(cmdline)+1);
	i386_copyin(cmdline, mb_info->cmdline, strlen(cmdline)+1);
	mb_info->flags |= MULTIBOOT_INFO_CMDLINE;
	free(cmdline);
	cmdline = NULL;

	dev_cleanup();
	__exec((void *)VTOP(multiboot_tramp), MULTIBOOT_BOOTLOADER_MAGIC,
	    (void *)entry, (void *)VTOP(mb_info));

	panic("exec returned");

error:
	free(cmdline);
	return (error);
}
Exemple #14
0
/*
 * There is an ELF kernel and one or more ELF modules loaded.
 * We wish to start executing the kernel image, so make such
 * preparations as are required, and do so.
 */
static int
elf64_exec(struct preloaded_file *fp)
{
	struct file_metadata	*md;
	Elf_Ehdr 		*ehdr;
	vm_offset_t		modulep, kernend;
	int			err;
	int			i;
	uint32_t		stack[1024];
	p4_entry_t		PT4[512];
	p3_entry_t		PT3[512];
	p2_entry_t		PT2[512];
	uint64_t		gdtr[3];

	if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return(EFTYPE);
	ehdr = (Elf_Ehdr *)&(md->md_data);

	err = bi_load64(fp->f_args, &modulep, &kernend);
	if (err != 0)
		return(err);

	bzero(PT4, PAGE_SIZE);
	bzero(PT3, PAGE_SIZE);
	bzero(PT2, PAGE_SIZE);

	/*
	 * Build a scratch stack at physical 0x1000, page tables:
	 *	PT4 at 0x2000,
	 *	PT3 at 0x3000,
	 *	PT2 at 0x4000,
	 *      gdtr at 0x5000,
	 */

	/*
	 * This is kinda brutal, but every single 1GB VM memory segment
	 * points to the same first 1GB of physical memory.  But it is
	 * more than adequate.
	 */
	for (i = 0; i < 512; i++) {
		/* Each slot of the level 4 pages points to the same level 3 page */
		PT4[i] = (p4_entry_t) 0x3000;
		PT4[i] |= PG_V | PG_RW | PG_U;

		/* Each slot of the level 3 pages points to the same level 2 page */
		PT3[i] = (p3_entry_t) 0x4000;
		PT3[i] |= PG_V | PG_RW | PG_U;

		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
		PT2[i] = i * (2 * 1024 * 1024);
		PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
	}

#ifdef DEBUG
	printf("Start @ %#llx ...\n", ehdr->e_entry);
#endif

	dev_cleanup();

	stack[0] = 0;		/* return address */
	stack[1] = modulep;
	stack[2] = kernend;
	CALLBACK(copyin, stack, 0x1000, sizeof(stack));
	CALLBACK(copyin, PT4, 0x2000, sizeof(PT4));
	CALLBACK(copyin, PT3, 0x3000, sizeof(PT3));
	CALLBACK(copyin, PT2, 0x4000, sizeof(PT2));
	CALLBACK(setreg, 4, 0x1000);

	CALLBACK(setmsr, MSR_EFER, EFER_LMA | EFER_LME);
	CALLBACK(setcr, 4, CR4_PAE | CR4_VMXE);
	CALLBACK(setcr, 3, 0x2000);
	CALLBACK(setcr, 0, CR0_PG | CR0_PE | CR0_NE);

	setup_freebsd_gdt(gdtr);
	CALLBACK(copyin, gdtr, 0x5000, sizeof(gdtr));
        CALLBACK(setgdt, 0x5000, sizeof(gdtr));

	CALLBACK(exec, ehdr->e_entry);

	panic("exec returned");
}
Exemple #15
0
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.
	 *
	 * Native layout:
	 *           fp->f_addr + fp->f_size
	 * +---------+----------------+------------+
	 * |         |                |            |
	 * | Kernel  |    Modules     |  Metadata  |
	 * |         |                |            |
	 * +---------+----------------+------------+
	 * fp->f_addr                 modulep      kernend
	 *
	 * Xen layout:
	 *
	 * Initial:
	 *                      fp->f_addr + fp->f_size
	 * +---------+----------+----------------+------------+
	 * |         |          |                |            |
	 * | Kernel  | Reserved |    Modules     |  Metadata  |
	 * |         |          |                |  dry run   |
	 * +---------+----------+----------------+------------+
	 * fp->f_addr
	 *
	 * After metadata polacement (ie: final):
	 *                                  fp->f_addr + fp->f_size
	 * +-----------+---------+----------+----------------+
	 * |           |         |          |                |
	 * |  Kernel   |  Free   | Metadata |    Modules     |
	 * |           |         |          |                |
	 * +-----------+---------+----------+----------------+
	 * fp->f_addr            modulep                     kernend
	 * \__________/          \__________________________/
	 *  Multiboot module 0    Multiboot module 1
	 */

	fp = file_findfile(NULL, "elf kernel");
	if (fp == NULL) {
		printf("No FreeBSD kernel provided, aborting\n");
		error = EINVAL;
		goto error;
	}

	if (fp->f_metadata != NULL) {
		printf("FreeBSD kernel already contains metadata, 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;
	}

	/* Clean the metadata added to the kernel in the bi_load64 dry run */
	file_removemetadata(fp);

	/*
	 * 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);
}
Exemple #16
0
/*
 * There is an ELF kernel and one or more ELF modules loaded.
 * We wish to start executing the kernel image, so make such
 * preparations as are required, and do so.
 */
static int
elf64_exec(struct preloaded_file *fp)
{
	struct file_metadata	*md;
	Elf_Ehdr 		*ehdr;
	vm_offset_t		modulep, kernend, trampcode, trampstack;
	int			err, i;
	ACPI_TABLE_RSDP		*rsdp;
	char			buf[24];
	int			revision;

	rsdp = efi_get_table(&acpi20_guid);
	if (rsdp == NULL) {
		rsdp = efi_get_table(&acpi_guid);
	}
	if (rsdp != NULL) {
		sprintf(buf, "0x%016llx", (unsigned long long)rsdp);
		setenv("hint.acpi.0.rsdp", buf, 1);
		revision = rsdp->Revision;
		if (revision == 0)
			revision = 1;
		sprintf(buf, "%d", revision);
		setenv("hint.acpi.0.revision", buf, 1);
		strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId));
		buf[sizeof(rsdp->OemId)] = '\0';
		setenv("hint.acpi.0.oem", buf, 1);
		sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress);
		setenv("hint.acpi.0.rsdt", buf, 1);
		if (revision >= 2) {
			/* XXX extended checksum? */
			sprintf(buf, "0x%016llx",
			    (unsigned long long)rsdp->XsdtPhysicalAddress);
			setenv("hint.acpi.0.xsdt", buf, 1);
			sprintf(buf, "%d", rsdp->Length);
			setenv("hint.acpi.0.xsdt_length", buf, 1);
		}
	}

	if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return(EFTYPE);
	ehdr = (Elf_Ehdr *)&(md->md_data);

	trampcode = (vm_offset_t)0x0000000040000000;
	err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1,
	    (EFI_PHYSICAL_ADDRESS *)&trampcode);
	bzero((void *)trampcode, EFI_PAGE_SIZE);
	trampstack = trampcode + EFI_PAGE_SIZE - 8;
	bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size);
	trampoline = (void *)trampcode;

	PT4 = (p4_entry_t *)0x0000000040000000;
	err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3,
	    (EFI_PHYSICAL_ADDRESS *)&PT4);
	bzero(PT4, 3 * EFI_PAGE_SIZE);

	PT3 = &PT4[512];
	PT2 = &PT3[512];

	/*
	 * This is kinda brutal, but every single 1GB VM memory segment points
	 * to the same first 1GB of physical memory.  But it is more than
	 * adequate.
	 */
	for (i = 0; i < 512; i++) {
		/* Each slot of the L4 pages points to the same L3 page. */
		PT4[i] = (p4_entry_t)PT3;
		PT4[i] |= PG_V | PG_RW | PG_U;

		/* Each slot of the L3 pages points to the same L2 page. */
		PT3[i] = (p3_entry_t)PT2;
		PT3[i] |= PG_V | PG_RW | PG_U;

		/* The L2 page slots are mapped with 2MB pages for 1GB. */
		PT2[i] = i * (2 * 1024 * 1024);
		PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
	}

	printf("Start @ 0x%lx ...\n", ehdr->e_entry);

	err = bi_load(fp->f_args, &modulep, &kernend);
	if (err != 0)
		return(err);

	dev_cleanup();

	trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4,
	    ehdr->e_entry);

	panic("exec returned");
}