Index: sys/amd64/vmm/vmm.c =================================================================== --- sys/amd64/vmm/vmm.c +++ sys/amd64/vmm/vmm.c @@ -77,6 +77,7 @@ #include "vlapic.h" #include "vpmtmr.h" #include "vrtc.h" +#include "vmm_host_stat.h" #include "vmm_stat.h" #include "vmm_lapic.h" @@ -365,6 +366,7 @@ switch (what) { case MOD_LOAD: vmmdev_init(); + vmm_host_stat_init(); error = vmm_init(); if (error == 0) vmm_initialized = 1; @@ -383,6 +385,7 @@ */ if (error) vmm_initialized = 0; + vmm_host_stat_cleanup(); } break; default: @@ -1647,7 +1650,7 @@ int error, vcpuid; struct vcpu *vcpu; struct pcb *pcb; - uint64_t tscval; + uint64_t tscval_enter, tscval_delta; struct vm_exit *vme; bool retu, intr_disabled; pmap_t pmap; @@ -1675,7 +1678,7 @@ KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), ("vm_run: absurd pm_active")); - tscval = rdtsc(); + tscval_enter = rdtsc(); pcb = PCPU_GET(curpcb); set_pcb_flags(pcb, PCB_FULL_IRET); @@ -1688,10 +1691,13 @@ save_guest_fpustate(vcpu); - vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval); + tscval_delta = rdtsc() - tscval_enter; + vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, tscval_delta); critical_exit(); + vmm_host_stat_cpu_ticks_incr(curcpu, tscval_delta); + if (error == 0) { retu = false; vcpu->nextrip = vme->rip + vme->inst_length; Index: sys/amd64/vmm/vmm_host_stat.h =================================================================== --- /dev/null +++ sys/amd64/vmm/vmm_host_stat.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Dr Robert Harvey Crowston + * All rights reserved. + * + * 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 AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef _VMM_HOST_STAT_H_ +#define _VMM_HOST_STAT_H_ + +void vmm_host_stat_cpu_ticks_incr(int pcpu, uint64_t val); + +void vmm_host_stat_init(void); +void vmm_host_stat_cleanup(void); + +SYSCTL_DECL(_hw_vmm); + +#endif /* _VMM_HOST_STAT_H_ */ + + Index: sys/amd64/vmm/vmm_host_stat.c =================================================================== --- /dev/null +++ sys/amd64/vmm/vmm_host_stat.c @@ -0,0 +1,120 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Dr Robert Harvey Crowston + * All rights reserved. + * + * 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 AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vmm_host_stat.h" + +static MALLOC_DEFINE(M_VMM_HOST_STAT, "vmm host stats", + "vmm host statistics"); + +static uint64_t *guest_counters; +static struct sysctl_ctx_list sysctl_ctx; +static unsigned pr_allow_flag; + +static int sysctl_hw_vmm_stat_guest_ticks(SYSCTL_HANDLER_ARGS); + +SYSCTL_NODE(_hw_vmm, OID_AUTO, stat, CTLFLAG_RD, 0, "vmm host statistics"); + +void vmm_host_stat_init() +{ + + guest_counters = malloc(sizeof(uint64_t) * mp_ncpus, M_VMM_HOST_STAT, + M_WAITOK | M_ZERO); + + sysctl_ctx_init(&sysctl_ctx); + SYSCTL_ADD_PROC(&sysctl_ctx, SYSCTL_STATIC_CHILDREN(_hw_vmm_stat), + OID_AUTO, "guest_ticks", CTLTYPE_U64|CTLFLAG_RD|CTLFLAG_MPSAFE, 0, + 0, sysctl_hw_vmm_stat_guest_ticks, "QU", + "Ticks each CPU has spent in guest execution"); + + pr_allow_flag = prison_add_allow(NULL, "vmm_host_stat", NULL, + "Allow jailed processes to read hw.vmm.stat."); +} + +void vmm_host_stat_cleanup() +{ + + /* Destroy the sysctl context before we free the counters. */ + sysctl_ctx_free(&sysctl_ctx); + + free(guest_counters, M_VMM_HOST_STAT); +} + +void vmm_host_stat_cpu_ticks_incr(int pcpu, uint64_t val) +{ + + KASSERT(pcpu < mp_ncpus, "Invalid CPU ID for guest tick counter."); + + atomic_add_64((guest_counters + pcpu), val); +} + +static int +check_sysctl_priv(struct thread *td) +{ + + if (jailed(td->td_ucred) && !prison_allow(td->td_ucred, pr_allow_flag)) + return (EPERM); + + return (priv_check(td, PRIV_VMM_HOST_STAT)); +} + +static int +sysctl_hw_vmm_stat_guest_ticks(SYSCTL_HANDLER_ARGS) +{ + int error; + int cpu; + uint64_t ticks; + + error = check_sysctl_priv(req->td); + if (error) + return error; + + if (!req->oldptr) + return SYSCTL_OUT(req, 0, sizeof(uint64_t) * mp_ncpus); + + for (error = 0, cpu = 0; error == 0 && cpu < mp_ncpus; cpu++) { + ticks = atomic_load_64(guest_counters + cpu); + error = SYSCTL_OUT(req, &ticks, sizeof(uint64_t)); + } + return error; +} + Index: sys/kern/kern_jail.c =================================================================== --- sys/kern/kern_jail.c +++ sys/kern/kern_jail.c @@ -3367,6 +3367,13 @@ return (0); return (EPERM); + case PRIV_VMM_HOST_STAT: + /* + * Allow root in a jail to read the vmm host statistics sysctl. + * This privilege can be denied by vmm_host_stat.c. + */ + return (0); + default: /* * In all remaining cases, deny the privilege request. This Index: sys/modules/vmm/Makefile =================================================================== --- sys/modules/vmm/Makefile +++ sys/modules/vmm/Makefile @@ -17,6 +17,7 @@ SRCS+= vmm.c \ vmm_dev.c \ vmm_host.c \ + vmm_host_stat.c \ vmm_instruction_emul.c \ vmm_ioport.c \ vmm_lapic.c \ Index: sys/sys/priv.h =================================================================== --- sys/sys/priv.h +++ sys/sys/priv.h @@ -508,10 +508,15 @@ #define PRIV_KMEM_READ 680 /* Open mem/kmem for reading. */ #define PRIV_KMEM_WRITE 681 /* Open mem/kmem for writing. */ +/* + * vmm(4) privileges. + */ +#define PRIV_VMM_HOST_STAT 690 /* Read the sysctl hw.vmm.stat. */ + /* * Track end of privilege list. */ -#define _PRIV_HIGHEST 682 +#define _PRIV_HIGHEST 691 /* * Validate that a named privilege is known by the privilege system. Invalid