CVS commit: src/lib/libnvmm
Module Name:src Committed By: reinoud Date: Tue Apr 6 08:40:17 UTC 2021 Modified Files: src/lib/libnvmm: libnvmm.c nvmm.h Log Message: Implement nvmm_vcpu::stop, a race-free exit from nvmm_vcpu_run() without signals. This introduces a new kernel and userland NVMM version indicating this support. Patch by Kamil Rytarowski and committed on his request. This is the missing libnvmm part I forgot to include in the origional commit. To generate a diff of this commit: cvs rdiff -u -r1.19 -r1.20 src/lib/libnvmm/libnvmm.c cvs rdiff -u -r1.18 -r1.19 src/lib/libnvmm/nvmm.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.c diff -u src/lib/libnvmm/libnvmm.c:1.19 src/lib/libnvmm/libnvmm.c:1.20 --- src/lib/libnvmm/libnvmm.c:1.19 Sat Sep 5 07:22:25 2020 +++ src/lib/libnvmm/libnvmm.c Tue Apr 6 08:40:17 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.19 2020/09/05 07:22:25 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.20 2021/04/06 08:40:17 reinoud Exp $ */ /* * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net @@ -310,6 +310,7 @@ nvmm_vcpu_create(struct nvmm_machine *ma vcpu->cpuid = cpuid; vcpu->state = >state; vcpu->event = >event; + vcpu->stop = >stop; vcpu->exit = malloc(sizeof(*vcpu->exit)); return 0; @@ -561,3 +562,12 @@ nvmm_ctl(int op, void *data, size_t size return 0; } + +int +nvmm_vcpu_stop(struct nvmm_vcpu *vcpu) +{ + + *vcpu->stop = 1; + + return 0; +} Index: src/lib/libnvmm/nvmm.h diff -u src/lib/libnvmm/nvmm.h:1.18 src/lib/libnvmm/nvmm.h:1.19 --- src/lib/libnvmm/nvmm.h:1.18 Sat Sep 5 07:22:25 2020 +++ src/lib/libnvmm/nvmm.h Tue Apr 6 08:40:17 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: nvmm.h,v 1.18 2020/09/05 07:22:25 maxv Exp $ */ +/* $NetBSD: nvmm.h,v 1.19 2021/04/06 08:40:17 reinoud Exp $ */ /* * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net @@ -37,7 +37,12 @@ #include #include -#define NVMM_USER_VERSION 1 +#define NVMM_USER_VERSION 2 + +/* + * Version 1 - Initial release in NetBSD 9.0. + * Version 2 - Added nvmm_vcpu::stop. + */ struct nvmm_io; struct nvmm_mem; @@ -59,6 +64,7 @@ struct nvmm_vcpu { struct nvmm_vcpu_state *state; struct nvmm_vcpu_event *event; struct nvmm_vcpu_exit *exit; + volatile int *stop; }; struct nvmm_io { @@ -123,4 +129,6 @@ int nvmm_ctl(int, void *, size_t); int nvmm_vcpu_dump(struct nvmm_machine *, struct nvmm_vcpu *); +int nvmm_vcpu_stop(struct nvmm_vcpu *); + #endif /* _LIBNVMM_H_ */
CVS commit: src/lib/libnvmm
Module Name:src Committed By: reinoud Date: Sat Oct 31 15:44:01 UTC 2020 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Revert (REPE) CMPS support per request of Maxime, it is incorrect. To generate a diff of this commit: cvs rdiff -u -r1.41 -r1.42 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.41 src/lib/libnvmm/libnvmm_x86.c:1.42 --- src/lib/libnvmm/libnvmm_x86.c:1.41 Fri Oct 30 21:06:13 2020 +++ src/lib/libnvmm/libnvmm_x86.c Sat Oct 31 15:44:01 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.41 2020/10/30 21:06:13 reinoud Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.42 2020/10/31 15:44:01 reinoud Exp $ */ /* * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net @@ -1051,7 +1051,6 @@ struct x86_opcode { bool movs:1; bool stos:1; bool lods:1; - bool cmps:1; bool szoverride:1; bool group1:1; bool group3:1; @@ -1464,26 +1463,6 @@ static const struct x86_opcode primary_o }, /* - * CMPS - */ - [0xA6] = { - /* Yb, Xb */ - .valid = true, - .cmps = true, - .szoverride = false, - .defsize = OPSIZE_BYTE, - .emul = _emul_cmp - }, - [0xA7] = { - /* Yv, Xv */ - .valid = true, - .cmps = true, - .szoverride = true, - .defsize = -1, - .emul = _emul_cmp - }, - - /* * STOS */ [0xAA] = { @@ -1892,35 +1871,6 @@ node_movs(struct x86_decode_fsm *fsm, st } /* - * Special node, for CMPS. Fake two displacements of zero on the source and - * destination registers. - * XXX coded as clone of movs as its similar in register usage - * XXX might be merged with node_movs() - */ -static int -node_cmps(struct x86_decode_fsm *fsm, struct x86_instr *instr) -{ - size_t adrsize; - - adrsize = instr->address_size; - - /* DS:RSI */ - instr->src.type = STORE_REG; - instr->src.u.reg = _map__special[1][2][adrsize-1]; - instr->src.disp.type = DISP_0; - - /* ES:RDI, force ES */ - instr->dst.type = STORE_REG; - instr->dst.u.reg = _map__special[1][3][adrsize-1]; - instr->dst.disp.type = DISP_0; - instr->dst.hardseg = NVMM_X64_SEG_ES; - - fsm_advance(fsm, 0, NULL); - - return 0; -} - -/* * Special node, for STOS and LODS. Fake a displacement of zero on the * destination register. */ @@ -2520,8 +2470,6 @@ node_primary_opcode(struct x86_decode_fs fsm_advance(fsm, 1, node_stlo); } else if (opcode->movs) { fsm_advance(fsm, 1, node_movs); - } else if (opcode->cmps) { - fsm_advance(fsm, 1, node_cmps); } else { return -1; } @@ -2698,16 +2646,8 @@ x86_decode(uint8_t *inst_bytes, size_t i while (fsm.fn != NULL) { ret = (*fsm.fn)(, instr); - if (ret == -1) { - printf("\nNVMM: %s missing support for instruction " \ - "with max length %ld : [ ", __func__, - inst_len); - for (uint i = 0; i < inst_len; i++) -printf("%02x ", inst_bytes[i]); - printf("], please report to NetBSD!\n\n"); - fflush(stdout); + if (ret == -1) return -1; - } } instr->len = fsm.buf - inst_bytes;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: reinoud Date: Fri Oct 30 21:06:13 UTC 2020 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Implement missing (REPE) CMPS instruction support in NVMMs x86_decode(). In apparently rare cases the (REPE) CMPS instruction can trigger an memory assist. NVMM wouldn't recognize the instruction and thus couldn't assist and Qemu would abort. To generate a diff of this commit: cvs rdiff -u -r1.40 -r1.41 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.40 src/lib/libnvmm/libnvmm_x86.c:1.41 --- src/lib/libnvmm/libnvmm_x86.c:1.40 Sat Sep 5 07:22:25 2020 +++ src/lib/libnvmm/libnvmm_x86.c Fri Oct 30 21:06:13 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.40 2020/09/05 07:22:25 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.41 2020/10/30 21:06:13 reinoud Exp $ */ /* * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net @@ -1051,6 +1051,7 @@ struct x86_opcode { bool movs:1; bool stos:1; bool lods:1; + bool cmps:1; bool szoverride:1; bool group1:1; bool group3:1; @@ -1463,6 +1464,26 @@ static const struct x86_opcode primary_o }, /* + * CMPS + */ + [0xA6] = { + /* Yb, Xb */ + .valid = true, + .cmps = true, + .szoverride = false, + .defsize = OPSIZE_BYTE, + .emul = _emul_cmp + }, + [0xA7] = { + /* Yv, Xv */ + .valid = true, + .cmps = true, + .szoverride = true, + .defsize = -1, + .emul = _emul_cmp + }, + + /* * STOS */ [0xAA] = { @@ -1871,6 +1892,35 @@ node_movs(struct x86_decode_fsm *fsm, st } /* + * Special node, for CMPS. Fake two displacements of zero on the source and + * destination registers. + * XXX coded as clone of movs as its similar in register usage + * XXX might be merged with node_movs() + */ +static int +node_cmps(struct x86_decode_fsm *fsm, struct x86_instr *instr) +{ + size_t adrsize; + + adrsize = instr->address_size; + + /* DS:RSI */ + instr->src.type = STORE_REG; + instr->src.u.reg = _map__special[1][2][adrsize-1]; + instr->src.disp.type = DISP_0; + + /* ES:RDI, force ES */ + instr->dst.type = STORE_REG; + instr->dst.u.reg = _map__special[1][3][adrsize-1]; + instr->dst.disp.type = DISP_0; + instr->dst.hardseg = NVMM_X64_SEG_ES; + + fsm_advance(fsm, 0, NULL); + + return 0; +} + +/* * Special node, for STOS and LODS. Fake a displacement of zero on the * destination register. */ @@ -2470,6 +2520,8 @@ node_primary_opcode(struct x86_decode_fs fsm_advance(fsm, 1, node_stlo); } else if (opcode->movs) { fsm_advance(fsm, 1, node_movs); + } else if (opcode->cmps) { + fsm_advance(fsm, 1, node_cmps); } else { return -1; } @@ -2646,8 +2698,16 @@ x86_decode(uint8_t *inst_bytes, size_t i while (fsm.fn != NULL) { ret = (*fsm.fn)(, instr); - if (ret == -1) + if (ret == -1) { + printf("\nNVMM: %s missing support for instruction " \ + "with max length %ld : [ ", __func__, + inst_len); + for (uint i = 0; i < inst_len; i++) +printf("%02x ", inst_bytes[i]); + printf("], please report to NetBSD!\n\n"); + fflush(stdout); return -1; + } } instr->len = fsm.buf - inst_bytes;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Mon Apr 29 19:03:17 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: sync with reality To generate a diff of this commit: cvs rdiff -u -r1.15 -r1.16 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.15 src/lib/libnvmm/libnvmm.3:1.16 --- src/lib/libnvmm/libnvmm.3:1.15 Mon Apr 29 18:54:25 2019 +++ src/lib/libnvmm/libnvmm.3 Mon Apr 29 19:03:17 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.15 2019/04/29 18:54:25 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.16 2019/04/29 19:03:17 maxv Exp $ .\" .\" Copyright (c) 2018, 2019 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 7, 2019 +.Dd April 29, 2019 .Dt LIBNVMM 3 .Os .Sh NAME @@ -284,12 +284,9 @@ struct nvmm_capability { uint64_t max_machines; uint64_t max_vcpus; uint64_t max_ram; - union { - struct { - ... - } x86; - uint64_t rsvd[8]; - } u; + struct { + ... + } arch; }; .Ed .Pp @@ -384,26 +381,20 @@ The .Cd nvmm_exit structure is used to handle VM exits: .Bd -literal -enum nvmm_exit_reason { - NVMM_EXIT_NONE = 0x, - - /* General. */ - NVMM_EXIT_MEMORY = 0x0001, - NVMM_EXIT_IO = 0x0002, - NVMM_EXIT_MSR = 0x0003, - NVMM_EXIT_INT_READY = 0x0004, - NVMM_EXIT_NMI_READY = 0x0005, - NVMM_EXIT_HALTED = 0x0006, - NVMM_EXIT_SHUTDOWN = 0x0007, - - /* Instructions (x86). */ +/* Exit Reasons */ +#define NVMM_EXIT_NONE 0xULL +#define NVMM_EXIT_MEMORY 0x0001ULL +#define NVMM_EXIT_IO 0x0002ULL +#define NVMM_EXIT_MSR 0x0003ULL +#define NVMM_EXIT_INT_READY 0x0004ULL +#define NVMM_EXIT_NMI_READY 0x0005ULL +#define NVMM_EXIT_HALTED 0x0006ULL +#define NVMM_EXIT_SHUTDOWN 0x0007ULL ... - - NVMM_EXIT_INVALID = 0x -}; +#define NVMM_EXIT_INVALID 0xULL struct nvmm_exit { - enum nvmm_exit_reason reason; + uint64_t reason; union { ... } u;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Mon Apr 29 17:27:57 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.c Log Message: Remove useless calls to nvmm_init(). To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/lib/libnvmm/libnvmm.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.c diff -u src/lib/libnvmm/libnvmm.c:1.10 src/lib/libnvmm/libnvmm.c:1.11 --- src/lib/libnvmm/libnvmm.c:1.10 Sun Apr 28 14:22:13 2019 +++ src/lib/libnvmm/libnvmm.c Mon Apr 29 17:27:57 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.10 2019/04/28 14:22:13 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.11 2019/04/29 17:27:57 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -237,10 +237,6 @@ nvmm_machine_destroy(struct nvmm_machine struct nvmm_ioc_machine_destroy args; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; ret = ioctl(nvmm_fd, NVMM_IOC_MACHINE_DESTROY, ); @@ -259,10 +255,6 @@ nvmm_machine_configure(struct nvmm_machi struct nvmm_ioc_machine_configure args; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; args.op = op; args.conf = conf; @@ -281,10 +273,6 @@ nvmm_vcpu_create(struct nvmm_machine *ma struct nvmm_comm_page *comm; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; args.cpuid = cpuid; @@ -309,10 +297,6 @@ nvmm_vcpu_destroy(struct nvmm_machine *m struct nvmm_comm_page *comm; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; args.cpuid = cpuid; @@ -332,10 +316,6 @@ nvmm_vcpu_setstate(struct nvmm_machine * { struct nvmm_comm_page *comm; - if (nvmm_init() == -1) { - return -1; - } - if (__predict_false(cpuid >= mach->npages)) { return -1; } @@ -356,10 +336,6 @@ nvmm_vcpu_getstate(struct nvmm_machine * struct nvmm_comm_page *comm; int ret; - if (nvmm_init() == -1) { - return -1; - } - if (__predict_false(cpuid >= mach->npages)) { return -1; } @@ -389,10 +365,6 @@ nvmm_vcpu_inject(struct nvmm_machine *ma struct nvmm_ioc_vcpu_inject args; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; args.cpuid = cpuid; memcpy(, event, sizeof(args.event)); @@ -411,10 +383,6 @@ nvmm_vcpu_run(struct nvmm_machine *mach, struct nvmm_ioc_vcpu_run args; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; args.cpuid = cpuid; memset(, 0, sizeof(args.exit)); @@ -435,10 +403,6 @@ nvmm_gpa_map(struct nvmm_machine *mach, struct nvmm_ioc_gpa_map args; int ret; - if (nvmm_init() == -1) { - return -1; - } - ret = __area_add(mach, hva, gpa, size, prot); if (ret == -1) return -1; @@ -465,10 +429,6 @@ nvmm_gpa_unmap(struct nvmm_machine *mach struct nvmm_ioc_gpa_unmap args; int ret; - if (nvmm_init() == -1) { - return -1; - } - ret = __area_delete(mach, hva, gpa, size); if (ret == -1) return -1; @@ -492,10 +452,6 @@ nvmm_hva_map(struct nvmm_machine *mach, struct nvmm_ioc_hva_map args; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; args.hva = hva; args.size = size; @@ -513,10 +469,6 @@ nvmm_hva_unmap(struct nvmm_machine *mach struct nvmm_ioc_hva_unmap args; int ret; - if (nvmm_init() == -1) { - return -1; - } - args.machid = mach->machid; args.hva = hva; args.size = size;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sun Apr 7 14:13:03 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: Sync, and fix grammar. To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.14 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.13 src/lib/libnvmm/libnvmm.3:1.14 --- src/lib/libnvmm/libnvmm.3:1.13 Thu Apr 4 17:33:47 2019 +++ src/lib/libnvmm/libnvmm.3 Sun Apr 7 14:13:03 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.13 2019/04/04 17:33:47 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.14 2019/04/07 14:13:03 maxv Exp $ .\" .\" Copyright (c) 2018, 2019 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 4, 2019 +.Dd April 7, 2019 .Dt LIBNVMM 3 .Os .Sh NAME @@ -361,7 +361,7 @@ struct nvmm_x64_state { uint64_t crs[NVMM_X64_NCR]; uint64_t drs[NVMM_X64_NDR]; uint64_t msrs[NVMM_X64_NMSR]; - uint64_t misc[NVMM_X64_NMISC]; + struct nvmm_x64_state_intr intr; struct fxsave fpu; }; .Ed @@ -466,7 +466,7 @@ event, if: the event is a hardware interrupt, and the VCPU runs with interrupts disabled, or .It -the event is a non-maskable interrupt (NMI), and the VCPU is already in a +the event is a non-maskable interrupt (NMI), and the VCPU is already in an in-NMI context. .El .Pp
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Thu Apr 4 17:33:47 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.3 libnvmm.c libnvmm_x86.c nvmm.h Log Message: Check the GPA permissions too in the Assists, because it is possible that the guest traps on a page the virtualizer marked as read-only (even if it appears as read-write in the HVA). To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/lib/libnvmm/libnvmm.3 cvs rdiff -u -r1.7 -r1.8 src/lib/libnvmm/libnvmm.c cvs rdiff -u -r1.27 -r1.28 src/lib/libnvmm/libnvmm_x86.c cvs rdiff -u -r1.6 -r1.7 src/lib/libnvmm/nvmm.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.12 src/lib/libnvmm/libnvmm.3:1.13 --- src/lib/libnvmm/libnvmm.3:1.12 Thu Mar 21 20:21:40 2019 +++ src/lib/libnvmm/libnvmm.3 Thu Apr 4 17:33:47 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.12 2019/03/21 20:21:40 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.13 2019/04/04 17:33:47 maxv Exp $ .\" .\" Copyright (c) 2018, 2019 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd March 19, 2019 +.Dd April 4, 2019 .Dt LIBNVMM 3 .Os .Sh NAME @@ -77,7 +77,7 @@ "gvaddr_t gva" "gpaddr_t *gpa" "nvmm_prot_t *prot" .Ft int .Fn nvmm_gpa_to_hva "struct nvmm_machine *mach" "gpaddr_t gpa" \ -"uintptr_t *hva" +"uintptr_t *hva" "nvmm_prot_t *prot" .Ft void .Fn nvmm_callbacks_register "const struct nvmm_callbacks *cbs" .Ft int @@ -241,6 +241,8 @@ the guest physical address indicated in .Fa gpa into a host virtual address returned in .Fa hva . +The associated page premissions are returned in +.Fa prot . .Fa gpa must be page-aligned. .Pp Index: src/lib/libnvmm/libnvmm.c diff -u src/lib/libnvmm/libnvmm.c:1.7 src/lib/libnvmm/libnvmm.c:1.8 --- src/lib/libnvmm/libnvmm.c:1.7 Thu Mar 21 20:21:40 2019 +++ src/lib/libnvmm/libnvmm.c Thu Apr 4 17:33:47 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.7 2019/03/21 20:21:40 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.8 2019/04/04 17:33:47 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -50,6 +50,7 @@ typedef struct __area { gpaddr_t gpa; uintptr_t hva; size_t size; + nvmm_prot_t prot; } area_t; typedef LIST_HEAD(, __area) area_list_t; @@ -83,11 +84,21 @@ __area_isvalid(struct nvmm_machine *mach } static int -__area_add(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) +__area_add(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size, +int prot) { area_list_t *areas = mach->areas; + nvmm_prot_t nprot; area_t *area; + nprot = 0; + if (prot & PROT_READ) + nprot |= NVMM_PROT_READ; + if (prot & PROT_WRITE) + nprot |= NVMM_PROT_WRITE; + if (prot & PROT_EXEC) + nprot |= NVMM_PROT_EXEC; + if (!__area_isvalid(mach, hva, gpa, size)) { errno = EINVAL; return -1; @@ -99,6 +110,7 @@ __area_add(struct nvmm_machine *mach, ui area->gpa = gpa; area->hva = hva; area->size = size; + area->prot = nprot; LIST_INSERT_HEAD(areas, area, list); @@ -383,7 +395,7 @@ nvmm_gpa_map(struct nvmm_machine *mach, return -1; } - ret = __area_add(mach, hva, gpa, size); + ret = __area_add(mach, hva, gpa, size, prot); if (ret == -1) return -1; @@ -477,7 +489,8 @@ nvmm_hva_unmap(struct nvmm_machine *mach */ int -nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva) +nvmm_gpa_to_hva(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t *hva, +nvmm_prot_t *prot) { area_list_t *areas = mach->areas; area_t *ent; @@ -485,6 +498,7 @@ nvmm_gpa_to_hva(struct nvmm_machine *mac LIST_FOREACH(ent, areas, list) { if (gpa >= ent->gpa && gpa < ent->gpa + ent->size) { *hva = ent->hva + (gpa - ent->gpa); + *prot = ent->prot; return 0; } } Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.27 src/lib/libnvmm/libnvmm_x86.c:1.28 --- src/lib/libnvmm/libnvmm_x86.c:1.27 Thu Mar 7 15:47:34 2019 +++ src/lib/libnvmm/libnvmm_x86.c Thu Apr 4 17:33:47 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.27 2019/03/07 15:47:34 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.28 2019/04/04 17:33:47 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -123,13 +123,14 @@ x86_gva_to_gpa_32bit(struct nvmm_machine gpaddr_t L2gpa, L1gpa; uintptr_t L2hva, L1hva; pte_32bit_t *pdir, pte; + nvmm_prot_t pageprot; /* We begin with an RWXU access. */ *prot = NVMM_PROT_ALL; /* Parse L2. */ L2gpa = (cr3 & CR3_FRAME_32BIT); - if (nvmm_gpa_to_hva(mach, L2gpa, ) == -1) + if (nvmm_gpa_to_hva(mach, L2gpa, , ) == -1) return -1; pdir = (pte_32bit_t *)L2hva; pte = pdir[pte32_l2idx(gva)]; @@ -149,7 +150,7 @@ x86_gva_to_gpa_32bit(struct nvmm_machine /* Parse L1. */ L1gpa = (pte &
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Thu Mar 7 15:47:34 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Micro optimizations: - Compress x86_rexpref, x86_regmodrm, x86_opcode and x86_instr. - Cache-align the register, opcode and group tables. - Modify the opcode tables to have 256 entries, and avoid a lookup. To generate a diff of this commit: cvs rdiff -u -r1.26 -r1.27 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.26 src/lib/libnvmm/libnvmm_x86.c:1.27 --- src/lib/libnvmm/libnvmm_x86.c:1.26 Tue Feb 26 12:23:12 2019 +++ src/lib/libnvmm/libnvmm_x86.c Thu Mar 7 15:47:34 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.26 2019/02/26 12:23:12 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.27 2019/03/07 15:47:34 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -46,6 +46,7 @@ #include "nvmm.h" #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define __cacheline_aligned __attribute__((__aligned__(64))) #include @@ -904,15 +905,15 @@ struct x86_legpref { bool adr_ovr:1; bool rep:1; bool repn:1; - int seg; + int8_t seg; }; struct x86_rexpref { - bool present; - bool w; - bool r; - bool x; - bool b; + bool b:1; + bool x:1; + bool r:1; + bool w:1; + bool present:1; }; struct x86_reg { @@ -962,10 +963,9 @@ enum REGMODRM__Rm { }; struct x86_regmodrm { - bool present; - enum REGMODRM__Mod mod; - enum REGMODRM__Reg reg; - enum REGMODRM__Rm rm; + uint8_t mod:2; + uint8_t reg:3; + uint8_t rm:3; }; struct x86_immediate { @@ -999,22 +999,20 @@ struct x86_store { }; struct x86_instr { - size_t len; + uint8_t len; struct x86_legpref legpref; struct x86_rexpref rexpref; - size_t operand_size; - size_t address_size; - uint64_t zeroextend_mask; - struct x86_regmodrm regmodrm; + uint8_t operand_size; + uint8_t address_size; + uint64_t zeroextend_mask; const struct x86_opcode *opcode; + const struct x86_emul *emul; struct x86_store src; struct x86_store dst; struct x86_store *strm; - - const struct x86_emul *emul; }; struct x86_decode_fsm { @@ -1030,22 +1028,21 @@ struct x86_decode_fsm { }; struct x86_opcode { - uint8_t byte; - bool regmodrm; - bool regtorm; - bool dmo; - bool todmo; - bool movs; - bool stos; - bool lods; - bool szoverride; - int defsize; - int allsize; - bool group1; - bool group3; - bool group11; - bool immediate; - int flags; + bool valid:1; + bool regmodrm:1; + bool regtorm:1; + bool dmo:1; + bool todmo:1; + bool movs:1; + bool stos:1; + bool lods:1; + bool szoverride:1; + bool group1:1; + bool group3:1; + bool group11:1; + bool immediate:1; + uint8_t defsize; + uint8_t flags; const struct x86_emul *emul; }; @@ -1062,59 +1059,56 @@ struct x86_group_entry { #define FLAG_immz 0x02 #define FLAG_ze 0x04 -static const struct x86_group_entry group1[8] = { +static const struct x86_group_entry group1[8] __cacheline_aligned = { [1] = { .emul = _emul_or }, [4] = { .emul = _emul_and }, [6] = { .emul = _emul_xor }, [7] = { .emul = _emul_cmp } }; -static const struct x86_group_entry group3[8] = { +static const struct x86_group_entry group3[8] __cacheline_aligned = { [0] = { .emul = _emul_test }, [1] = { .emul = _emul_test } }; -static const struct x86_group_entry group11[8] = { +static const struct x86_group_entry group11[8] __cacheline_aligned = { [0] = { .emul = _emul_mov } }; -static const struct x86_opcode primary_opcode_table[] = { +static const struct x86_opcode primary_opcode_table[256] __cacheline_aligned = { /* * Group1 */ - { + [0x80] = { /* Eb, Ib */ - .byte = 0x80, + .valid = true, .regmodrm = true, .regtorm = true, .szoverride = false, .defsize = OPSIZE_BYTE, - .allsize = -1, .group1 = true, .immediate = true, .emul = NULL /* group1 */ }, - { + [0x81] = { /* Ev, Iz */ - .byte = 0x81, + .valid = true, .regmodrm = true, .regtorm = true, .szoverride = true, .defsize = -1, - .allsize = OPSIZE_WORD|OPSIZE_DOUB|OPSIZE_QUAD, .group1 = true, .immediate = true, .flags = FLAG_immz, .emul = NULL /* group1 */ }, - { + [0x83] = { /* Ev, Ib */ - .byte = 0x83, + .valid = true, .regmodrm = true, .regtorm = true, .szoverride = true, .defsize = -1, - .allsize = OPSIZE_WORD|OPSIZE_DOUB|OPSIZE_QUAD, .group1 = true, .immediate = true, .flags = FLAG_imm8, @@ -1124,26 +1118,24 @@ static const struct x86_opcode primary_o /* * Group3 */ - { + [0xF6] = { /* Eb, Ib */ - .byte = 0xF6, + .valid = true, .regmodrm = true, .regtorm = true, .szoverride = false, .defsize = OPSIZE_BYTE, - .allsize = -1, .group3 = true, .immediate = true, .emul = NULL /* group3 */ }, - { + [0xF7] = { /* Ev, Iz */ - .byte = 0xF7, + .valid = true, .regmodrm = true,
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Tue Feb 26 10:18:39 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Set hardseg to -1 rather than 0, because 0 can be a valid segment. To generate a diff of this commit: cvs rdiff -u -r1.24 -r1.25 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.24 src/lib/libnvmm/libnvmm_x86.c:1.25 --- src/lib/libnvmm/libnvmm_x86.c:1.24 Sun Feb 17 20:25:46 2019 +++ src/lib/libnvmm/libnvmm_x86.c Tue Feb 26 10:18:39 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.24 2019/02/17 20:25:46 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.25 2019/02/26 10:18:39 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -2556,6 +2556,8 @@ x86_decode(uint8_t *inst_bytes, size_t i memset(instr, 0, sizeof(*instr)); instr->legpref.seg = -1; + instr->src.hardseg = -1; + instr->dst.hardseg = -1; fsm.is64bit = is_64bit(state); fsm.is32bit = is_32bit(state); @@ -2926,7 +2928,7 @@ store_to_gva(struct nvmm_x64_state *stat gva += store->disp.data; } - if (store->hardseg != 0) { + if (store->hardseg != -1) { seg = store->hardseg; } else { if (__predict_false(instr->legpref.seg != -1)) {
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sun Feb 17 20:25:46 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Fix handling of SIB instructions. We were jumping to the SIB node _before_ fetching the displacement, so the node would always think there was no displacement. This didn't alter the final GPA we would be touching - because it is fetched from the kernel directly and not from the computation -, but it altered the instruction length, and on some guests (like Fedora 64bit), the VCPU would resume execution at the wrong RIP and crash. Now these guests work. To generate a diff of this commit: cvs rdiff -u -r1.23 -r1.24 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.23 src/lib/libnvmm/libnvmm_x86.c:1.24 --- src/lib/libnvmm/libnvmm_x86.c:1.23 Fri Feb 15 16:42:27 2019 +++ src/lib/libnvmm/libnvmm_x86.c Sun Feb 17 20:25:46 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.23 2019/02/15 16:42:27 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.24 2019/02/17 20:25:46 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -2233,15 +2233,15 @@ node_regmodrm(struct x86_decode_fsm *fsm strg->u.reg = reg; } + /* The displacement applies to RM. */ + strm->disp.type = get_disp_type(instr); + if (has_sib(instr)) { /* Overwrites RM */ fsm_advance(fsm, 1, node_sib); return 0; } - /* The displacement applies to RM. */ - strm->disp.type = get_disp_type(instr); - if (is_rip_relative(fsm, instr)) { /* Overwrites RM */ strm->type = STORE_REG;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Fri Feb 15 16:42:27 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Remove the PSE check in the 32bit-PAE MMU. Setting CR4.PAE automatically enables PSE regardless of whether CR4.PSE is set or not, so we should just ignore it. With this in place I can boot Windows 8.1 on NVMM. To generate a diff of this commit: cvs rdiff -u -r1.22 -r1.23 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.22 src/lib/libnvmm/libnvmm_x86.c:1.23 --- src/lib/libnvmm/libnvmm_x86.c:1.22 Thu Feb 14 14:30:20 2019 +++ src/lib/libnvmm/libnvmm_x86.c Fri Feb 15 16:42:27 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.22 2019/02/14 14:30:20 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.23 2019/02/15 16:42:27 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -188,7 +188,7 @@ typedef uint64_t pte_32bit_pae_t; static int x86_gva_to_gpa_32bit_pae(struct nvmm_machine *mach, uint64_t cr3, -gvaddr_t gva, gpaddr_t *gpa, bool has_pse, nvmm_prot_t *prot) +gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot) { gpaddr_t L3gpa, L2gpa, L1gpa; uintptr_t L3hva, L2hva, L1hva; @@ -224,8 +224,6 @@ x86_gva_to_gpa_32bit_pae(struct nvmm_mac *prot &= ~NVMM_PROT_WRITE; if (pte & PG_NX) *prot &= ~NVMM_PROT_EXEC; - if ((pte & PG_PS) && !has_pse) - return -1; if (pte & PG_PS) { *gpa = (pte & PTE32_PAE_L2_FRAME); *gpa = *gpa + (gva & PTE32_PAE_L1_MASK); @@ -408,8 +406,7 @@ x86_gva_to_gpa(struct nvmm_machine *mach ret = x86_gva_to_gpa_64bit(mach, cr3, gva, gpa, prot); } else if (is_pae && !is_lng) { /* 32bit PAE */ - ret = x86_gva_to_gpa_32bit_pae(mach, cr3, gva, gpa, has_pse, - prot); + ret = x86_gva_to_gpa_32bit_pae(mach, cr3, gva, gpa, prot); } else if (!is_pae && !is_lng) { /* 32bit */ ret = x86_gva_to_gpa_32bit(mach, cr3, gva, gpa, has_pse, prot);
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Tue Feb 12 14:50:21 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Optimize: fetch only 5 bytes instead of 15, the instruction can have only up to five prefixes. To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.21 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.20 src/lib/libnvmm/libnvmm_x86.c:1.21 --- src/lib/libnvmm/libnvmm_x86.c:1.20 Sun Feb 10 19:30:28 2019 +++ src/lib/libnvmm/libnvmm_x86.c Tue Feb 12 14:50:21 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.20 2019/02/10 19:30:28 christos Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.21 2019/02/12 14:50:21 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -2958,7 +2958,7 @@ store_to_gva(struct nvmm_x64_state *stat static int fetch_segment(struct nvmm_machine *mach, struct nvmm_x64_state *state) { - uint8_t inst_bytes[15], byte; + uint8_t inst_bytes[5], byte; size_t i, fetchsize; gvaddr_t gva; int ret, seg;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: christos Date: Sun Feb 10 19:30:28 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: is not legal. To generate a diff of this commit: cvs rdiff -u -r1.19 -r1.20 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.19 src/lib/libnvmm/libnvmm_x86.c:1.20 --- src/lib/libnvmm/libnvmm_x86.c:1.19 Thu Feb 7 05:58:45 2019 +++ src/lib/libnvmm/libnvmm_x86.c Sun Feb 10 14:30:28 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.19 2019/02/07 10:58:45 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.20 2019/02/10 19:30:28 christos Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -2584,7 +2584,7 @@ x86_decode(uint8_t *inst_bytes, size_t i #define EXEC_INSTR(sz, instr) \ static uint##sz##_t \ -exec_##instrsz(uint##sz##_t op1, uint##sz##_t op2, uint64_t *rflags)\ +exec_##instr##sz(uint##sz##_t op1, uint##sz##_t op2, uint64_t *rflags) \ { \ uint##sz##_t res; \ __asm __volatile ( \
CVS commit: src/lib/libnvmm
Module Name:src Committed By: wiz Date: Tue Feb 5 15:03:35 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: Mark up NULL with Dv. Remove empty line. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.10 src/lib/libnvmm/libnvmm.3:1.11 --- src/lib/libnvmm/libnvmm.3:1.10 Tue Feb 5 13:56:32 2019 +++ src/lib/libnvmm/libnvmm.3 Tue Feb 5 15:03:35 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.10 2019/02/05 13:56:32 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.11 2019/02/05 15:03:35 wiz Exp $ .\" .\" Copyright (c) 2018, 2019 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -377,7 +377,6 @@ During VM exits, a partial VCPU state ar see .Sx Exit Reasons below for details. - .Ss Exit Reasons The .Cd nvmm_exit @@ -499,7 +498,8 @@ or .Fn nvmm_assist_mem are invoked. VMM software that does not intend to use either of these assists can put -NULL in the callbacks. +.Dv NULL +in the callbacks. .Ss I/O Assist When a VM exit occurs with reason .Cd NVMM_EXIT_IO ,
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Tue Feb 5 13:56:32 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: Sync with reality, and improve. To generate a diff of this commit: cvs rdiff -u -r1.9 -r1.10 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.9 src/lib/libnvmm/libnvmm.3:1.10 --- src/lib/libnvmm/libnvmm.3:1.9 Mon Jan 7 22:17:02 2019 +++ src/lib/libnvmm/libnvmm.3 Tue Feb 5 13:56:32 2019 @@ -1,6 +1,6 @@ -.\" $NetBSD: libnvmm.3,v 1.9 2019/01/07 22:17:02 wiz Exp $ +.\" $NetBSD: libnvmm.3,v 1.10 2019/02/05 13:56:32 maxv Exp $ .\" -.\" Copyright (c) 2018 The NetBSD Foundation, Inc. +.\" Copyright (c) 2018, 2019 The NetBSD Foundation, Inc. .\" All rights reserved. .\" .\" This code is derived from software contributed to The NetBSD Foundation @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 7, 2019 +.Dd February 5, 2019 .Dt LIBNVMM 3 .Os .Sh NAME @@ -96,10 +96,13 @@ A virtual machine is described by an opa VMM software should not attempt to modify this structure directly, and should use the API provided by .Nm -to handle virtual machines. +to manage virtual machines. .Pp .Fn nvmm_capability gets the capabilities of NVMM. +See +.Sx NVMM Capability +below for details. .Pp .Fn nvmm_machine_create creates a virtual machine in the kernel. @@ -159,6 +162,17 @@ See .Sx VCPU State Area below for details. .Pp +.Fn nvmm_vcpu_inject +injects into the CPU identified by +.Fa cpuid +of the machine +.Fa mach +an event described by +.Fa event . +See +.Sx Event Injection +below for details. +.Pp .Fn nvmm_vcpu_run runs the CPU identified by .Fa cpuid @@ -282,17 +296,88 @@ For example, the field indicates the maximum number of virtual machines supported, while .Cd max_vcpus indicates the maximum number of VCPUs supported per virtual machine. +.Ss Guest-Host Mappings +Each virtual machine has an associated guest physical memory. +VMM software is allowed to modify this guest physical memory by mapping +it into some parts of its virtual address space. +.Pp +VMM software should follow the following steps to achieve that: +.Pp +.Bl -bullet -offset indent -compact +.It +Call +.Fn nvmm_hva_map +to create in the host's virtual address space an area of memory that can +be shared with a guest. +Typically, the +.Fa hva +parameter will be a pointer to an area that was previously mapped via +.Fn mmap . +.Fn nvmm_hva_map +will replace the content of the area, and will make it read-write (but not +executable). +.It +Make available in the guest an area of guest physical memory, by calling +.Fn nvmm_gpa_map +and passing in the +.Fa hva +parameter the value that was previously given to +.Fn nvmm_hva_map . +.Fn nvmm_gpa_map +does not replace the content of any memory, it only creates a direct link +from +.Fa gpa +into +.Fa hva . +.Fn nvmm_gpa_unmap +removes this link without modifying +.Fa hva . +.El +.Pp +The guest will then be able to use the guest physical address passed in the +.Fa gpa +parameter of +.Fn nvmm_gpa_map . +Each change the guest makes in +.Fa gpa +will be reflected in the host's +.Fa hva , +and vice versa. +.Pp +It is illegal for VMM software to use +.Fn munmap +on an area that was mapped via +.Fn nvmm_hva_map . .Ss VCPU State Area A VCPU state area is a structure that entirely defines the content of the registers of a VCPU. Only one such structure exists, for x86: .Bd -literal struct nvmm_x64_state { - ... + struct nvmm_x64_state_seg segs[NVMM_X64_NSEG]; + uint64_t gprs[NVMM_X64_NGPR]; + uint64_t crs[NVMM_X64_NCR]; + uint64_t drs[NVMM_X64_NDR]; + uint64_t msrs[NVMM_X64_NMSR]; + uint64_t misc[NVMM_X64_NMISC]; + struct fxsave fpu; }; .Ed .Pp Refer to functional examples to see precisely how to use this structure. +.Pp +A VCPU state area is divided in sub-states. +A +.Fa flags +parameter is used to set and get the VCPU state; it acts as a bitmap which +indicates which sub-states to set or get. +.Pp +During VM exits, a partial VCPU state area is provided in +.Va exitstate , +see +.Sx Exit Reasons +below for details. + .Ss Exit Reasons The .Cd nvmm_exit @@ -307,7 +392,8 @@ enum nvmm_exit_reason { NVMM_EXIT_MSR = 0x0003, NVMM_EXIT_INT_READY = 0x0004, NVMM_EXIT_NMI_READY = 0x0005, - NVMM_EXIT_SHUTDOWN = 0x0006, + NVMM_EXIT_HALTED = 0x0006, + NVMM_EXIT_SHUTDOWN = 0x0007, /* Instructions (x86). */ ... @@ -392,6 +478,28 @@ and NVMM will cause a VM exit with reaso or .Cd NVMM_EXIT_NMI_READY to indicate that VMM software can now reinject the desired event. +.Ss Assist Callbacks +In order to assist emulation of certain operations, +.Nm +requires VMM software to register, via +.Fn
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sat Jan 26 14:44:54 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Ah, fix bug: when the opcode has an immediate, we fill the src with a register storage, but then we overwrite it without zeroing out the highest bits of the resulting immediate (which may contain garbage from the union). To generate a diff of this commit: cvs rdiff -u -r1.15 -r1.16 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.15 src/lib/libnvmm/libnvmm_x86.c:1.16 --- src/lib/libnvmm/libnvmm_x86.c:1.15 Sun Jan 13 10:43:22 2019 +++ src/lib/libnvmm/libnvmm_x86.c Sat Jan 26 14:44:54 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.15 2019/01/13 10:43:22 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.16 2019/01/26 14:44:54 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -2071,12 +2071,14 @@ node_regmodrm(struct x86_decode_fsm *fsm instr->emul = group11[instr->regmodrm.reg].emul; } - reg = get_register_reg(instr, opcode); - if (reg == NULL) { - return -1; + if (!opcode->immediate) { + reg = get_register_reg(instr, opcode); + if (reg == NULL) { + return -1; + } + strg->type = STORE_REG; + strg->u.reg = reg; } - strg->type = STORE_REG; - strg->u.reg = reg; if (has_sib(instr)) { /* Overwrites RM */
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sun Jan 13 10:43:23 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Handle more corner cases, clean up a little, and add a set of instructions in Group1. To generate a diff of this commit: cvs rdiff -u -r1.14 -r1.15 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.14 src/lib/libnvmm/libnvmm_x86.c:1.15 --- src/lib/libnvmm/libnvmm_x86.c:1.14 Tue Jan 8 07:34:22 2019 +++ src/lib/libnvmm/libnvmm_x86.c Sun Jan 13 10:43:22 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.14 2019/01/08 07:34:22 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.15 2019/01/13 10:43:22 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -77,13 +77,15 @@ nvmm_vcpu_dump(struct nvmm_machine *mach printf("| -> RAX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RAX]); printf("| -> RBX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RBX]); printf("| -> RCX=%p\n", (void *)state.gprs[NVMM_X64_GPR_RCX]); + printf("| -> RFLAGS=%p\n", (void *)state.gprs[NVMM_X64_GPR_RFLAGS]); for (i = 0; i < NVMM_X64_NSEG; i++) { - printf("| -> %s: sel=0x%lx base=%p, limit=%p, P=%d, D=%d\n", + printf("| -> %s: sel=0x%lx base=%p, limit=%p, P=%d, D=%d L=%d\n", segnames[i], state.segs[i].selector, (void *)state.segs[i].base, (void *)state.segs[i].limit, - state.segs[i].attrib.p, state.segs[i].attrib.def32); + state.segs[i].attrib.p, state.segs[i].attrib.def32, + state.segs[i].attrib.lng); } printf("| -> MSR_EFER=%p\n", (void *)state.msrs[NVMM_X64_MSR_EFER]); printf("| -> CR0=%p\n", (void *)state.crs[NVMM_X64_CR_CR0]); @@ -392,7 +394,7 @@ x86_gva_to_gpa(struct nvmm_machine *mach gva &= ~PAGE_MASK; is_pae = (state->crs[NVMM_X64_CR_CR4] & CR4_PAE) != 0; - is_lng = (state->msrs[NVMM_X64_MSR_EFER] & EFER_LME) != 0; + is_lng = (state->msrs[NVMM_X64_MSR_EFER] & EFER_LMA) != 0; has_pse = (state->crs[NVMM_X64_CR_CR4] & CR4_PSE) != 0; cr3 = state->crs[NVMM_X64_CR_CR3]; @@ -437,6 +439,12 @@ nvmm_gva_to_gpa(struct nvmm_machine *mac /* -- */ static inline bool +is_long_mode(struct nvmm_x64_state *state) +{ + return (state->msrs[NVMM_X64_MSR_EFER] & EFER_LMA) != 0; +} + +static inline bool is_64bit(struct nvmm_x64_state *state) { return (state->segs[NVMM_X64_SEG_CS].attrib.lng != 0); @@ -456,14 +464,8 @@ is_16bit(struct nvmm_x64_state *state) (state->segs[NVMM_X64_SEG_CS].attrib.def32 == 0); } -static inline bool -is_long_mode(struct nvmm_x64_state *state) -{ - return (state->msrs[NVMM_X64_MSR_EFER] & EFER_LME) != 0; -} - static int -segment_apply(struct nvmm_x64_state_seg *seg, gvaddr_t *gva, size_t size) +segment_check(struct nvmm_x64_state_seg *seg, gvaddr_t gva, size_t size) { uint64_t limit; @@ -480,11 +482,10 @@ segment_apply(struct nvmm_x64_state_seg limit *= PAGE_SIZE; } - if (__predict_false(*gva + size > limit)) { + if (__predict_false(gva + size > limit)) { goto error; } - *gva += seg->base; return 0; error: @@ -492,17 +493,25 @@ error: return -1; } -static uint64_t -mask_from_adsize(size_t adsize) +static inline void +segment_apply(struct nvmm_x64_state_seg *seg, gvaddr_t *gva) { - switch (adsize) { - case 8: - return 0x; - case 4: - return 0x; + *gva += seg->base; +} + +static inline uint64_t +size_to_mask(size_t size) +{ + switch (size) { + case 1: + return 0x00FF; case 2: - default: /* impossible */ return 0x; + case 4: + return 0x; + case 8: + default: + return 0x; } } @@ -511,7 +520,7 @@ rep_get_cnt(struct nvmm_x64_state *state { uint64_t mask, cnt; - mask = mask_from_adsize(adsize); + mask = size_to_mask(adsize); cnt = state->gprs[NVMM_X64_GPR_RCX] & mask; return cnt; @@ -522,28 +531,12 @@ rep_set_cnt(struct nvmm_x64_state *state { uint64_t mask; - mask = mask_from_adsize(adsize); + /* XXX: should we zero-extend? */ + mask = size_to_mask(adsize); state->gprs[NVMM_X64_GPR_RCX] &= ~mask; state->gprs[NVMM_X64_GPR_RCX] |= cnt; } -static uint64_t -rep_dec_apply(struct nvmm_x64_state *state, size_t adsize) -{ - uint64_t mask, cnt; - - mask = mask_from_adsize(adsize); - - cnt = state->gprs[NVMM_X64_GPR_RCX] & mask; - cnt -= 1; - cnt &= mask; - - state->gprs[NVMM_X64_GPR_RCX] &= ~mask; - state->gprs[NVMM_X64_GPR_RCX] |= cnt; - - return cnt; -} - static int read_guest_memory(struct nvmm_machine *mach, struct nvmm_x64_state *state, gvaddr_t gva, uint8_t *data, size_t size) @@ -693,7 +686,7 @@ nvmm_assist_io(struct nvmm_machine *mach uint64_t cnt = 0; /* GCC */ uint8_t iobuf[8]; int iocnt = 1; - gvaddr_t gva; + gvaddr_t gva = 0; /* GCC */ int reg = 0; /* GCC */
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Tue Jan 8 07:34:22 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Handle REPN. FreeBSD has a "repn movs", which is a bit unusual, but doesn't seem illegal as far as I can tell from the AMD SDM. With that, I can boot FreeBSD on Qemu+NVMM. To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.14 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.13 src/lib/libnvmm/libnvmm_x86.c:1.14 --- src/lib/libnvmm/libnvmm_x86.c:1.13 Mon Jan 7 18:13:34 2019 +++ src/lib/libnvmm/libnvmm_x86.c Tue Jan 8 07:34:22 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.13 2019/01/07 18:13:34 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.14 2019/01/08 07:34:22 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -2902,11 +2902,6 @@ nvmm_assist_mem(struct nvmm_machine *mac return -1; } - if (__predict_false(instr.legpref.repn)) { - errno = ENODEV; - return -1; - } - if (instr.opcode->movs) { ret = assist_mem_double(mach, , ); } else { @@ -2917,10 +2912,14 @@ nvmm_assist_mem(struct nvmm_machine *mac return -1; } - if (instr.legpref.rep) { + if (instr.legpref.rep || instr.legpref.repn) { cnt = rep_dec_apply(, instr.address_size); if (cnt == 0) { state.gprs[NVMM_X64_GPR_RIP] += instr.len; + } else if (__predict_false(instr.legpref.repn)) { + if (state.gprs[NVMM_X64_GPR_RFLAGS] & PSL_Z) { +state.gprs[NVMM_X64_GPR_RIP] += instr.len; + } } } else { state.gprs[NVMM_X64_GPR_RIP] += instr.len;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: wiz Date: Mon Jan 7 22:17:02 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: Remove leading zero from date. To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.8 src/lib/libnvmm/libnvmm.3:1.9 --- src/lib/libnvmm/libnvmm.3:1.8 Mon Jan 7 16:30:25 2019 +++ src/lib/libnvmm/libnvmm.3 Mon Jan 7 22:17:02 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.8 2019/01/07 16:30:25 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.9 2019/01/07 22:17:02 wiz Exp $ .\" .\" Copyright (c) 2018 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 07, 2019 +.Dd January 7, 2019 .Dt LIBNVMM 3 .Os .Sh NAME
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Mon Jan 7 18:13:34 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Optimize the legpref node: omit BRN (we don't care and it's the same as OVR_CS), inline the loops, sort the checks from most to least likely prefix, and use a compact structure. To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.12 src/lib/libnvmm/libnvmm_x86.c:1.13 --- src/lib/libnvmm/libnvmm_x86.c:1.12 Mon Jan 7 16:30:25 2019 +++ src/lib/libnvmm/libnvmm_x86.c Mon Jan 7 18:13:34 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.12 2019/01/07 16:30:25 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.13 2019/01/07 18:13:34 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -824,26 +824,25 @@ static void x86_emul_stos(struct nvmm_me static void x86_emul_lods(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); static void x86_emul_movs(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); -enum x86_legpref { - /* Group 1 */ - LEG_LOCK = 0, - LEG_REPN, /* REPNE/REPNZ */ - LEG_REP, /* REP/REPE/REPZ */ - /* Group 2 */ - LEG_OVR_CS, - LEG_OVR_SS, - LEG_OVR_DS, - LEG_OVR_ES, - LEG_OVR_FS, - LEG_OVR_GS, - LEG_BRN_TAKEN, - LEG_BRN_NTAKEN, - /* Group 3 */ - LEG_OPR_OVR, - /* Group 4 */ - LEG_ADR_OVR, - - NLEG +/* Legacy prefixes. */ +#define LEG_LOCK 0xF0 +#define LEG_REPN 0xF2 +#define LEG_REP 0xF3 +#define LEG_OVR_CS 0x2E +#define LEG_OVR_SS 0x36 +#define LEG_OVR_DS 0x3E +#define LEG_OVR_ES 0x26 +#define LEG_OVR_FS 0x64 +#define LEG_OVR_GS 0x65 +#define LEG_OPR_OVR 0x66 +#define LEG_ADR_OVR 0x67 + +struct x86_legpref { + bool opr_ovr:1; + bool adr_ovr:1; + bool rep:1; + bool repn:1; + int seg; }; struct x86_rexpref { @@ -940,7 +939,7 @@ struct x86_store { struct x86_instr { size_t len; - bool legpref[NLEG]; + struct x86_legpref legpref; struct x86_rexpref rexpref; size_t operand_size; size_t address_size; @@ -2133,13 +2132,13 @@ get_operand_size(struct x86_decode_fsm * opsize = 8; } else { if (!fsm->is16bit) { - if (instr->legpref[LEG_OPR_OVR]) { + if (instr->legpref.opr_ovr) { opsize = 2; } else { opsize = 4; } } else { /* 16bit */ - if (instr->legpref[LEG_OPR_OVR]) { + if (instr->legpref.opr_ovr) { opsize = 4; } else { opsize = 2; @@ -2159,21 +2158,21 @@ static size_t get_address_size(struct x86_decode_fsm *fsm, struct x86_instr *instr) { if (fsm->is64bit) { - if (__predict_false(instr->legpref[LEG_ADR_OVR])) { + if (__predict_false(instr->legpref.adr_ovr)) { return 4; } return 8; } if (fsm->is32bit) { - if (__predict_false(instr->legpref[LEG_ADR_OVR])) { + if (__predict_false(instr->legpref.adr_ovr)) { return 2; } return 4; } /* 16bit. */ - if (__predict_false(instr->legpref[LEG_ADR_OVR])) { + if (__predict_false(instr->legpref.adr_ovr)) { return 4; } return 2; @@ -2344,51 +2343,44 @@ node_rex_prefix(struct x86_decode_fsm *f return 0; } -static const struct { - uint8_t byte; - int seg; -} legpref_table[NLEG] = { - /* Group 1 */ - [LEG_LOCK] = { 0xF0, -1 }, - [LEG_REPN] = { 0xF2, -1 }, - [LEG_REP] = { 0xF3, -1 }, - /* Group 2 */ - [LEG_OVR_CS] = { 0x2E, NVMM_X64_SEG_CS }, - [LEG_OVR_SS] = { 0x36, NVMM_X64_SEG_SS }, - [LEG_OVR_DS] = { 0x3E, NVMM_X64_SEG_DS }, - [LEG_OVR_ES] = { 0x26, NVMM_X64_SEG_ES }, - [LEG_OVR_FS] = { 0x64, NVMM_X64_SEG_FS }, - [LEG_OVR_GS] = { 0x65, NVMM_X64_SEG_GS }, - [LEG_BRN_TAKEN] = { 0x2E, -1 }, - [LEG_BRN_NTAKEN] = { 0x3E, -1 }, - /* Group 3 */ - [LEG_OPR_OVR] = { 0x66, -1 }, - /* Group 4 */ - [LEG_ADR_OVR] = { 0x67, -1 }, -}; - static int node_legacy_prefix(struct x86_decode_fsm *fsm, struct x86_instr *instr) { uint8_t byte; - size_t i; if (fsm_read(fsm, , sizeof(byte)) == -1) { return -1; } - for (i = 0; i < NLEG; i++) { - if (byte == legpref_table[i].byte) - break; - } - - if (i == NLEG) { - fsm->fn = node_rex_prefix; + if (byte == LEG_OPR_OVR) { + instr->legpref.opr_ovr = 1; + } else if (byte == LEG_OVR_DS) { + instr->legpref.seg = NVMM_X64_SEG_DS; + } else if (byte == LEG_OVR_ES) { + instr->legpref.seg = NVMM_X64_SEG_ES; + } else if (byte == LEG_REP) { + instr->legpref.rep = 1; + } else if (byte == LEG_OVR_GS) { + instr->legpref.seg = NVMM_X64_SEG_GS; + } else if (byte == LEG_OVR_FS) { + instr->legpref.seg = NVMM_X64_SEG_FS; + } else if (byte == LEG_ADR_OVR) { + instr->legpref.adr_ovr = 1; + } else if (byte == LEG_OVR_CS) { + instr->legpref.seg = NVMM_X64_SEG_CS; + } else if (byte == LEG_OVR_SS) { + instr->legpref.seg = NVMM_X64_SEG_SS; + } else if (byte == LEG_REPN) { + instr->legpref.repn = 1; + } else if (byte == LEG_LOCK) { + /* ignore */ } else { - instr->legpref[i] = true; -
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Mon Jan 7 16:30:26 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm.3 libnvmm_x86.c nvmm.h Log Message: Optimize: on single memory operand instructions, take the GPA directly from the exit structure provided by the kernel. This saves an MMU translation, and sometimes complex address computation (eg SIB). Drop the GVA field, it is not useful to virtualizers. To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/lib/libnvmm/libnvmm.3 cvs rdiff -u -r1.11 -r1.12 src/lib/libnvmm/libnvmm_x86.c cvs rdiff -u -r1.5 -r1.6 src/lib/libnvmm/nvmm.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.7 src/lib/libnvmm/libnvmm.3:1.8 --- src/lib/libnvmm/libnvmm.3:1.7 Sun Jan 6 16:10:51 2019 +++ src/lib/libnvmm/libnvmm.3 Mon Jan 7 16:30:25 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.7 2019/01/06 16:10:51 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.8 2019/01/07 16:30:25 maxv Exp $ .\" .\" Copyright (c) 2018 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 06, 2019 +.Dd January 07, 2019 .Dt LIBNVMM 3 .Os .Sh NAME @@ -455,7 +455,6 @@ structure as argument. This structure describes a Mem transaction: .Bd -literal struct nvmm_mem { - gvaddr_t gva; gpaddr_t gpa; bool write; size_t size; @@ -480,8 +479,6 @@ to retrieve the desired value. .El .Pp In either case, -.Va gva -will indicate the guest virtual address, .Va gpa will indicate the guest physical address, .Va write Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.11 src/lib/libnvmm/libnvmm_x86.c:1.12 --- src/lib/libnvmm/libnvmm_x86.c:1.11 Mon Jan 7 13:47:33 2019 +++ src/lib/libnvmm/libnvmm_x86.c Mon Jan 7 16:30:25 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.11 2019/01/07 13:47:33 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.12 2019/01/07 16:30:25 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -576,7 +576,6 @@ read_guest_memory(struct nvmm_machine *m if (is_mmio) { mem.data = data; - mem.gva = gva; mem.gpa = gpa; mem.write = false; mem.size = size; @@ -627,7 +626,6 @@ write_guest_memory(struct nvmm_machine * if (is_mmio) { mem.data = data; - mem.gva = gva; mem.gpa = gpa; mem.write = true; mem.size = size; @@ -2687,30 +2685,6 @@ store_to_gva(struct nvmm_x64_state *stat } static int -store_to_mem(struct nvmm_machine *mach, struct nvmm_x64_state *state, -struct x86_instr *instr, struct x86_store *store, struct nvmm_mem *mem) -{ - nvmm_prot_t prot; - int ret; - - ret = store_to_gva(state, instr, store, >gva, mem->size); - if (ret == -1) - return -1; - - if ((mem->gva & PAGE_MASK) + mem->size > PAGE_SIZE) { - /* Don't allow a cross-page MMIO. */ - errno = EINVAL; - return -1; - } - - ret = x86_gva_to_gpa(mach, state, mem->gva, >gpa, ); - if (ret == -1) - return -1; - - return 0; -} - -static int fetch_segment(struct nvmm_machine *mach, struct nvmm_x64_state *state) { uint8_t inst_bytes[15], byte; @@ -2820,110 +2794,66 @@ assist_mem_double(struct nvmm_machine *m static int assist_mem_single(struct nvmm_machine *mach, struct nvmm_x64_state *state, -struct x86_instr *instr) +struct x86_instr *instr, struct nvmm_exit *exit) { struct nvmm_mem mem; uint8_t membuf[8]; uint64_t val; - int ret; memset(membuf, 0, sizeof(membuf)); + + mem.gpa = exit->u.mem.gpa; + mem.size = instr->operand_size; mem.data = membuf; + /* Determine the direction. */ switch (instr->src.type) { case STORE_REG: if (instr->src.disp.type != DISP_NONE) { /* Indirect access. */ mem.write = false; - mem.size = instr->operand_size; - ret = store_to_mem(mach, state, instr, >src, - ); - if (ret == -1) -return -1; } else { /* Direct access. */ mem.write = true; - mem.size = instr->operand_size; - val = state->gprs[instr->src.u.reg->num]; - val = __SHIFTOUT(val, instr->src.u.reg->mask); - memcpy(mem.data, , mem.size); } break; - case STORE_IMM: mem.write = true; - mem.size = instr->src.u.imm.size; - memcpy(mem.data, >src.u.imm.data, mem.size); break; - case STORE_SIB: mem.write = false; - mem.size = instr->operand_size; - ret = store_to_mem(mach, state, instr, >src, ); - if (ret == -1) - return -1; break; - case STORE_DMO: mem.write = false; - mem.size = instr->operand_size; - ret = store_to_mem(mach, state, instr, >src, ); - if (ret == -1) - return -1; break; - default: - return -1; + DISASSEMBLER_BUG(); } - switch (instr->dst.type) { - case STORE_REG: - if (instr->dst.disp.type != DISP_NONE) { - if (__predict_false(!mem.write)) { + if (mem.write) { + switch (instr->src.type) { +
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Mon Jan 7 13:47:33 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Improvements and fixes: * Decode AND/OR/XOR from Group1. * Sign-extend the immediates and displacements in 64bit mode. * Fix the storage of {read,write}_guest_memory, now that we batch certain IO operations we can copy more than 8 bytes, and shit hits the fan. * Remove the CR4_PSE check in the 64bit MMU. This bit is actually ignored in long mode, and some systems (like FreeBSD) don't set it. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.10 src/lib/libnvmm/libnvmm_x86.c:1.11 --- src/lib/libnvmm/libnvmm_x86.c:1.10 Sun Jan 6 16:10:51 2019 +++ src/lib/libnvmm/libnvmm_x86.c Mon Jan 7 13:47:33 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.10 2019/01/06 16:10:51 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.11 2019/01/07 13:47:33 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -282,7 +282,7 @@ x86_gva_64bit_canonical(gvaddr_t gva) static int x86_gva_to_gpa_64bit(struct nvmm_machine *mach, uint64_t cr3, -gvaddr_t gva, gpaddr_t *gpa, bool has_pse, nvmm_prot_t *prot) +gvaddr_t gva, gpaddr_t *gpa, nvmm_prot_t *prot) { gpaddr_t L4gpa, L3gpa, L2gpa, L1gpa; uintptr_t L4hva, L3hva, L2hva, L1hva; @@ -325,8 +325,6 @@ x86_gva_to_gpa_64bit(struct nvmm_machine *prot &= ~NVMM_PROT_WRITE; if (pte & PG_NX) *prot &= ~NVMM_PROT_EXEC; - if ((pte & PG_PS) && !has_pse) - return -1; if (pte & PG_PS) { *gpa = (pte & PTE64_L3_FRAME); *gpa = *gpa + (gva & (PTE64_L2_MASK|PTE64_L1_MASK)); @@ -347,8 +345,6 @@ x86_gva_to_gpa_64bit(struct nvmm_machine *prot &= ~NVMM_PROT_WRITE; if (pte & PG_NX) *prot &= ~NVMM_PROT_EXEC; - if ((pte & PG_PS) && !has_pse) - return -1; if (pte & PG_PS) { *gpa = (pte & PTE64_L2_FRAME); *gpa = *gpa + (gva & PTE64_L1_MASK); @@ -402,7 +398,7 @@ x86_gva_to_gpa(struct nvmm_machine *mach if (is_pae && is_lng) { /* 64bit */ - ret = x86_gva_to_gpa_64bit(mach, cr3, gva, gpa, has_pse, prot); + ret = x86_gva_to_gpa_64bit(mach, cr3, gva, gpa, prot); } else if (is_pae && !is_lng) { /* 32bit PAE */ ret = x86_gva_to_gpa_32bit_pae(mach, cr3, gva, gpa, has_pse, @@ -553,7 +549,6 @@ read_guest_memory(struct nvmm_machine *m gvaddr_t gva, uint8_t *data, size_t size) { struct nvmm_mem mem; - uint8_t membuf[8]; nvmm_prot_t prot; gpaddr_t gpa; uintptr_t hva; @@ -580,13 +575,12 @@ read_guest_memory(struct nvmm_machine *m is_mmio = (ret == -1); if (is_mmio) { - mem.data = membuf; + mem.data = data; mem.gva = gva; mem.gpa = gpa; mem.write = false; mem.size = size; (*__callbacks.mem)(); - memcpy(data, mem.data, size); } else { memcpy(data, (uint8_t *)hva, size); } @@ -606,7 +600,6 @@ write_guest_memory(struct nvmm_machine * gvaddr_t gva, uint8_t *data, size_t size) { struct nvmm_mem mem; - uint8_t membuf[8]; nvmm_prot_t prot; gpaddr_t gpa; uintptr_t hva; @@ -633,11 +626,10 @@ write_guest_memory(struct nvmm_machine * is_mmio = (ret == -1); if (is_mmio) { - mem.data = membuf; + mem.data = data; mem.gva = gva; mem.gpa = gpa; mem.write = true; - memcpy(mem.data, data, size); mem.size = size; (*__callbacks.mem)(); } else { @@ -878,7 +870,7 @@ enum x86_disp_type { struct x86_disp { enum x86_disp_type type; - uint8_t data[4]; + uint64_t data; /* 4 bytes, but can be sign-extended */ }; enum REGMODRM__Mod { @@ -919,7 +911,7 @@ struct x86_regmodrm { struct x86_immediate { size_t size; /* 1/2/4/8 */ - uint8_t data[8]; + uint64_t data; }; struct x86_sib { @@ -992,9 +984,9 @@ struct x86_opcode { bool szoverride; int defsize; int allsize; + bool group1; bool group11; bool immediate; - int immsize; int flags; void (*emul)(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); }; @@ -1008,8 +1000,15 @@ struct x86_group_entry { #define OPSIZE_DOUB 0x04 /* 4 bytes */ #define OPSIZE_QUAD 0x08 /* 8 bytes */ -#define FLAG_z 0x02 -#define FLAG_e 0x10 +#define FLAG_imm8 0x01 +#define FLAG_immz 0x02 +#define FLAG_ze 0x04 + +static const struct x86_group_entry group1[8] = { + [1] = { .emul = x86_emul_or }, + [4] = { .emul = x86_emul_and }, + [6] = { .emul = x86_emul_xor } +}; static const struct x86_group_entry group11[8] = { [0] = { .emul = x86_emul_mov } @@ -1017,9 +1016,27 @@ static const struct x86_group_entry grou static const struct x86_opcode primary_opcode_table[] = { /* + * Group1 + */ + { + /* Ev, Ib */ + .byte = 0x83, + .regmodrm = true, + .regtorm = true, + .szoverride = true, + .defsize = -1, + .allsize = OPSIZE_WORD|OPSIZE_DOUB|OPSIZE_QUAD, + .group1 = true, + .immediate = true, + .flags
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Fri Jan 4 10:25:40 UTC 2019 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: In !64bit mode RIP-relative is null+disp32, handle that correctly. To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.8 src/lib/libnvmm/libnvmm_x86.c:1.9 --- src/lib/libnvmm/libnvmm_x86.c:1.8 Wed Jan 2 12:18:08 2019 +++ src/lib/libnvmm/libnvmm_x86.c Fri Jan 4 10:25:39 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.8 2019/01/02 12:18:08 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.9 2019/01/04 10:25:39 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -1826,9 +1826,16 @@ has_sib(struct x86_instr *instr) } static inline bool -is_rip_relative(struct x86_instr *instr) +is_rip_relative(struct x86_decode_fsm *fsm, struct x86_instr *instr) { - return (instr->strm->disp.type == DISP_0 && + return (fsm->is64bit && instr->strm->disp.type == DISP_0 && + instr->regmodrm.rm == RM_RBP_DISP32); +} + +static inline bool +is_disp32_only(struct x86_decode_fsm *fsm, struct x86_instr *instr) +{ + return (!fsm->is64bit && instr->strm->disp.type == DISP_0 && instr->regmodrm.rm == RM_RBP_DISP32); } @@ -1905,7 +1912,7 @@ node_regmodrm(struct x86_decode_fsm *fsm /* The displacement applies to RM. */ strm->disp.type = get_disp_type(instr); - if (is_rip_relative(instr)) { + if (is_rip_relative(fsm, instr)) { /* Overwrites RM */ strm->type = STORE_REG; strm->u.reg = _map__rip; @@ -1914,6 +1921,15 @@ node_regmodrm(struct x86_decode_fsm *fsm return 0; } + if (is_disp32_only(fsm, instr)) { + /* Overwrites RM */ + strm->type = STORE_REG; + strm->u.reg = NULL; + strm->disp.type = DISP_4; + fsm_advance(fsm, 1, node_disp); + return 0; + } + reg = get_register_rm(instr, opcode); if (reg == NULL) { return -1; @@ -2405,7 +2421,11 @@ store_to_gva(struct nvmm_x64_state *stat gva += sib->scale * reg; } } else if (store->type == STORE_REG) { - gva = gpr_read_address(instr, state, store->u.reg->num); + if (store->u.reg == NULL) { + /* The base is null. Happens with disp32-only. */ + } else { + gva = gpr_read_address(instr, state, store->u.reg->num); + } } else { gva = store->u.dmo; }
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sat Dec 29 17:54:54 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Fix the segmentation check, the limit is relative, not absolute. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.6 src/lib/libnvmm/libnvmm_x86.c:1.7 --- src/lib/libnvmm/libnvmm_x86.c:1.6 Thu Dec 27 07:22:31 2018 +++ src/lib/libnvmm/libnvmm_x86.c Sat Dec 29 17:54:54 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.6 2018/12/27 07:22:31 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.7 2018/12/29 17:54:54 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -472,7 +472,7 @@ segment_apply(struct nvmm_x64_state_seg limit *= PAGE_SIZE; } - if (__predict_false(*gva + seg->base + size > limit)) { + if (__predict_false(*gva + size > limit)) { goto error; }
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sat Dec 15 13:09:02 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Two changes: - Fix the I/O Assist, for INS* it is RDI and not RSI, and the register gets updated regardless of the REP prefix. - Fill in the Mem Assist. We decode and emulate certain instructions, and pass a mem descriptor to the callback to handle the transaction. The disassembler could use some polishing, and there are still a few instructions missing; but basically it works. To generate a diff of this commit: cvs rdiff -u -r1.4 -r1.5 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.4 src/lib/libnvmm/libnvmm_x86.c:1.5 --- src/lib/libnvmm/libnvmm_x86.c:1.4 Sat Nov 17 16:11:33 2018 +++ src/lib/libnvmm/libnvmm_x86.c Sat Dec 15 13:09:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.4 2018/11/17 16:11:33 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.5 2018/12/15 13:09:02 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -388,6 +388,26 @@ nvmm_gva_to_gpa(struct nvmm_machine *mac /* -- */ static inline bool +is_64bit(struct nvmm_x64_state *state) +{ + return (state->segs[NVMM_X64_SEG_CS].attrib.lng != 0); +} + +static inline bool +is_32bit(struct nvmm_x64_state *state) +{ + return (state->segs[NVMM_X64_SEG_CS].attrib.lng == 0) && + (state->segs[NVMM_X64_SEG_CS].attrib.def32 == 1); +} + +static inline bool +is_16bit(struct nvmm_x64_state *state) +{ + return (state->segs[NVMM_X64_SEG_CS].attrib.lng == 0) && + (state->segs[NVMM_X64_SEG_CS].attrib.def32 == 0); +} + +static inline bool is_long_mode(struct nvmm_x64_state *state) { return (state->msrs[NVMM_X64_MSR_EFER] & EFER_LME) != 0; @@ -440,9 +460,9 @@ nvmm_assist_io(struct nvmm_machine *mach uintptr_t hva; gvaddr_t gva, off; gpaddr_t gpa; - uint64_t rsi; uint8_t tmp[8]; uint8_t *ptr, *ptr2; + int reg = 0; /* GCC */ bool cross; int ret; @@ -466,18 +486,22 @@ nvmm_assist_io(struct nvmm_machine *mach if (!exit->u.io.str) { ptr = (uint8_t *)[NVMM_X64_GPR_RAX]; } else { - rsi = state.gprs[NVMM_X64_GPR_RSI]; + if (io.in) { + reg = NVMM_X64_GPR_RDI; + } else { + reg = NVMM_X64_GPR_RSI; + } switch (exit->u.io.address_size) { case 8: - gva = rsi; + gva = state.gprs[reg]; break; case 4: - gva = (rsi & 0x); + gva = (state.gprs[reg] & 0x); break; case 2: default: /* impossible */ - gva = (rsi & 0x); + gva = (state.gprs[reg] & 0x); break; } @@ -553,18 +577,19 @@ nvmm_assist_io(struct nvmm_machine *mach /* nothing to do */ } + if (exit->u.io.str) { + if (state.gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) { + state.gprs[reg] -= io.size; + } else { + state.gprs[reg] += io.size; + } + } + if (exit->u.io.rep) { state.gprs[NVMM_X64_GPR_RCX] -= 1; if (state.gprs[NVMM_X64_GPR_RCX] == 0) { state.gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc; } - if (exit->u.io.str) { - if (state.gprs[NVMM_X64_GPR_RFLAGS] & PSL_D) { -state.gprs[NVMM_X64_GPR_RSI] -= io.size; - } else { -state.gprs[NVMM_X64_GPR_RSI] += io.size; - } - } } else { state.gprs[NVMM_X64_GPR_RIP] = exit->u.io.npc; } @@ -578,16 +603,1897 @@ nvmm_assist_io(struct nvmm_machine *mach /* -- */ -int -nvmm_assist_mem(struct nvmm_machine *mach, nvmm_cpuid_t cpuid, -struct nvmm_exit *exit, void (*cb)(struct nvmm_mem *)) +static void x86_emul_or(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); +static void x86_emul_and(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); +static void x86_emul_xor(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); +static void x86_emul_mov(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); +static void x86_emul_stos(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); +static void x86_emul_lods(struct nvmm_mem *, void (*)(struct nvmm_mem *), uint64_t *); + +enum x86_legpref { + /* Group 1 */ + LEG_LOCK = 0, + LEG_REPN, /* REPNE/REPNZ */ + LEG_REP, /* REP/REPE/REPZ */ + /* Group 2 */ + LEG_OVR_CS, + LEG_OVR_SS, + LEG_OVR_DS, + LEG_OVR_ES, + LEG_OVR_FS, + LEG_OVR_GS, + LEG_BRN_TAKEN, + LEG_BRN_NTAKEN, + /* Group 3 */ + LEG_OPR_OVR, + /* Group 4 */ + LEG_ADR_OVR, + + NLEG +}; + +struct x86_rexpref { + bool present; + bool w; + bool r; + bool x; + bool b; +}; + +struct x86_reg { + int num; /* NVMM GPR state index */ + uint64_t mask; +}; + +enum x86_disp_type { + DISP_NONE, + DISP_0, + DISP_1, + DISP_4 +}; + +struct x86_disp { + enum x86_disp_type type; + uint8_t data[4]; +}; + +enum REGMODRM__Mod { + MOD_DIS0, /* also, register indirect
CVS commit: src/lib/libnvmm
Module Name:src Committed By: wiz Date: Wed Dec 12 11:40:08 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: Remove superfluous dot. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.3 src/lib/libnvmm/libnvmm.3:1.4 --- src/lib/libnvmm/libnvmm.3:1.3 Wed Dec 12 09:09:08 2018 +++ src/lib/libnvmm/libnvmm.3 Wed Dec 12 11:40:08 2018 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.3 2018/12/12 09:09:08 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.4 2018/12/12 11:40:08 wiz Exp $ .\" .\" Copyright (c) 2018 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -513,7 +513,7 @@ uses the following error codes: The VCPU cannot receive the event immediately. .El .Sh SEE ALSO -.Xr nvmm 4 . +.Xr nvmm 4 .Sh AUTHORS NVMM was designed and implemented by .An Maxime Villard .
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Wed Dec 12 10:42:34 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm.c Log Message: Change the map/unmap functions, again. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/lib/libnvmm/libnvmm.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.c diff -u src/lib/libnvmm/libnvmm.c:1.3 src/lib/libnvmm/libnvmm.c:1.4 --- src/lib/libnvmm/libnvmm.c:1.3 Thu Nov 29 19:55:20 2018 +++ src/lib/libnvmm/libnvmm.c Wed Dec 12 10:42:34 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.3 2018/11/29 19:55:20 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.4 2018/12/12 10:42:34 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -57,89 +57,40 @@ static size_t nvmm_page_size = 0; /* -- */ -static int -__area_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, - size_t size) -{ - struct nvmm_ioc_gpa_unmap args; - int ret; - - args.machid = mach->machid; - args.gpa = gpa; - args.size = size; - - ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, ); - if (ret == -1) - return -1; - - ret = munmap((void *)hva, size); - - return ret; -} - -static int -__area_dig_hole(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, +static bool +__area_isvalid(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) { area_list_t *areas = mach->areas; - area_t *ent, *tmp, *nxt; - size_t diff; + area_t *ent; - LIST_FOREACH_SAFE(ent, areas, list, nxt) { - /* Case 1. */ - if ((gpa < ent->gpa) && (gpa + size > ent->gpa)) { - diff = (gpa + size) - ent->gpa; - if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) { -return -1; - } - ent->gpa += diff; - ent->hva += diff; - ent->size -= diff; + LIST_FOREACH(ent, areas, list) { + /* Collision on HVA */ + if (hva >= ent->hva && hva < ent->hva + ent->size) { + return false; } - - /* Case 2. */ - if ((gpa >= ent->gpa) && (gpa + size <= ent->gpa + ent->size)) { - /* First half. */ - tmp = malloc(sizeof(*tmp)); - tmp->gpa = ent->gpa; - tmp->hva = ent->hva; - tmp->size = (gpa - ent->gpa); - LIST_INSERT_BEFORE(ent, tmp, list); - /* Second half. */ - ent->gpa += tmp->size; - ent->hva += tmp->size; - ent->size -= tmp->size; - diff = size; - if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) { -return -1; - } - ent->gpa += diff; - ent->hva += diff; - ent->size -= diff; + if (hva + size >= ent->hva && + hva + size < ent->hva + ent->size) { + return false; } - - /* Case 3. */ - if ((gpa < ent->gpa + ent->size) && - (gpa + size > ent->gpa + ent->size)) { - diff = (ent->gpa + ent->size) - gpa; - if (__area_unmap(mach, hva, gpa, diff) == -1) { -return -1; - } - ent->size -= diff; + if (hva <= ent->hva && hva + size >= ent->hva + ent->size) { + return false; } - /* Case 4. */ - if ((gpa < ent->gpa + ent->size) && - (gpa + size > ent->gpa + ent->size)) { - if (__area_unmap(mach, ent->hva, ent->gpa, ent->size) == -1) { -return -1; - } - LIST_REMOVE(ent, list); - free(ent); + /* Collision on GPA */ + if (gpa >= ent->gpa && gpa < ent->gpa + ent->size) { + return false; + } + if (gpa + size >= ent->gpa && + gpa + size < ent->gpa + ent->size) { + return false; + } + if (gpa <= ent->gpa && gpa + size >= ent->gpa + ent->size) { + return false; } } - return 0; + return true; } static int @@ -147,7 +98,11 @@ __area_add(struct nvmm_machine *mach, ui { area_list_t *areas = mach->areas; area_t *area; - int ret; + + if (!__area_isvalid(mach, hva, gpa, size)) { + errno = EINVAL; + return -1; + } area = malloc(sizeof(*area)); if (area == NULL) @@ -156,16 +111,29 @@ __area_add(struct nvmm_machine *mach, ui area->hva = hva; area->size = size; - ret = __area_dig_hole(mach, hva, gpa, size); - if (ret == -1) { - free(area); - return -1; - } - LIST_INSERT_HEAD(areas, area, list); + return 0; } +static int +__area_delete(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, +size_t size) +{ + area_list_t *areas = mach->areas; + area_t *ent, *nxt; + + LIST_FOREACH_SAFE(ent, areas, list, nxt) { + if (hva == ent->hva && gpa == ent->gpa && size == ent->size) { + LIST_REMOVE(ent, list); + free(ent); + return 0; + } + } + + return -1; +} + static void __area_remove_all(struct nvmm_machine *mach) { @@ -450,11 +418,28 @@ int nvmm_gpa_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) { + struct nvmm_ioc_gpa_unmap args; + int ret; + if (nvmm_init() == -1) { return -1; } - return __area_dig_hole(mach, hva, gpa, size); + ret = __area_delete(mach, hva, gpa, size); + if (ret == -1) + return -1; + + args.machid = mach->machid; + args.gpa = gpa; + args.size = size; + + ret = ioctl(nvmm_fd,
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Wed Dec 12 09:09:08 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: Change the "FILES" section, in the end I don't want to commit toyvirt and smallkern, there is little interest installing them by default, rather they can be downloaded from www. It's better this way. While here add NVMM(4) in "SEE ALSO". To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.2 src/lib/libnvmm/libnvmm.3:1.3 --- src/lib/libnvmm/libnvmm.3:1.2 Sat Nov 10 10:57:06 2018 +++ src/lib/libnvmm/libnvmm.3 Wed Dec 12 09:09:08 2018 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnvmm.3,v 1.2 2018/11/10 10:57:06 maxv Exp $ +.\" $NetBSD: libnvmm.3,v 1.3 2018/12/12 09:09:08 maxv Exp $ .\" .\" Copyright (c) 2018 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 10, 2018 +.Dd December 12, 2018 .Dt LIBNVMM 3 .Os .Sh NAME @@ -473,14 +473,18 @@ variable .Va errno is set to indicate the error. .Sh FILES -Functional examples: -.Pp .Bl -tag -width -compact -.It Pa src/share/examples/nvmm/toyvirt/ -Example of virtualizer. -Launches the binary given as argument in a virtual machine. -.It Pa src/share/examples/nvmm/smallkern/ -Example of a kernel that can be executed by toyvirt. +.It Lk https://www.netbsd.org/~maxv/nvmm/nvmm-demo.zip +Functional example (demonstrator). +Contains a virtualizer that uses the +.Nm +API, and a small kernel that exercises this virtualizer. +.It Pa src/sys/dev/nvmm/ +Source code of the kernel NVMM driver. +.It Pa src/lib/libnvmm/ +Source code of the +.Nm +library. .El .Sh ERRORS These functions will fail if: @@ -508,6 +512,8 @@ uses the following error codes: .It Bq Er EAGAIN The VCPU cannot receive the event immediately. .El +.Sh SEE ALSO +.Xr nvmm 4 . .Sh AUTHORS NVMM was designed and implemented by .An Maxime Villard .
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Thu Nov 29 19:55:21 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm.c nvmm.h Log Message: Rewrite the gpa map/unmap functions. Dig holes in the mapped areas when there is an overlap. Close to what Qemu expects. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/lib/libnvmm/libnvmm.c cvs rdiff -u -r1.1 -r1.2 src/lib/libnvmm/nvmm.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.c diff -u src/lib/libnvmm/libnvmm.c:1.2 src/lib/libnvmm/libnvmm.c:1.3 --- src/lib/libnvmm/libnvmm.c:1.2 Mon Nov 19 21:45:37 2018 +++ src/lib/libnvmm/libnvmm.c Thu Nov 29 19:55:20 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.2 2018/11/19 21:45:37 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.3 2018/11/29 19:55:20 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -39,78 +39,145 @@ #include #include #include +#include #include "nvmm.h" +typedef struct __area { + LIST_ENTRY(__area) list; + gpaddr_t gpa; + uintptr_t hva; + size_t size; +} area_t; + +typedef LIST_HEAD(, __area) area_list_t; + static int nvmm_fd = -1; static size_t nvmm_page_size = 0; /* -- */ static int -_nvmm_area_add(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva, +__area_unmap(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, + size_t size) +{ + struct nvmm_ioc_gpa_unmap args; + int ret; + + args.machid = mach->machid; + args.gpa = gpa; + args.size = size; + + ret = ioctl(nvmm_fd, NVMM_IOC_GPA_UNMAP, ); + if (ret == -1) + return -1; + + ret = munmap((void *)hva, size); + + return ret; +} + +static int +__area_dig_hole(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) { - struct nvmm_area *area; - void *ptr; - size_t i; - - for (i = 0; i < mach->nareas; i++) { - if (gpa >= mach->areas[i].gpa && - gpa < mach->areas[i].gpa + mach->areas[i].size) { - goto error; + area_list_t *areas = mach->areas; + area_t *ent, *tmp, *nxt; + size_t diff; + + LIST_FOREACH_SAFE(ent, areas, list, nxt) { + /* Case 1. */ + if ((gpa < ent->gpa) && (gpa + size > ent->gpa)) { + diff = (gpa + size) - ent->gpa; + if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) { +return -1; + } + ent->gpa += diff; + ent->hva += diff; + ent->size -= diff; } - if (gpa + size > mach->areas[i].gpa && - gpa + size <= mach->areas[i].gpa + mach->areas[i].size) { - goto error; + + /* Case 2. */ + if ((gpa >= ent->gpa) && (gpa + size <= ent->gpa + ent->size)) { + /* First half. */ + tmp = malloc(sizeof(*tmp)); + tmp->gpa = ent->gpa; + tmp->hva = ent->hva; + tmp->size = (gpa - ent->gpa); + LIST_INSERT_BEFORE(ent, tmp, list); + /* Second half. */ + ent->gpa += tmp->size; + ent->hva += tmp->size; + ent->size -= tmp->size; + diff = size; + if (__area_unmap(mach, ent->hva, ent->gpa, diff) == -1) { +return -1; + } + ent->gpa += diff; + ent->hva += diff; + ent->size -= diff; } - if (gpa < mach->areas[i].gpa && - gpa + size >= mach->areas[i].gpa + mach->areas[i].size) { - goto error; + + /* Case 3. */ + if ((gpa < ent->gpa + ent->size) && + (gpa + size > ent->gpa + ent->size)) { + diff = (ent->gpa + ent->size) - gpa; + if (__area_unmap(mach, hva, gpa, diff) == -1) { +return -1; + } + ent->size -= diff; + } + + /* Case 4. */ + if ((gpa < ent->gpa + ent->size) && + (gpa + size > ent->gpa + ent->size)) { + if (__area_unmap(mach, ent->hva, ent->gpa, ent->size) == -1) { +return -1; + } + LIST_REMOVE(ent, list); + free(ent); } } - ptr = realloc(mach->areas, (mach->nareas + 1) * - sizeof(struct nvmm_area)); - if (ptr == NULL) - return -1; - mach->areas = ptr; + return 0; +} + +static int +__area_add(struct nvmm_machine *mach, uintptr_t hva, gpaddr_t gpa, size_t size) +{ + area_list_t *areas = mach->areas; + area_t *area; + int ret; - area = >areas[mach->nareas++]; + area = malloc(sizeof(*area)); + if (area == NULL) + return -1; area->gpa = gpa; area->hva = hva; area->size = size; - return 0; + ret = __area_dig_hole(mach, hva, gpa, size); + if (ret == -1) { + free(area); + return -1; + } -error: - errno = EEXIST; - return -1; + LIST_INSERT_HEAD(areas, area, list); + return 0; } -static int -_nvmm_area_delete(struct nvmm_machine *mach, gpaddr_t gpa, uintptr_t hva, -size_t size) +static void +__area_remove_all(struct nvmm_machine *mach) { - size_t i; + area_list_t *areas = mach->areas; + area_t *ent; - for (i = 0; i < mach->nareas; i++) { - if (gpa == mach->areas[i].gpa && - hva == mach->areas[i].hva && - size == mach->areas[i].size) { - break; - } - } - if (i == mach->nareas) { - errno = ENOENT; - return -1; + while ((ent = LIST_FIRST(areas)) != NULL) { + LIST_REMOVE(ent, list); + free(ent); } -
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Mon Nov 19 21:45:37 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm.c Log Message: Fix error handling of realloc, and use memmove because the areas overlap; noted by agc@. These _nvmm_area_add/delete functions don't make a lot of sense right now and will likely be rewritten to match the behavior expected by Qemu; but still fix for the time being. Also fix a collision check while here. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/lib/libnvmm/libnvmm.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.c diff -u src/lib/libnvmm/libnvmm.c:1.1 src/lib/libnvmm/libnvmm.c:1.2 --- src/lib/libnvmm/libnvmm.c:1.1 Sat Nov 10 09:28:56 2018 +++ src/lib/libnvmm/libnvmm.c Mon Nov 19 21:45:37 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm.c,v 1.1 2018/11/10 09:28:56 maxv Exp $ */ +/* $NetBSD: libnvmm.c,v 1.2 2018/11/19 21:45:37 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -60,8 +60,8 @@ _nvmm_area_add(struct nvmm_machine *mach gpa < mach->areas[i].gpa + mach->areas[i].size) { goto error; } - if (gpa + size >= mach->areas[i].gpa && - gpa + size < mach->areas[i].gpa + mach->areas[i].size) { + if (gpa + size > mach->areas[i].gpa && + gpa + size <= mach->areas[i].gpa + mach->areas[i].size) { goto error; } if (gpa < mach->areas[i].gpa && @@ -70,13 +70,13 @@ _nvmm_area_add(struct nvmm_machine *mach } } - mach->nareas++; - ptr = realloc(mach->areas, mach->nareas * sizeof(struct nvmm_area)); + ptr = realloc(mach->areas, (mach->nareas + 1) * + sizeof(struct nvmm_area)); if (ptr == NULL) return -1; mach->areas = ptr; - area = >areas[mach->nareas-1]; + area = >areas[mach->nareas++]; area->gpa = gpa; area->hva = hva; area->size = size; @@ -106,7 +106,7 @@ _nvmm_area_delete(struct nvmm_machine *m return -1; } - memcpy(>areas[i], >areas[i+1], + memmove(>areas[i], >areas[i+1], (mach->nareas - i - 1) * sizeof(struct nvmm_area)); mach->nareas--;
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sat Nov 17 16:11:33 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Don't forget to set 'prot' when the guest has paging disabled. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.3 src/lib/libnvmm/libnvmm_x86.c:1.4 --- src/lib/libnvmm/libnvmm_x86.c:1.3 Tue Nov 13 06:57:14 2018 +++ src/lib/libnvmm/libnvmm_x86.c Sat Nov 17 16:11:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.3 2018/11/13 06:57:14 maya Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.4 2018/11/17 16:11:33 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -334,6 +334,7 @@ x86_gva_to_gpa(struct nvmm_machine *mach if ((state->crs[NVMM_X64_CR_CR0] & CR0_PG) == 0) { /* No paging. */ + *prot = NVMM_PROT_ALL; *gpa = gva; return 0; }
CVS commit: src/lib/libnvmm
Module Name:src Committed By: martin Date: Tue Nov 13 09:14:14 UTC 2018 Modified Files: src/lib/libnvmm: Makefile Log Message: Need some minimalistic support for additional things that ../Makefile requires, even if we do nothing here To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/lib/libnvmm/Makefile Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/Makefile diff -u src/lib/libnvmm/Makefile:1.3 src/lib/libnvmm/Makefile:1.4 --- src/lib/libnvmm/Makefile:1.3 Tue Nov 13 09:00:09 2018 +++ src/lib/libnvmm/Makefile Tue Nov 13 09:14:14 2018 @@ -1,9 +1,9 @@ -# $NetBSD: Makefile,v 1.3 2018/11/13 09:00:09 martin Exp $ - -.if ${MACHINE_ARCH} == "x86_64" && ${MLIBDIR:Unone} != "i386" +# $NetBSD: Makefile,v 1.4 2018/11/13 09:14:14 martin Exp $ .include +.if ${MACHINE_ARCH} == "x86_64" && ${MLIBDIR:Unone} != "i386" + LIB= nvmm MAN= libnvmm.3 @@ -14,6 +14,10 @@ INCSDIR= /usr/include WARNS= 5 +.else +LIB= +LIBDPLIBS= +.endif + .include -.endif
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maya Date: Tue Nov 13 06:57:14 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Revert my own rev 1.2, the missing include was only when building the 32-bit compat library, we no longer do this. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.2 src/lib/libnvmm/libnvmm_x86.c:1.3 --- src/lib/libnvmm/libnvmm_x86.c:1.2 Sun Nov 11 00:06:48 2018 +++ src/lib/libnvmm/libnvmm_x86.c Tue Nov 13 06:57:14 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.2 2018/11/11 00:06:48 maya Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.3 2018/11/13 06:57:14 maya Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -42,7 +42,6 @@ #include #include #include -#include #include "nvmm.h"
CVS commit: src/lib/libnvmm
Module Name:src Committed By: nakayama Date: Mon Nov 12 17:46:53 UTC 2018 Modified Files: src/lib/libnvmm: Makefile Log Message: No need to install shared libraries to /lib. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/lib/libnvmm/Makefile Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/Makefile diff -u src/lib/libnvmm/Makefile:1.1 src/lib/libnvmm/Makefile:1.2 --- src/lib/libnvmm/Makefile:1.1 Sat Nov 10 09:28:56 2018 +++ src/lib/libnvmm/Makefile Mon Nov 12 17:46:53 2018 @@ -1,6 +1,4 @@ -# $NetBSD: Makefile,v 1.1 2018/11/10 09:28:56 maxv Exp $ - -USE_SHLIBDIR= yes +# $NetBSD: Makefile,v 1.2 2018/11/12 17:46:53 nakayama Exp $ .include
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maya Date: Sun Nov 11 00:06:48 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm_x86.c Log Message: Add missing include for struct nvmm_x64_state (Pointed out by the clang build) To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/lib/libnvmm/libnvmm_x86.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm_x86.c diff -u src/lib/libnvmm/libnvmm_x86.c:1.1 src/lib/libnvmm/libnvmm_x86.c:1.2 --- src/lib/libnvmm/libnvmm_x86.c:1.1 Sat Nov 10 09:28:56 2018 +++ src/lib/libnvmm/libnvmm_x86.c Sun Nov 11 00:06:48 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: libnvmm_x86.c,v 1.1 2018/11/10 09:28:56 maxv Exp $ */ +/* $NetBSD: libnvmm_x86.c,v 1.2 2018/11/11 00:06:48 maya Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -42,6 +42,7 @@ #include #include #include +#include #include "nvmm.h"
CVS commit: src/lib/libnvmm
Module Name:src Committed By: maxv Date: Sat Nov 10 10:57:06 UTC 2018 Modified Files: src/lib/libnvmm: libnvmm.3 Log Message: Add copyright and RCSID, from wiz@. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/lib/libnvmm/libnvmm.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. Modified files: Index: src/lib/libnvmm/libnvmm.3 diff -u src/lib/libnvmm/libnvmm.3:1.1 src/lib/libnvmm/libnvmm.3:1.2 --- src/lib/libnvmm/libnvmm.3:1.1 Sat Nov 10 09:28:56 2018 +++ src/lib/libnvmm/libnvmm.3 Sat Nov 10 10:57:06 2018 @@ -1,4 +1,33 @@ -.Dd September 12, 2018 +.\" $NetBSD: libnvmm.3,v 1.2 2018/11/10 10:57:06 maxv Exp $ +.\" +.\" Copyright (c) 2018 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Maxime Villard. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd November 10, 2018 .Dt LIBNVMM 3 .Os .Sh NAME