diff options
Diffstat (limited to 'usr.sbin/vmd')
-rw-r--r-- | usr.sbin/vmd/loadfile.h | 7 | ||||
-rw-r--r-- | usr.sbin/vmd/loadfile_elf.c | 175 | ||||
-rw-r--r-- | usr.sbin/vmd/parse.y | 10 | ||||
-rw-r--r-- | usr.sbin/vmd/virtio.c | 43 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.h | 6 | ||||
-rw-r--r-- | usr.sbin/vmd/vmm.c | 97 |
6 files changed, 217 insertions, 121 deletions
diff --git a/usr.sbin/vmd/loadfile.h b/usr.sbin/vmd/loadfile.h index 92155921b95..4b473425550 100644 --- a/usr.sbin/vmd/loadfile.h +++ b/usr.sbin/vmd/loadfile.h @@ -1,5 +1,5 @@ /* $NetBSD: loadfile.h,v 1.1 1999/04/28 09:08:50 christos Exp $ */ -/* $OpenBSD: loadfile.h,v 1.2 2015/12/17 09:29:28 mlarkin Exp $ */ +/* $OpenBSD: loadfile.h,v 1.3 2016/03/13 13:11:47 stefan Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -63,6 +63,9 @@ #define COUNT_RANDOM 0x4000 #define COUNT_ALL 0x7f00 -int loadelf_main(int, int, int, struct vcpu_init_state *); +#define LOWMEM_KB 636 + +int loadelf_main(int, struct vm_create_params *, + struct vcpu_init_state *); #include <machine/loadfile_machdep.h> diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c index 069677d3059..2c51e199c03 100644 --- a/usr.sbin/vmd/loadfile_elf.c +++ b/usr.sbin/vmd/loadfile_elf.c @@ -1,5 +1,5 @@ /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ -/* $OpenBSD: loadfile_elf.c,v 1.10 2016/03/04 15:34:14 stefan Exp $ */ +/* $OpenBSD: loadfile_elf.c,v 1.11 2016/03/13 13:11:47 stefan Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -108,8 +108,6 @@ #define GDT_PAGE 0x10000 #define STACK_PAGE 0xF000 -#define LOWMEM_KB 636 - union { Elf32_Ehdr elf32; Elf64_Ehdr elf64; @@ -119,12 +117,13 @@ static void setsegment(struct mem_segment_descriptor *, uint32_t, size_t, int, int, int, int); static int elf32_exec(int, Elf32_Ehdr *, u_long *, int); static int elf64_exec(int, Elf64_Ehdr *, u_long *, int); -static void push_bootargs(int); -static size_t push_stack(int, uint32_t); +static size_t create_bios_memmap(struct vm_create_params *, bios_memmap_t *); +static uint32_t push_bootargs(bios_memmap_t *, size_t); +static size_t push_stack(uint32_t, uint32_t); static void push_gdt(void); -static size_t mread(int, uint32_t, size_t); -static void marc4random_buf(uint32_t, int); -static void mbzero(uint32_t, int); +static size_t mread(int, paddr_t, size_t); +static void marc4random_buf(paddr_t, int); +static void mbzero(paddr_t, int); static void mbcopy(char *, char *, int); extern char *__progname; @@ -198,15 +197,12 @@ push_gdt(void) /* * loadelf_main * - * Loads an ELF kernel to it's defined load address in the guest VM whose - * ID is provided in 'vm_id_in'. The kernel is loaded to its defined start - * point as set in the ELF header. + * Loads an ELF kernel to it's defined load address in the guest VM. + * The kernel is loaded to its defined start point as set in the ELF header. * * Parameters: * fd: file descriptor of a kernel file to load - * vm_id_in: ID of the VM to load the kernel into - * mem_sz: memory size in MB assigned to the guest (passed through to - * push_bootargs) + * vcp: the VM create parameters, holding the exact memory map * (out) vis: register state to set on init for this kernel * * Return values: @@ -214,13 +210,13 @@ push_gdt(void) * various error codes returned from read(2) or loadelf functions */ int -loadelf_main(int fd, int vm_id_in, int mem_sz, struct vcpu_init_state *vis) +loadelf_main(int fd, struct vm_create_params *vcp, struct vcpu_init_state *vis) { int r; - size_t stacksize; + uint32_t bootargsz; + size_t n, stacksize; u_long marks[MARK_MAX]; - - vm_id = vm_id_in; + bios_memmap_t memmap[VMM_MAX_MEM_RANGES + 1]; if ((r = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) return 1; @@ -237,9 +233,10 @@ loadelf_main(int fd, int vm_id_in, int mem_sz, struct vcpu_init_state *vis) if (r) return (r); - push_bootargs(mem_sz); push_gdt(); - stacksize = push_stack(mem_sz, marks[MARK_END]); + n = create_bios_memmap(vcp, memmap); + bootargsz = push_bootargs(memmap, n); + stacksize = push_stack(bootargsz, marks[MARK_END]); vis->vis_rip = (uint64_t)marks[MARK_ENTRY]; vis->vis_rsp = (uint64_t)(STACK_PAGE + PAGE_SIZE) - stacksize; @@ -249,6 +246,58 @@ loadelf_main(int fd, int vm_id_in, int mem_sz, struct vcpu_init_state *vis) } /* + * create_bios_memmap + * + * Construct a memory map as returned by the BIOS INT 0x15, e820 routine. + * + * Parameters: + * vcp: the VM create parameters, containing the memory map passed to vmm(4) + * memmap (out): the BIOS memory map + * + * Return values: + * Number of bios_memmap_t entries, including the terminating nul-entry. + */ +static size_t +create_bios_memmap(struct vm_create_params *vcp, bios_memmap_t *memmap) +{ + size_t i, n = 0, sz; + paddr_t gpa; + struct vm_mem_range *vmr; + + for (i = 0; i < vcp->vcp_nmemranges; i++) { + vmr = &vcp->vcp_memranges[i]; + gpa = vmr->vmr_gpa; + sz = vmr->vmr_size; + + /* + * Make sure that we do not mark the ROM/video RAM area in the + * low memory as physcal memory available to the kernel. + */ + if (gpa < 0x100000 && gpa + sz > LOWMEM_KB * 1024) { + if (gpa >= LOWMEM_KB * 1024) + sz = 0; + else + sz = LOWMEM_KB * 1024 - gpa; + } + + if (sz != 0) { + memmap[n].addr = gpa; + memmap[n].size = sz; + memmap[n].type = 0x1; /* Type 1 : Normal memory */ + n++; + } + } + + /* Null mem map entry to denote the end of the ranges */ + memmap[n].addr = 0x0; + memmap[n].size = 0x0; + memmap[n].type = 0x0; + n++; + + return (n); +} + +/* * push_bootargs * * Creates the boot arguments page in the guest address space. @@ -257,40 +306,25 @@ loadelf_main(int fd, int vm_id_in, int mem_sz, struct vcpu_init_state *vis) * into the guest phys RAM space at address BOOTARGS_PAGE. * * Parameters: - * mem_sz: guest memory size in MB + * memmap: the BIOS memory map + * n: number of entries in memmap * * Return values: - * nothing + * The size of the bootargs */ -static void -push_bootargs(int mem_sz) +static uint32_t +push_bootargs(bios_memmap_t *memmap, size_t n) { - size_t sz; - bios_memmap_t memmap[3]; + uint32_t memmap_sz, consdev_sz, i; bios_consdev_t consdev; uint32_t ba[1024]; - /* First memory region: 0 - LOWMEM_KB (DOS low mem) */ - memmap[0].addr = 0x0; - memmap[0].size = LOWMEM_KB * 1024; - memmap[0].type = 0x1; /* Type 1 : Normal memory */ - - /* Second memory region: 1MB - n, reserve top 1MB */ - memmap[1].addr = 0x100000; - memmap[1].size = (mem_sz - 1) * 1024 * 1024; - memmap[1].type = 0x1; /* Type 1 : Normal memory */ - - /* Null mem map entry to denote the end of the ranges */ - memmap[2].addr = 0x0; - memmap[2].size = 0x0; - memmap[2].type = 0x0; - - sz = 3 * sizeof(int) + 3 * sizeof(bios_memmap_t); + memmap_sz = 3 * sizeof(int) + n * sizeof(bios_memmap_t); ba[0] = 0x0; /* memory map */ - ba[1] = sz; - ba[2] = sz; /* next */ - memcpy(&ba[3], &memmap, 3 * sizeof(bios_memmap_t)); - sz = sz / sizeof(int); + ba[1] = memmap_sz; + ba[2] = memmap_sz; /* next */ + memcpy(&ba[3], memmap, n * sizeof(bios_memmap_t)); + i = memmap_sz / sizeof(int); /* Serial console device, COM1 @ 0x3f8 */ consdev.consdev = makedev(8, 0); /* com1 @ 0x3f8 */ @@ -298,12 +332,15 @@ push_bootargs(int mem_sz) consdev.consaddr = 0x3f8; consdev.consfreq = 0; - ba[sz] = 0x5; /* consdev */ - ba[sz + 1] = (int)sizeof(bios_consdev_t) + 3 * sizeof(int); - ba[sz + 2] = (int)sizeof(bios_consdev_t) + 3 * sizeof(int); - memcpy(&ba[sz + 3], &consdev, sizeof(bios_consdev_t)); + consdev_sz = 3 * sizeof(int) + sizeof(bios_consdev_t); + ba[i] = 0x5; /* consdev */ + ba[i + 1] = consdev_sz; + ba[i + 2] = consdev_sz; + memcpy(&ba[i + 3], &consdev, sizeof(bios_consdev_t)); write_mem(BOOTARGS_PAGE, ba, PAGE_SIZE, 1); + + return (memmap_sz + consdev_sz); } /* @@ -319,20 +356,20 @@ push_bootargs(int mem_sz) * Stack Layout: (TOS == Top Of Stack) * TOS location of boot arguments page * TOS - 0x4 size of the content in the boot arguments page - * TOS - 0x8 size of low memory in KB - * TOS - 0xc size of high memory in KB + * TOS - 0x8 size of low memory (biosbasemem: kernel uses BIOS map only if 0) + * TOS - 0xc size of high memory (biosextmem, not used by kernel at all) * TOS - 0x10 kernel 'end' symbol value * TOS - 0x14 version of bootarg API * * Parameters: - * mem_sz: size of guest VM memory, in MB + * bootargsz: size of boot arguments * end: kernel 'end' symbol value * * Return values: * size of the stack */ static size_t -push_stack(int mem_sz, uint32_t end) +push_stack(uint32_t bootargsz, uint32_t end) { uint32_t stack[1024]; uint16_t loc; @@ -341,11 +378,9 @@ push_stack(int mem_sz, uint32_t end) loc = 1024; stack[--loc] = BOOTARGS_PAGE; - stack[--loc] = 3 * sizeof(bios_memmap_t) + - sizeof(bios_consdev_t) + - 6 * sizeof(int); - stack[--loc] = LOWMEM_KB; - stack[--loc] = mem_sz * 1024 - LOWMEM_KB; + stack[--loc] = bootargsz; + stack[--loc] = 0; /* biosbasemem */ + stack[--loc] = 0; /* biosextmem */ stack[--loc] = end; stack[--loc] = 0x0e; stack[--loc] = MAKEBOOTDEV(0x4, 0, 0, 0, 0); /* bootdev: sd0a */ @@ -360,8 +395,7 @@ push_stack(int mem_sz, uint32_t end) * mread * * Reads 'sz' bytes from the file whose descriptor is provided in 'fd' - * into the guest address space at paddr 'addr'. Note that the guest - * paddr is limited to 32 bit (4GB). + * into the guest address space at paddr 'addr'. * * Parameters: * fd: file descriptor of the kernel image file to read from. @@ -372,7 +406,7 @@ push_stack(int mem_sz, uint32_t end) * returns 'sz' if successful, or 0 otherwise. */ static size_t -mread(int fd, uint32_t addr, size_t sz) +mread(int fd, paddr_t addr, size_t sz) { int ct; size_t i, rd, osz; @@ -433,7 +467,7 @@ mread(int fd, uint32_t addr, size_t sz) * marc4random_buf * * load 'sz' bytes of random data into the guest address space at paddr - * 'addr'. Note that the guest paddr is limited to 32 bit (4GB). + * 'addr'. * * Parameters: * addr: guest paddr_t to load random bytes into @@ -443,7 +477,7 @@ mread(int fd, uint32_t addr, size_t sz) * nothing */ static void -marc4random_buf(uint32_t addr, int sz) +marc4random_buf(paddr_t addr, int sz) { int i, ct; char buf[PAGE_SIZE]; @@ -483,7 +517,7 @@ marc4random_buf(uint32_t addr, int sz) * mbzero * * load 'sz' bytes of zeros into the guest address space at paddr - * 'addr'. Note that the guest paddr is limited to 32 bit (4GB) + * 'addr'. * * Parameters: * addr: guest paddr_t to zero @@ -493,7 +527,7 @@ marc4random_buf(uint32_t addr, int sz) * nothing */ static void -mbzero(uint32_t addr, int sz) +mbzero(paddr_t addr, int sz) { int i, ct; char buf[PAGE_SIZE]; @@ -528,7 +562,6 @@ mbzero(uint32_t addr, int sz) * mbcopy * * copies 'sz' bytes from guest paddr 'src' to guest paddr 'dst'. - * Both 'src' and 'dst' are limited to 32 bit (4GB) * * Parameters: * src: source guest paddr_t to copy from @@ -632,7 +665,7 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) free(phdr); return 1; } - if (mread(fd, (uint32_t)(phdr[i].p_paddr - + if (mread(fd, (phdr[i].p_paddr - 0xffffffff80000000ULL), phdr[i].p_filesz) != phdr[i].p_filesz) { free(phdr); @@ -654,7 +687,7 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) /* Zero out BSS. */ if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) { - mbzero((uint32_t)(phdr[i].p_paddr - + mbzero((phdr[i].p_paddr - 0xffffffff80000000 + phdr[i].p_filesz), phdr[i].p_memsz - phdr[i].p_filesz); } @@ -725,7 +758,7 @@ elf64_exec(int fd, Elf64_Ehdr *elf, u_long *marks, int flags) free(shp); return 1; } - if (mread(fd, (uint32_t)maxp, + if (mread(fd, maxp, shp[i].sh_size) != shp[i].sh_size) { free(shstr); free(shp); @@ -946,7 +979,7 @@ elf32_exec(int fd, Elf32_Ehdr *elf, u_long *marks, int flags) free(shp); return 1; } - if (mread(fd, (uint32_t)maxp, + if (mread(fd, maxp, shp[i].sh_size) != shp[i].sh_size) { free(shstr); free(shp); diff --git a/usr.sbin/vmd/parse.y b/usr.sbin/vmd/parse.y index c69eaf167ac..23cea73bb32 100644 --- a/usr.sbin/vmd/parse.y +++ b/usr.sbin/vmd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.5 2015/12/07 13:30:06 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.6 2016/03/13 13:11:47 stefan Exp $ */ /* * Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org> @@ -218,7 +218,7 @@ vm_opts : disable { } | MEMORY NUMBER { ssize_t res; - if (vcp.vcp_memory_size != 0) { + if (vcp.vcp_memranges[0].vmr_size != 0) { yyerror("memory specified more than once"); YYERROR; } @@ -226,11 +226,11 @@ vm_opts : disable { yyerror("failed to parse size: %lld", $2); YYERROR; } - vcp.vcp_memory_size = (size_t)res; + vcp.vcp_memranges[0].vmr_size = (size_t)res; } | MEMORY STRING { ssize_t res; - if (vcp.vcp_memory_size != 0) { + if (vcp.vcp_memranges[0].vmr_size != 0) { yyerror("argument specified more than once"); free($2); YYERROR; @@ -240,7 +240,7 @@ vm_opts : disable { free($2); YYERROR; } - vcp.vcp_memory_size = (size_t)res; + vcp.vcp_memranges[0].vmr_size = (size_t)res; } ; diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c index 56de8244f96..43a19777980 100644 --- a/usr.sbin/vmd/virtio.c +++ b/usr.sbin/vmd/virtio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.c,v 1.9 2016/02/07 10:17:19 jsg Exp $ */ +/* $OpenBSD: virtio.c,v 1.10 2016/03/13 13:11:47 stefan Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -172,7 +172,7 @@ viornd_notifyq(void) memset(buf, 0, vr_sz); - if (read_mem((uint32_t)q_gpa, buf, vr_sz, 0)) { + if (read_mem(q_gpa, buf, vr_sz, 0)) { free(buf); return (0); } @@ -188,7 +188,7 @@ viornd_notifyq(void) if (rnd_data != NULL) { arc4random_buf(rnd_data, desc[avail->ring[avail->idx]].len); - if (write_mem((uint32_t)(desc[avail->ring[avail->idx]].addr), + if (write_mem(desc[avail->ring[avail->idx]].addr, rnd_data, desc[avail->ring[avail->idx]].len, 0)) { log_warnx("viornd: can't write random data @ " "0x%llx", @@ -384,8 +384,8 @@ vioblk_notifyq(struct vioblk_dev *dev) memset(vr, 0, vr_sz); - if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { - log_warnx("error reading gpa 0x%x", (uint32_t)q_gpa); + if (read_mem(q_gpa, vr, vr_sz, 0)) { + log_warnx("error reading gpa 0x%llx", q_gpa); free(vr); return (0); } @@ -417,7 +417,7 @@ vioblk_notifyq(struct vioblk_dev *dev) } /* Read command from descriptor ring */ - if (read_mem((uint32_t)cmd_desc->addr, &cmd, cmd_desc->len, 0)) { + if (read_mem(cmd_desc->addr, &cmd, cmd_desc->len, 0)) { log_warnx("vioblk: command read_mem error @ 0x%llx", cmd_desc->addr); free(vr); @@ -453,7 +453,7 @@ vioblk_notifyq(struct vioblk_dev *dev) return (0); } - if (write_mem((uint32_t)secdata_desc->addr, secdata, + if (write_mem(secdata_desc->addr, secdata, secdata_desc->len, 0)) { log_warnx("can't write sector " "data to gpa @ 0x%llx", @@ -476,8 +476,7 @@ vioblk_notifyq(struct vioblk_dev *dev) ds_desc = secdata_desc; ds = VIRTIO_BLK_S_OK; - if (write_mem((uint32_t)ds_desc->addr, - &ds, ds_desc->len, 0)) { + if (write_mem(ds_desc->addr, &ds, ds_desc->len, 0)) { log_warnx("can't write device status data @ " "0x%llx", ds_desc->addr); dump_descriptor_chain(desc, cmd_desc_idx); @@ -520,7 +519,7 @@ vioblk_notifyq(struct vioblk_dev *dev) secbias = 0; do { - if (read_mem((uint32_t)secdata_desc->addr, secdata, + if (read_mem(secdata_desc->addr, secdata, secdata_desc->len, 0)) { log_warnx("wr vioblk: can't read " "sector data @ 0x%llx", @@ -552,8 +551,7 @@ vioblk_notifyq(struct vioblk_dev *dev) ds_desc = secdata_desc; ds = VIRTIO_BLK_S_OK; - if (write_mem((uint32_t)ds_desc->addr, - &ds, ds_desc->len, 0)) { + if (write_mem(ds_desc->addr, &ds, ds_desc->len, 0)) { log_warnx("wr vioblk: can't write device status " "data @ 0x%llx", ds_desc->addr); dump_descriptor_chain(desc, cmd_desc_idx); @@ -578,8 +576,7 @@ vioblk_notifyq(struct vioblk_dev *dev) ds_desc = &desc[ds_desc_idx]; ds = VIRTIO_BLK_S_OK; - if (write_mem((uint32_t)ds_desc->addr, - &ds, ds_desc->len, 0)) { + if (write_mem(ds_desc->addr, &ds, ds_desc->len, 0)) { log_warnx("fl vioblk: can't write device status " "data @ 0x%llx", ds_desc->addr); dump_descriptor_chain(desc, cmd_desc_idx); @@ -807,8 +804,8 @@ vionet_enq_rx(struct vionet_dev *dev, char *pkt, ssize_t sz, int *spc) memset(vr, 0, vr_sz); - if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { - log_warnx("rx enq: error reading gpa 0x%x", (uint32_t)q_gpa); + if (read_mem(q_gpa, vr, vr_sz, 0)) { + log_warnx("rx enq: error reading gpa 0x%llx", q_gpa); free(vr); return (0); } @@ -843,7 +840,7 @@ vionet_enq_rx(struct vionet_dev *dev, char *pkt, ssize_t sz, int *spc) } /* Write packet to descriptor ring */ - if (write_mem((uint32_t)pkt_desc->addr, pkt, sz, 0)) { + if (write_mem(pkt_desc->addr, pkt, sz, 0)) { log_warnx("vionet: rx enq packet write_mem error @ " "0x%llx", pkt_desc->addr); free(vr); @@ -933,8 +930,8 @@ vionet_notify_rx(struct vionet_dev *dev) memset(vr, 0, vr_sz); - if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { - log_warnx("error reading gpa 0x%x", (uint32_t)q_gpa); + if (read_mem(q_gpa, vr, vr_sz, 0)) { + log_warnx("error reading gpa 0x%llx", q_gpa); free(vr); return; } @@ -994,8 +991,8 @@ vionet_notifyq(struct vionet_dev *dev) memset(vr, 0, vr_sz); - if (read_mem((uint32_t)q_gpa, vr, vr_sz, 0)) { - log_warnx("error reading gpa 0x%x", (uint32_t)q_gpa); + if (read_mem(q_gpa, vr, vr_sz, 0)) { + log_warnx("error reading gpa 0x%llx", q_gpa); goto out; } @@ -1055,7 +1052,7 @@ vionet_notifyq(struct vionet_dev *dev) } /* Read packet from descriptor ring */ - if (read_mem((uint32_t)pkt_desc->addr, pkt + ofs, + if (read_mem(pkt_desc->addr, pkt + ofs, pkt_desc->len, 0)) { log_warnx("vionet: packet read_mem error " "@ 0x%llx", pkt_desc->addr); @@ -1075,7 +1072,7 @@ vionet_notifyq(struct vionet_dev *dev) } /* Read packet from descriptor ring */ - if (read_mem((uint32_t)pkt_desc->addr, pkt + ofs, + if (read_mem(pkt_desc->addr, pkt + ofs, pkt_desc->len, 0)) { log_warnx("vionet: packet read_mem error @ " "0x%llx", pkt_desc->addr); diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index 97a2ebdbba1..2d52ac87a44 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.18 2016/01/16 08:55:40 stefan Exp $ */ +/* $OpenBSD: vmd.h,v 1.19 2016/03/13 13:11:47 stefan Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -114,8 +114,8 @@ char *get_string(uint8_t *, size_t); /* vmm.c */ pid_t vmm(struct privsep *, struct privsep_proc *); -int write_mem(uint32_t dst, void *buf, uint32_t, int); -int read_mem(uint32_t dst, void *buf, uint32_t, int); +int write_mem(paddr_t, void *buf, size_t, int); +int read_mem(paddr_t, void *buf, size_t, int); int opentap(void); /* control.c */ diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c index 1d0ef1613ee..3f1a3653e09 100644 --- a/usr.sbin/vmd/vmm.c +++ b/usr.sbin/vmd/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.22 2016/03/13 02:37:29 mlarkin Exp $ */ +/* $OpenBSD: vmm.c,v 1.23 2016/03/13 13:11:47 stefan Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -63,7 +63,6 @@ /* * Emulated 8250 UART - * */ #define COM1_DATA 0x3f8 #define COM1_IER 0x3f9 @@ -121,6 +120,7 @@ int run_vm(int *, int *, struct vm_create_params *, struct vcpu_init_state *); void *vcpu_run_loop(void *); int vcpu_exit(struct vm_run_params *); int vcpu_reset(uint32_t, uint32_t, struct vcpu_init_state *); +void create_memory_map(struct vm_create_params *); int vmm_create_vm(struct vm_create_params *); void init_emulated_hw(struct vm_create_params *, int *, int *); void vcpu_exit_inout(struct vm_run_params *); @@ -139,7 +139,8 @@ void vcpu_process_com_scr(union vm_exit *); int vmm_dispatch_parent(int, struct privsep_proc *, struct imsg *); void vmm_run(struct privsep *, struct privsep_proc *, void *); -int con_fd, vm_id; +int con_fd; +struct vmd_vm *current_vm; extern struct vmd *env; @@ -470,7 +471,9 @@ start_vm(struct imsg *imsg, uint32_t *id) setproctitle(vcp->vcp_name); log_procinit(vcp->vcp_name); + create_memory_map(vcp); ret = vmm_create_vm(vcp); + current_vm = vm; /* send back the kernel-generated vm id (0 on error) */ close(fds[0]); @@ -501,8 +504,7 @@ start_vm(struct imsg *imsg, uint32_t *id) memcpy(&vis, &vcpu_init_flat32, sizeof(struct vcpu_init_state)); /* Load kernel image */ - ret = loadelf_main(vm->vm_kernel, vcp->vcp_id, - vcp->vcp_memory_size, &vis); + ret = loadelf_main(vm->vm_kernel, vcp, &vis); if (ret) { errno = ret; fatal("failed to load kernel - exiting"); @@ -642,6 +644,65 @@ start_client_vmd(void) } /* + * create_memory_map + * + * Sets up the guest physical memory ranges that the VM can access. + * + * Return values: + * nothing + */ +void +create_memory_map(struct vm_create_params *vcp) +{ + size_t mem_mb; + uint64_t mem_bytes, len; + + mem_mb = vcp->vcp_memranges[0].vmr_size; + vcp->vcp_nmemranges = 0; + if (mem_mb < 1 || mem_mb > VMM_MAX_VM_MEM_SIZE) + return; + + mem_bytes = (uint64_t)mem_mb * 1024 * 1024; + + /* First memory region: 0 - LOWMEM_KB (DOS low mem) */ + vcp->vcp_memranges[0].vmr_gpa = 0x0; + vcp->vcp_memranges[0].vmr_size = LOWMEM_KB * 1024; + mem_bytes -= LOWMEM_KB * 1024; + + /* + * Second memory region: LOWMEM_KB - 1MB. + * XXX Normally ROMs or parts of video RAM are mapped here. + * We have to add this region, because some systems + * unconditionally write to 0xb8000 (video RAM), and + * we need to make sure that vmm(4) permits accesses + * to it. So allocate guest memory for it. + */ + len = 0x100000 - LOWMEM_KB * 1024; + vcp->vcp_memranges[1].vmr_gpa = LOWMEM_KB * 1024; + vcp->vcp_memranges[1].vmr_size = len; + mem_bytes -= len; + + /* Make sure that we do not place physical memory into MMIO ranges. */ + if (mem_bytes > VMM_PCI_MMIO_BAR_BASE - 0x100000) + len = VMM_PCI_MMIO_BAR_BASE - 0x100000; + else + len = mem_bytes; + + /* Third memory region: 1MB - (1MB + len) */ + vcp->vcp_memranges[2].vmr_gpa = 0x100000; + vcp->vcp_memranges[2].vmr_size = len; + mem_bytes -= len; + + if (mem_bytes > 0) { + /* Fourth memory region for the remaining memory (if any) */ + vcp->vcp_memranges[3].vmr_gpa = VMM_PCI_MMIO_BAR_END + 1; + vcp->vcp_memranges[3].vmr_size = mem_bytes; + vcp->vcp_nmemranges = 4; + } else + vcp->vcp_nmemranges = 3; +} + +/* * vmm_create_vm * * Requests vmm(4) to create a new VM using the supplied creation @@ -663,7 +724,8 @@ vmm_create_vm(struct vm_create_params *vcp) if (vcp->vcp_ncpus > VMM_MAX_VCPUS_PER_VM) return (EINVAL); - if (vcp->vcp_memory_size > VMM_MAX_VM_MEM_SIZE) + if (vcp->vcp_nmemranges == 0 || + vcp->vcp_nmemranges > VMM_MAX_MEM_RANGES) return (EINVAL); if (vcp->vcp_ndisks > VMM_MAX_DISKS_PER_VM) @@ -1492,10 +1554,11 @@ vcpu_exit(struct vm_run_params *vrp) * Note - this function only handles GPAs < 4GB. */ int -write_mem(uint32_t dst, void *buf, uint32_t len, int do_mask) +write_mem(paddr_t dst, void *buf, size_t len, int do_mask) { char *p = buf; - uint32_t gpa, n, left; + size_t n, left; + paddr_t gpa; struct vm_writepage_params vwp; /* @@ -1516,11 +1579,11 @@ write_mem(uint32_t dst, void *buf, uint32_t len, int do_mask) vwp.vwp_paddr = (paddr_t)gpa; vwp.vwp_data = p; - vwp.vwp_vm_id = vm_id; + vwp.vwp_vm_id = current_vm->vm_params.vcp_id; vwp.vwp_len = n; if (ioctl(env->vmd_fd, VMM_IOC_WRITEPAGE, &vwp) < 0) { - log_warn("writepage ioctl failed @ 0x%x: " - "dst = 0x%x, len = 0x%x", gpa, dst, len); + log_warn("writepage ioctl failed @ 0x%lx: " + "dst = 0x%lx, len = 0x%zx", gpa, dst, len); return (errno); } @@ -1550,13 +1613,13 @@ write_mem(uint32_t dst, void *buf, uint32_t len, int do_mask) * Note - this function only handles GPAs < 4GB. */ int -read_mem(uint32_t src, void *buf, uint32_t len, int do_mask) +read_mem(paddr_t src, void *buf, size_t len, int do_mask) { char *p = buf; - uint32_t gpa, n, left; + size_t n, left; + paddr_t gpa; struct vm_readpage_params vrp; - /* * Mask kernel load addresses to avoid uint32_t -> uint64_t cast * errors @@ -1575,11 +1638,11 @@ read_mem(uint32_t src, void *buf, uint32_t len, int do_mask) vrp.vrp_paddr = (paddr_t)gpa; vrp.vrp_data = p; - vrp.vrp_vm_id = vm_id; + vrp.vrp_vm_id = current_vm->vm_params.vcp_id; vrp.vrp_len = n; if (ioctl(env->vmd_fd, VMM_IOC_READPAGE, &vrp) < 0) { - log_warn("readpage ioctl failed @ 0x%x: " - "src = 0x%x, len = 0x%x", gpa, src, len); + log_warn("readpage ioctl failed @ 0x%lx: " + "src = 0x%lx, len = 0x%zx", gpa, src, len); return (errno); } |