From owner-svn-src-user@FreeBSD.ORG Sun Aug 4 01:22:27 2013 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 6E01BB11; Sun, 4 Aug 2013 01:22:27 +0000 (UTC) (envelope-from syuu@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 4A80B2539; Sun, 4 Aug 2013 01:22:27 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r741MQul047076; Sun, 4 Aug 2013 01:22:26 GMT (envelope-from syuu@svn.freebsd.org) Received: (from syuu@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r741MQSY047075; Sun, 4 Aug 2013 01:22:26 GMT (envelope-from syuu@svn.freebsd.org) Message-Id: <201308040122.r741MQSY047075@svn.freebsd.org> From: Takuya ASADA Date: Sun, 4 Aug 2013 01:22:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r253922 - user/syuu/bhyve_standalone_guest/usr.sbin/bhyveload X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 04 Aug 2013 01:22:27 -0000 Author: syuu Date: Sun Aug 4 01:22:26 2013 New Revision: 253922 URL: http://svnweb.freebsd.org/changeset/base/253922 Log: support standalone binary loading Modified: user/syuu/bhyve_standalone_guest/usr.sbin/bhyveload/bhyveload.c Modified: user/syuu/bhyve_standalone_guest/usr.sbin/bhyveload/bhyveload.c ============================================================================== --- user/syuu/bhyve_standalone_guest/usr.sbin/bhyveload/bhyveload.c Sat Aug 3 22:16:24 2013 (r253921) +++ user/syuu/bhyve_standalone_guest/usr.sbin/bhyveload/bhyveload.c Sun Aug 4 01:22:26 2013 (r253922) @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -75,6 +76,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include @@ -556,13 +559,152 @@ usage(void) exit(1); } -int -main(int argc, char** argv) +#define MSR_EFER 0xc0000080 +#define CR4_PAE 0x00000020 +#define CR4_PSE 0x00000010 +#define CR0_PG 0x80000000 +#define CR0_PE 0x00000001 /* Protected mode Enable */ +#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ + +#define PG_V 0x001 +#define PG_RW 0x002 +#define PG_U 0x004 +#define PG_PS 0x080 + +typedef u_int64_t p4_entry_t; +typedef u_int64_t p3_entry_t; +typedef u_int64_t p2_entry_t; + +#define GUEST_NULL_SEL 0 +#define GUEST_CODE_SEL 1 +#define GUEST_DATA_SEL 2 +#define GUEST_GDTR_LIMIT (3 * 8 - 1) + +static void +setup_stand_gdt(uint64_t *gdtr) +{ + gdtr[GUEST_NULL_SEL] = 0; + gdtr[GUEST_CODE_SEL] = 0x0020980000000000; + gdtr[GUEST_DATA_SEL] = 0x0000900000000000; +} + +static int +stand_load(char *image, uint64_t addr) +{ + int i; + int fd; + struct stat sb; + char *buf; + uint32_t stack[1024]; + p4_entry_t PT4[512]; + p3_entry_t PT3[512]; + p2_entry_t PT2[512]; + uint64_t gdtr[3]; + + if ((fd = open(image, O_RDONLY)) < 0) { + perror("open"); + return (1); + } + if (fstat(fd, &sb)) { + perror("fstat"); + return (1); + } + buf = alloca(sb.st_size); + if (read(fd, buf, sb.st_size) != sb.st_size) { + perror("read"); + return (1); + } + if (close(fd) < 0) { + perror("close"); + return (1); + } + if (cb_copyin(NULL, buf, addr, sb.st_size)) { + perror("copyin"); + return (1); + } + + 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", addr); +#endif + + cb_copyin(NULL, stack, 0x1000, sizeof(stack)); + cb_copyin(NULL, PT4, 0x2000, sizeof(PT4)); + cb_copyin(NULL, PT3, 0x3000, sizeof(PT3)); + cb_copyin(NULL, PT2, 0x4000, sizeof(PT2)); + cb_setreg(NULL, 4, 0x1000); + + cb_setmsr(NULL, MSR_EFER, EFER_LMA | EFER_LME); + cb_setcr(NULL, 4, CR4_PAE | CR4_VMXE); + cb_setcr(NULL, 3, 0x2000); + cb_setcr(NULL, 0, CR0_PG | CR0_PE | CR0_NE); + + setup_stand_gdt(gdtr); + cb_copyin(NULL, gdtr, 0x5000, sizeof(gdtr)); + cb_setgdt(NULL, 0x5000, sizeof(gdtr)); + + cb_exec(NULL, addr); + return (0); +} + +static int +freebsd_load(void) { void *h; void (*func)(struct loader_callbacks *, void *, int, int); + + h = dlopen("/boot/userboot.so", RTLD_LOCAL); + if (!h) { + printf("%s\n", dlerror()); + return (1); + } + func = dlsym(h, "loader_main"); + if (!func) { + printf("%s\n", dlerror()); + return (1); + } + + func(&cb, NULL, USERBOOT_VERSION_3, disk_fd >= 0); + return (0); +} + +int +main(int argc, char** argv) +{ uint64_t mem_size; int opt, error; + uint64_t stand_addr; + char *stand_image; char *disk_image; progname = argv[0]; @@ -570,7 +712,7 @@ main(int argc, char** argv) mem_size = 256 * MB; disk_image = NULL; - while ((opt = getopt(argc, argv, "d:h:m:")) != -1) { + while ((opt = getopt(argc, argv, "d:h:m:S:I:")) != -1) { switch (opt) { case 'd': disk_image = optarg; @@ -583,6 +725,25 @@ main(int argc, char** argv) case 'm': mem_size = strtoul(optarg, NULL, 0) * MB; break; + + case 'S': { + char *addr_str; + + stand_image = strtok(optarg, ":"); + if (stand_image == NULL) { + usage(); + break; + } + + addr_str = strtok(NULL, ":"); + if (addr_str == NULL) { + usage(); + break; + } + stand_addr = strtoll(addr_str, NULL, 0); + + break; + } case '?': usage(); @@ -621,19 +782,16 @@ main(int argc, char** argv) term.c_lflag &= ~(ICANON|ECHO); term.c_iflag &= ~ICRNL; tcsetattr(0, TCSAFLUSH, &term); - h = dlopen("/boot/userboot.so", RTLD_LOCAL); - if (!h) { - printf("%s\n", dlerror()); - return (1); - } - func = dlsym(h, "loader_main"); - if (!func) { - printf("%s\n", dlerror()); - return (1); - } if (disk_image) { disk_fd = open(disk_image, O_RDONLY); } - func(&cb, NULL, USERBOOT_VERSION_3, disk_fd >= 0); + + if (stand_image) { + if (stand_load(stand_image, stand_addr)) + exit(1); + }else{ + if (freebsd_load()) + exit(1); + } }