From owner-svn-src-all@FreeBSD.ORG Wed Dec 31 09:15:41 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 305FA884 for ; Wed, 31 Dec 2014 09:15:41 +0000 (UTC) Received: from frv25.fwdcdn.com (frv25.fwdcdn.com [212.42.77.25]) by mx1.freebsd.org (Postfix) with ESMTP id D066C64CF3 for ; Wed, 31 Dec 2014 09:15:40 +0000 (UTC) Received: from [10.10.14.27] (helo=frv27.fwdcdn.com) by frv25.fwdcdn.com QID:1Y6F5C-000GHc-Id/RC:1; Wed, 31 Dec 2014 10:56:46 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=ukr.net; s=fsm; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Subject:To:From:Date; bh=12/FTTKcfM1q16ZRBmkLrYzi0X0xAbMasXuqjPTLQtM=; b=gjNv1SO6ZbmFTCh0/6mqkhGF5F53IMlDIURCryrSIMdVkO/wZoOsw9TV3kOWnb9lkr4U6YHjepzqxb7Q3YJCkuOJs+BXtFwdLYq7nxdOd1yRdt6jhQbuPjta9UmhqvHiuNTOZd2gHhK9a53/TCZCWbnkIhZXvbxCN5VO0enUSFc=; Received: from [37.229.193.70] (helo=nonamehost.local) by frv27.fwdcdn.com with esmtpsa ID 1Y6F54-0000OG-KK for svn-src-all@freebsd.org; Wed, 31 Dec 2014 10:56:38 +0200 Date: Wed, 31 Dec 2014 10:56:38 +0200 From: Ivan Klymenko To: svn-src-all@freebsd.org Subject: Re: svn commit: r276428 - in head: lib/libvmmapi sys/amd64/include sys/amd64/vmm sys/amd64/vmm/io sys/modules/vmm usr.sbin/bhyve usr.sbin/bhyvectl Message-ID: <20141231105638.15336969@nonamehost.local> In-Reply-To: <201412302219.sBUMJZ1x094872@svn.freebsd.org> References: <201412302219.sBUMJZ1x094872@svn.freebsd.org> X-Mailer: Claws Mail 3.11.1 (GTK+ 2.24.25; amd64-portbld-freebsd11.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Authentication-Result: IP=37.229.193.70; mail.from=fidaj@ukr.net; dkim=pass; header.d=ukr.net X-Ukrnet-Yellow: 0 X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 31 Dec 2014 09:15:41 -0000 =D0=92 Tue, 30 Dec 2014 22:19:35 +0000 (UTC) Neel Natu =D0=BF=D0=B8=D1=88=D0=B5=D1=82: > Author: neel > Date: Tue Dec 30 22:19:34 2014 > New Revision: 276428 > URL: https://svnweb.freebsd.org/changeset/base/276428 >=20 > Log: > Replace bhyve's minimal RTC emulation with a fully featured one in > vmm.ko.=20 > The new RTC emulation supports all interrupt modes: periodic, > update ended and alarm. It is also capable of maintaining the > date/time and NVRAM contents across virtual machine reset. Also, the > date/time fields can now be modified by the guest. > =20 > Since bhyve now emulates both the PIT and the RTC there is no need > for "Legacy Replacement Routing" in the HPET so get rid of it. > =20 > The RTC device state can be inspected via bhyvectl as follows: > bhyvectl --vm=3Dvm --get-rtc-time > bhyvectl --vm=3Dvm --set-rtc-time=3D > bhyvectl --vm=3Dvm --rtc-nvram-offset=3D --get-rtc-nvram > bhyvectl --vm=3Dvm --rtc-nvram-offset=3D --set-rtc-nvram=3D > =20 > Reviewed by: tychon > Discussed with: grehan > Differential Revision: https://reviews.freebsd.org/D1385 > MFC after: 2 weeks >=20 > Added: > head/sys/amd64/vmm/io/vrtc.c (contents, props changed) > head/sys/amd64/vmm/io/vrtc.h (contents, props changed) > Modified: > head/lib/libvmmapi/vmmapi.c > head/lib/libvmmapi/vmmapi.h > head/sys/amd64/include/vmm.h > head/sys/amd64/include/vmm_dev.h > head/sys/amd64/vmm/io/vhpet.c > head/sys/amd64/vmm/vmm.c > head/sys/amd64/vmm/vmm_dev.c > head/sys/amd64/vmm/vmm_ioport.c > head/sys/modules/vmm/Makefile > head/usr.sbin/bhyve/rtc.c > head/usr.sbin/bhyvectl/bhyvectl.c >=20 > Modified: head/lib/libvmmapi/vmmapi.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/lib/libvmmapi/vmmapi.c Tue Dec 30 22:04:24 > 2014 (r276427) +++ head/lib/libvmmapi/vmmapi.c Tue Dec > 30 22:19:34 2014 (r276428) @@ -1146,3 +1146,55 @@ > vm_set_intinfo(struct vmctx *ctx, int vc error =3D ioctl(ctx->fd, > VM_SET_INTINFO, &vmii); return (error); > } > + > +int > +vm_rtc_write(struct vmctx *ctx, int offset, uint8_t value) > +{ > + struct vm_rtc_data rtcdata; > + int error; > + > + bzero(&rtcdata, sizeof(struct vm_rtc_data)); > + rtcdata.offset =3D offset; > + rtcdata.value =3D value; > + error =3D ioctl(ctx->fd, VM_RTC_WRITE, &rtcdata); > + return (error); > +} > + > +int > +vm_rtc_read(struct vmctx *ctx, int offset, uint8_t *retval) > +{ > + struct vm_rtc_data rtcdata; > + int error; > + > + bzero(&rtcdata, sizeof(struct vm_rtc_data)); > + rtcdata.offset =3D offset; > + error =3D ioctl(ctx->fd, VM_RTC_READ, &rtcdata); > + if (error =3D=3D 0) > + *retval =3D rtcdata.value; > + return (error); > +} > + > +int > +vm_rtc_settime(struct vmctx *ctx, time_t secs) > +{ > + struct vm_rtc_time rtctime; > + int error; > + > + bzero(&rtctime, sizeof(struct vm_rtc_time)); > + rtctime.secs =3D secs; > + error =3D ioctl(ctx->fd, VM_RTC_SETTIME, &rtctime); > + return (error); > +} > + > +int > +vm_rtc_gettime(struct vmctx *ctx, time_t *secs) > +{ > + struct vm_rtc_time rtctime; > + int error; > + > + bzero(&rtctime, sizeof(struct vm_rtc_time)); > + error =3D ioctl(ctx->fd, VM_RTC_GETTIME, &rtctime); > + if (error =3D=3D 0) > + *secs =3D rtctime.secs; > + return (error); > +} >=20 > Modified: head/lib/libvmmapi/vmmapi.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/lib/libvmmapi/vmmapi.h Tue Dec 30 22:04:24 > 2014 (r276427) +++ head/lib/libvmmapi/vmmapi.h Tue Dec > 30 22:19:34 2014 (r276428) @@ -133,6 +133,12 @@ void > vm_copyin(struct vmctx *ctx, int vc void vm_copyout(struct > vmctx *ctx, int vcpu, const void *host_src, struct iovec *guest_iov, > size_t len);=20 > +/* RTC */ > +int vm_rtc_write(struct vmctx *ctx, int offset, uint8_t > value); +int vm_rtc_read(struct vmctx *ctx, int offset, > uint8_t *retval); +int vm_rtc_settime(struct vmctx *ctx, > time_t secs); +int vm_rtc_gettime(struct vmctx *ctx, time_t > *secs); + > /* Reset vcpu register state */ > int vcpu_reset(struct vmctx *ctx, int vcpu); > =20 >=20 > Modified: head/sys/amd64/include/vmm.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/sys/amd64/include/vmm.h Tue Dec 30 22:04:24 > 2014 (r276427) +++ head/sys/amd64/include/vmm.h Tue Dec > 30 22:19:34 2014 (r276428) @@ -286,6 +286,7 @@ int > vm_unassign_pptdev(struct vm *vm, in struct vatpic *vm_atpic(struct > vm *vm); struct vatpit *vm_atpit(struct vm *vm); > struct vpmtmr *vm_pmtmr(struct vm *vm); > +struct vrtc *vm_rtc(struct vm *vm); > =20 > /* > * Inject exception 'vme' into the guest vcpu. This function returns > 0 on >=20 > Modified: head/sys/amd64/include/vmm_dev.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/sys/amd64/include/vmm_dev.h Tue Dec 30 22:04:24 > 2014 (r276427) +++ head/sys/amd64/include/vmm_dev.h Tue > Dec 30 22:19:34 2014 (r276428) @@ -195,6 +195,15 @@ struct > vm_intinfo { uint64_t info2; > }; > =20 > +struct vm_rtc_time { > + time_t secs; > +}; > + > +struct vm_rtc_data { > + int offset; > + uint8_t value; > +}; > + > enum { > /* general routines */ > IOCNUM_ABIVERS =3D 0, > @@ -254,6 +263,12 @@ enum { > /* vm_cpuset */ > IOCNUM_ACTIVATE_CPU =3D 90, > IOCNUM_GET_CPUSET =3D 91, > + > + /* RTC */ > + IOCNUM_RTC_READ =3D 100, > + IOCNUM_RTC_WRITE =3D 101, > + IOCNUM_RTC_SETTIME =3D 102, > + IOCNUM_RTC_GETTIME =3D 103, > }; > =20 > #define VM_RUN \ > @@ -336,4 +351,12 @@ enum { > _IOW('v', IOCNUM_SET_INTINFO, struct vm_intinfo) > #define VM_GET_INTINFO \ > _IOWR('v', IOCNUM_GET_INTINFO, struct vm_intinfo) > +#define VM_RTC_WRITE \ > + _IOW('v', IOCNUM_RTC_WRITE, struct vm_rtc_data) > +#define VM_RTC_READ \ > + _IOWR('v', IOCNUM_RTC_READ, struct vm_rtc_data) > +#define VM_RTC_SETTIME \ > + _IOW('v', IOCNUM_RTC_SETTIME, struct vm_rtc_time) > +#define VM_RTC_GETTIME \ > + _IOR('v', IOCNUM_RTC_GETTIME, struct vm_rtc_time) > #endif >=20 > Modified: head/sys/amd64/vmm/io/vhpet.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- head/sys/amd64/vmm/io/vhpet.c Tue Dec 30 22:04:24 > 2014 (r276427) +++ head/sys/amd64/vmm/io/vhpet.c Tue > Dec 30 22:19:34 2014 (r276428) @@ -104,7 +104,6 @@ > vhpet_capabilities(void) uint64_t cap =3D 0; > =20 > cap |=3D 0x8086 << 16; /* vendor id */ > - cap |=3D HPET_CAP_LEG_RT; /* legacy > routing capable */ cap |=3D (VHPET_NUM_TIMERS - 1) << 8; /* > number of timers */ cap |=3D 1; /* > revision */ cap &=3D ~HPET_CAP_COUNT_SIZE; /* 32-bit > timer */ @@ -127,15 +126,6 @@ vhpet_timer_msi_enabled(struct vhpet *vh > { > const uint64_t msi_enable =3D HPET_TCAP_FSB_INT_DEL | > HPET_TCNF_FSB_EN;=20 > - /* > - * LegacyReplacement Route configuration takes precedence > over MSI > - * for timers 0 and 1. > - */ > - if (n =3D=3D 0 || n =3D=3D 1) { > - if (vhpet->config & HPET_CNF_LEG_RT) > - return (false); > - } > - > if ((vhpet->timer[n].cap_config & msi_enable) =3D=3D msi_enable) > return (true); > else > @@ -152,41 +142,9 @@ vhpet_timer_ioapic_pin(struct vhpet *vhp > if (vhpet_timer_msi_enabled(vhpet, n)) > return (0); > =20 > - if (vhpet->config & HPET_CNF_LEG_RT) { > - /* > - * In "legacy routing" timers 0 and 1 are connected > to > - * ioapic pins 2 and 8 respectively. > - */ > - switch (n) { > - case 0: > - return (2); > - case 1: > - return (8); > - } > - } > - > return ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ROUTE) > >> 9); } > =20 > -static __inline int > -vhpet_timer_atpic_pin(struct vhpet *vhpet, int n) > -{ > - if (vhpet->config & HPET_CNF_LEG_RT) { > - /* > - * In "legacy routing" timers 0 and 1 are connected > to > - * 8259 master pin 0 and slave pin 0 respectively. > - */ > - switch (n) { > - case 0: > - return (0); > - case 1: > - return (8); > - } > - } > - > - return (-1); > -} > - > static uint32_t > vhpet_counter(struct vhpet *vhpet, sbintime_t *nowptr) > { > @@ -216,17 +174,12 @@ vhpet_counter(struct vhpet *vhpet, sbint > static void > vhpet_timer_clear_isr(struct vhpet *vhpet, int n) > { > - int pin, legacy_pin; > + int pin; > =20 > if (vhpet->isr & (1 << n)) { > pin =3D vhpet_timer_ioapic_pin(vhpet, n); > KASSERT(pin !=3D 0, ("vhpet timer %d irq incorrectly > routed", n)); vioapic_deassert_irq(vhpet->vm, pin); > - > - legacy_pin =3D vhpet_timer_atpic_pin(vhpet, n); > - if (legacy_pin !=3D -1) > - vatpic_deassert_irq(vhpet->vm, legacy_pin); > - > vhpet->isr &=3D ~(1 << n); > } > } > @@ -252,12 +205,6 @@ vhpet_timer_edge_trig(struct vhpet *vhpe > KASSERT(!vhpet_timer_msi_enabled(vhpet, n), > ("vhpet_timer_edge_trig: " "timer %d is using MSI", n)); > =20 > - /* The legacy replacement interrupts are always edge > triggered */ > - if (vhpet->config & HPET_CNF_LEG_RT) { > - if (n =3D=3D 0 || n =3D=3D 1) > - return (true); > - } > - > if ((vhpet->timer[n].cap_config & HPET_TCNF_INT_TYPE) =3D=3D 0) > return (true); > else > @@ -267,7 +214,7 @@ vhpet_timer_edge_trig(struct vhpet *vhpe > static void > vhpet_timer_interrupt(struct vhpet *vhpet, int n) > { > - int pin, legacy_pin; > + int pin; > =20 > /* If interrupts are not enabled for this timer then just > return. */ if (!vhpet_timer_interrupt_enabled(vhpet, n)) > @@ -293,17 +240,11 @@ vhpet_timer_interrupt(struct vhpet *vhpe > return; > } > =20 > - legacy_pin =3D vhpet_timer_atpic_pin(vhpet, n); > - > if (vhpet_timer_edge_trig(vhpet, n)) { > vioapic_pulse_irq(vhpet->vm, pin); > - if (legacy_pin !=3D -1) > - vatpic_pulse_irq(vhpet->vm, legacy_pin); > } else { > vhpet->isr |=3D 1 << n; > vioapic_assert_irq(vhpet->vm, pin); > - if (legacy_pin !=3D -1) > - vatpic_assert_irq(vhpet->vm, legacy_pin); > } > } > =20 > @@ -579,6 +520,13 @@ vhpet_mmio_write(void *vm, int vcpuid, u > counter =3D vhpet_counter(vhpet, nowptr); > oldval =3D vhpet->config; > update_register(&vhpet->config, data, mask); > + > + /* > + * LegacyReplacement Routing is not supported so > clear the > + * bit explicitly. > + */ > + vhpet->config &=3D ~HPET_CNF_LEG_RT; > + > if ((oldval ^ vhpet->config) & HPET_CNF_ENABLE) { > if (vhpet_counter_enabled(vhpet)) { > vhpet_start_counting(vhpet); >=20 > Added: head/sys/amd64/vmm/io/vrtc.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D > --- /dev/null 00:00:00 1970 (empty, because file is > newly added) +++ head/sys/amd64/vmm/io/vrtc.c Tue Dec 30 > 22:19:34 2014 (r276428) @@ -0,0 +1,952 @@ > +/*- > + * Copyright (c) 2014, Neel Natu (neel@freebsd.org) > + * 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 unmodified, 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 ``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 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. > + */ > + > +#include > +__FBSDID("$FreeBSD$"); > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include > + > +#include "vmm_ktr.h" > +#include "vatpic.h" > +#include "vioapic.h" > +#include "vrtc.h" > + > +/* Register layout of the RTC */ > +struct rtcdev { > + uint8_t sec; > + uint8_t alarm_sec; > + uint8_t min; > + uint8_t alarm_min; > + uint8_t hour; > + uint8_t alarm_hour; > + uint8_t day_of_week; > + uint8_t day_of_month; > + uint8_t month; > + uint8_t year; > + uint8_t reg_a; > + uint8_t reg_b; > + uint8_t reg_c; > + uint8_t reg_d; > + uint8_t nvram[128 - 14]; > +} __packed; > +CTASSERT(sizeof(struct rtcdev) =3D=3D 128); > + > +struct vrtc { > + struct vm *vm; > + struct mtx mtx; > + struct callout callout; > + u_int addr; /* RTC register to > read or write */ > + sbintime_t base_uptime; > + time_t base_rtctime; > + struct rtcdev rtcdev; > +}; > + > +#define VRTC_LOCK(vrtc) > mtx_lock(&((vrtc)->mtx)) +#define VRTC_UNLOCK(vrtc) > mtx_unlock(&((vrtc)->mtx)) +#define VRTC_LOCKED(vrtc) > mtx_owned(&((vrtc)->mtx)) + > +/* > + * RTC time is considered "broken" if: > + * - RTC updates are halted by the guest > + * - RTC date/time fields have invalid values > + */ > +#define VRTC_BROKEN_TIME ((time_t)-1) > + > +#define RTC_IRQ 8 > +#define RTCSB_BIN 0x04 > +#define RTCSB_ALL_INTRS (RTCSB_UINTR | > RTCSB_AINTR | RTCSB_PINTR) +#define rtc_halted(vrtc) > ((vrtc->rtcdev.reg_b & RTCSB_HALT) !=3D 0) +#define > aintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b & RTCSB_AINTR) !=3D > 0) +#define pintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b > & RTCSB_PINTR) !=3D 0) +#define uintr_enabled(vrtc) > (((vrtc)->rtcdev.reg_b & RTCSB_UINTR) !=3D 0) + +static void > vrtc_callout_handler(void *arg); +static void vrtc_set_reg_c(struct > vrtc *vrtc, uint8_t newval); + > +static MALLOC_DEFINE(M_VRTC, "vrtc", "bhyve virtual rtc"); > + > +SYSCTL_DECL(_hw_vmm); > +SYSCTL_NODE(_hw_vmm, OID_AUTO, vrtc, CTLFLAG_RW, NULL, NULL); > + > +static int rtc_flag_broken_time =3D 1; > +SYSCTL_INT(_hw_vmm_vrtc, OID_AUTO, flag_broken_time, CTLFLAG_RDTUN, > + &rtc_flag_broken_time, 0, "Stop guest when invalid RTC time is > detected"); + > +static __inline bool > +divider_enabled(int reg_a) > +{ > + /* > + * The RTC is counting only when dividers are not held in > reset. > + */ > + return ((reg_a & 0x70) =3D=3D 0x20); > +} > + > +static __inline bool > +update_enabled(struct vrtc *vrtc) > +{ > + /* > + * RTC date/time can be updated only if: > + * - divider is not held in reset > + * - guest has not disabled updates > + * - the date/time fields have valid contents > + */ > + if (!divider_enabled(vrtc->rtcdev.reg_a)) > + return (false); > + > + if (rtc_halted(vrtc)) > + return (false); > + > + if (vrtc->base_rtctime =3D=3D VRTC_BROKEN_TIME) > + return (false); > + > + return (true); > +} > + > +static time_t > +vrtc_curtime(struct vrtc *vrtc) > +{ > + sbintime_t now, delta; > + time_t t; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + t =3D vrtc->base_rtctime; > + if (update_enabled(vrtc)) { > + now =3D sbinuptime(); > + delta =3D now - vrtc->base_uptime; > + KASSERT(delta >=3D 0, ("vrtc_curtime: uptime went > backwards: " > + "%#lx to %#lx", vrtc->base_uptime, now)); > + t +=3D delta / SBT_1S; > + } > + return (t); > +} > + > +static __inline uint8_t > +rtcset(struct rtcdev *rtc, int val) > +{ > + > + KASSERT(val >=3D 0 && val < 100, ("%s: invalid bin2bcd index > %d", > + __func__, val)); > + > + return ((rtc->reg_b & RTCSB_BIN) ? val : bin2bcd_data[val]); > +} > + > +static void > +secs_to_rtc(time_t rtctime, struct vrtc *vrtc, int force_update) > +{ > + struct clocktime ct; > + struct timespec ts; > + struct rtcdev *rtc; > + int hour; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + if (rtctime < 0) { > + KASSERT(rtctime =3D=3D VRTC_BROKEN_TIME, > + ("%s: invalid vrtc time %#lx", __func__, > rtctime)); > + return; > + } > + > + /* > + * If the RTC is halted then the guest has "ownership" of the > + * date/time fields. Don't update the RTC date/time fields in > + * this case (unless forced). > + */ > + if (rtc_halted(vrtc) && !force_update) > + return; > + > + ts.tv_sec =3D rtctime; > + ts.tv_nsec =3D 0; > + clock_ts_to_ct(&ts, &ct); > + > + KASSERT(ct.sec >=3D 0 && ct.sec <=3D 59, ("invalid clocktime sec > %d", > + ct.sec)); > + KASSERT(ct.min >=3D 0 && ct.min <=3D 59, ("invalid clocktime min > %d", > + ct.min)); > + KASSERT(ct.hour >=3D 0 && ct.hour <=3D 23, ("invalid clocktime > hour %d", > + ct.hour)); > + KASSERT(ct.dow >=3D 0 && ct.dow <=3D 6, ("invalid clocktime wday > %d", > + ct.dow)); > + KASSERT(ct.day >=3D 1 && ct.day <=3D 31, ("invalid clocktime > mday %d", > + ct.day)); > + KASSERT(ct.mon >=3D 1 && ct.mon <=3D 12, ("invalid clocktime > month %d", > + ct.mon)); > + KASSERT(ct.year >=3D POSIX_BASE_YEAR, ("invalid clocktime year > %d", > + ct.year)); > + > + rtc =3D &vrtc->rtcdev; > + rtc->sec =3D rtcset(rtc, ct.sec); > + rtc->min =3D rtcset(rtc, ct.min); > + > + hour =3D ct.hour; > + if ((rtc->reg_b & RTCSB_24HR) =3D=3D 0) > + hour =3D (hour % 12) + 1; /* convert to a > 12-hour format */ + > + rtc->hour =3D rtcset(rtc, hour); > + > + if ((rtc->reg_b & RTCSB_24HR) =3D=3D 0 && ct.hour >=3D 12) > + rtc->hour |=3D 0x80; /* set MSB to indicate > PM */ + > + rtc->day_of_week =3D rtcset(rtc, ct.dow + 1); > + rtc->day_of_month =3D rtcset(rtc, ct.day); > + rtc->month =3D rtcset(rtc, ct.mon); > + rtc->year =3D rtcset(rtc, ct.year % 100); > +} > + > +static int > +rtcget(struct rtcdev *rtc, int val, int *retval) > +{ > + uint8_t upper, lower; > + > + if (rtc->reg_b & RTCSB_BIN) { > + *retval =3D val; > + return (0); > + } > + > + lower =3D val & 0xf; > + upper =3D (val >> 4) & 0xf; > + > + if (lower > 9 || upper > 9) > + return (-1); > + > + *retval =3D upper * 10 + lower; > + return (0); > +} > + > +static time_t > +rtc_to_secs(struct vrtc *vrtc) > +{ > + struct clocktime ct; > + struct timespec ts; > + struct rtcdev *rtc; > + struct vm *vm; > + int error, hour, pm, year; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + vm =3D vrtc->vm; > + rtc =3D &vrtc->rtcdev; > + > + bzero(&ct, sizeof(struct clocktime)); > + > + error =3D rtcget(rtc, rtc->sec, &ct.sec); > + if (error || ct.sec < 0 || ct.sec > 59) { > + VM_CTR2(vm, "Invalid RTC sec %#x/%d", rtc->sec, > ct.sec); > + goto fail; > + } > + > + error =3D rtcget(rtc, rtc->min, &ct.min); > + if (error || ct.min < 0 || ct.min > 59) { > + VM_CTR2(vm, "Invalid RTC min %#x/%d", rtc->min, > ct.min); > + goto fail; > + } > + > + pm =3D 0; > + hour =3D rtc->hour; > + if ((rtc->reg_b & RTCSB_24HR) =3D=3D 0) { > + if (hour & 0x80) { > + hour &=3D ~0x80; > + pm =3D 1; > + } > + } > + error =3D rtcget(rtc, hour, &ct.hour); > + if ((rtc->reg_b & RTCSB_24HR) =3D=3D 0) { > + ct.hour -=3D 1; > + if (pm) > + ct.hour +=3D 12; > + } > + > + if (error || ct.hour < 0 || ct.hour > 23) { > + VM_CTR2(vm, "Invalid RTC hour %#x/%d", rtc->hour, > ct.hour); > + goto fail; > + } > + > + /* > + * Ignore 'rtc->dow' because some guests like Linux don't > bother > + * setting it at all while others like OpenBSD/i386 set it > incorrectly.=20 > + * > + * clock_ct_to_ts() does not depend on 'ct.dow' anyways so > ignore it. > + */ > + ct.dow =3D -1; > + > + error =3D rtcget(rtc, rtc->day_of_month, &ct.day); > + if (error || ct.day < 1 || ct.day > 31) { > + VM_CTR2(vm, "Invalid RTC mday %#x/%d", > rtc->day_of_month, > + ct.day); > + goto fail; > + } > + > + error =3D rtcget(rtc, rtc->month, &ct.mon); > + if (error || ct.mon < 1 || ct.mon > 12) { > + VM_CTR2(vm, "Invalid RTC month %#x/%d", rtc->month, > ct.mon); > + goto fail; > + } > + > + error =3D rtcget(rtc, rtc->year, &year); > + if (error || year < 0 || year > 99) { > + VM_CTR2(vm, "Invalid RTC year %#x/%d", rtc->year, > year); > + goto fail; > + } > + if (year >=3D 70) > + ct.year =3D 1900 + year; > + else > + ct.year =3D 2000 + year; > + > + error =3D clock_ct_to_ts(&ct, &ts); > + if (error || ts.tv_sec < 0) { > + VM_CTR3(vm, "Invalid RTC clocktime.date > %04d-%02d-%02d", > + ct.year, ct.mon, ct.day); > + VM_CTR3(vm, "Invalid RTC clocktime.time > %02d:%02d:%02d", > + ct.hour, ct.min, ct.sec); > + goto fail; > + } > + return (ts.tv_sec); /* success */ > +fail: > + return (VRTC_BROKEN_TIME); /* failure */ > +} > + > +static int > +vrtc_time_update(struct vrtc *vrtc, time_t newtime) > +{ > + struct rtcdev *rtc; > + time_t oldtime; > + uint8_t alarm_sec, alarm_min, alarm_hour; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + rtc =3D &vrtc->rtcdev; > + alarm_sec =3D rtc->alarm_sec; > + alarm_min =3D rtc->alarm_min; > + alarm_hour =3D rtc->alarm_hour; > + > + oldtime =3D vrtc->base_rtctime; > + VM_CTR2(vrtc->vm, "Updating RTC time from %#lx to %#lx", > + oldtime, newtime); > + > + if (newtime =3D=3D oldtime) > + return (0); > + > + /* > + * If 'newtime' indicates that RTC updates are disabled then > just > + * record that and return. There is no need to do alarm > interrupt > + * processing or update 'base_uptime' in this case. > + */ > + if (newtime =3D=3D VRTC_BROKEN_TIME) { > + vrtc->base_rtctime =3D VRTC_BROKEN_TIME; > + return (0); > + } > + > + /* > + * Return an error if RTC updates are halted by the guest. > + */ > + if (rtc_halted(vrtc)) { > + VM_CTR0(vrtc->vm, "RTC update halted by guest"); > + return (EBUSY); > + } > + > + do { > + /* > + * If the alarm interrupt is enabled and 'oldtime' > is valid > + * then visit all the seconds between 'oldtime' and > 'newtime' > + * to check for the alarm condition. > + * > + * Otherwise move the RTC time forward directly to > 'newtime'. > + */ > + if (aintr_enabled(vrtc) && oldtime !=3D > VRTC_BROKEN_TIME) > + vrtc->base_rtctime++; > + else > + vrtc->base_rtctime =3D newtime; > + > + if (aintr_enabled(vrtc)) { > + /* > + * Update the RTC date/time fields before > checking > + * if the alarm conditions are satisfied. > + */ > + secs_to_rtc(vrtc->base_rtctime, vrtc, 0); > + > + if ((alarm_sec >=3D 0xC0 || alarm_sec =3D=3D > rtc->sec) && > + (alarm_min >=3D 0xC0 || alarm_min =3D=3D > rtc->min) && > + (alarm_hour >=3D 0xC0 || alarm_hour =3D=3D > rtc->hour)) { > + vrtc_set_reg_c(vrtc, rtc->reg_c | > RTCIR_ALARM); > + } > + } > + } while (vrtc->base_rtctime !=3D newtime); > + > + if (uintr_enabled(vrtc)) > + vrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_UPDATE); > + > + vrtc->base_uptime =3D sbinuptime(); > + > + return (0); > +} > + > +static sbintime_t > +vrtc_freq(struct vrtc *vrtc) > +{ > + int ratesel; > + > + static sbintime_t pf[16] =3D { > + 0, > + SBT_1S / 256, > + SBT_1S / 128, > + SBT_1S / 8192, > + SBT_1S / 4096, > + SBT_1S / 2048, > + SBT_1S / 1024, > + SBT_1S / 512, > + SBT_1S / 256, > + SBT_1S / 128, > + SBT_1S / 64, > + SBT_1S / 32, > + SBT_1S / 16, > + SBT_1S / 8, > + SBT_1S / 4, > + SBT_1S / 2, > + }; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + /* > + * If both periodic and alarm interrupts are enabled then > use the > + * periodic frequency to drive the callout. The minimum > periodic > + * frequency (2 Hz) is higher than the alarm frequency (1 > Hz) so > + * piggyback the alarm on top of it. The same argument > applies to > + * the update interrupt. > + */ > + if (pintr_enabled(vrtc) && > divider_enabled(vrtc->rtcdev.reg_a)) { > + ratesel =3D vrtc->rtcdev.reg_a & 0xf; > + return (pf[ratesel]); > + } else if (aintr_enabled(vrtc) && update_enabled(vrtc)) { > + return (SBT_1S); > + } else if (uintr_enabled(vrtc) && update_enabled(vrtc)) { > + return (SBT_1S); > + } else { > + return (0); > + } > +} > + > +static void > +vrtc_callout_reset(struct vrtc *vrtc, sbintime_t freqsbt) > +{ > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + if (freqsbt =3D=3D 0) { > + if (callout_active(&vrtc->callout)) { > + VM_CTR0(vrtc->vm, "RTC callout stopped"); > + callout_stop(&vrtc->callout); > + } > + return; > + } > + VM_CTR1(vrtc->vm, "RTC callout frequency %d hz", SBT_1S / > freqsbt); > + callout_reset_sbt(&vrtc->callout, freqsbt, 0, > vrtc_callout_handler, > + vrtc, 0); > +} > + > +static void > +vrtc_callout_handler(void *arg) > +{ > + struct vrtc *vrtc =3D arg; > + sbintime_t freqsbt; > + time_t rtctime; > + int error; > + > + VM_CTR0(vrtc->vm, "vrtc callout fired"); > + > + VRTC_LOCK(vrtc); > + if (callout_pending(&vrtc->callout)) /* callout was > reset */ > + goto done; > + > + if (!callout_active(&vrtc->callout)) /* callout was > stopped */ > + goto done; > + > + callout_deactivate(&vrtc->callout); > + > + KASSERT((vrtc->rtcdev.reg_b & RTCSB_ALL_INTRS) !=3D 0, > + ("gratuitous vrtc callout")); > + > + if (pintr_enabled(vrtc)) > + vrtc_set_reg_c(vrtc, vrtc->rtcdev.reg_c | > RTCIR_PERIOD); + > + if (aintr_enabled(vrtc) || uintr_enabled(vrtc)) { > + rtctime =3D vrtc_curtime(vrtc); > + error =3D vrtc_time_update(vrtc, rtctime); > + KASSERT(error =3D=3D 0, ("%s: vrtc_time_update error %d", > + __func__, error)); > + } > + > + freqsbt =3D vrtc_freq(vrtc); > + KASSERT(freqsbt !=3D 0, ("%s: vrtc frequency cannot be zero", > __func__)); > + vrtc_callout_reset(vrtc, freqsbt); > +done: > + VRTC_UNLOCK(vrtc); > +} > + > +static __inline void > +vrtc_callout_check(struct vrtc *vrtc, sbintime_t freq) > +{ > + int active; > + > + active =3D callout_active(&vrtc->callout) ? 1 : 0; > + KASSERT((freq =3D=3D 0 && !active) || (freq !=3D 0 && active), > + ("vrtc callout %s with frequency %#lx", > + active ? "active" : "inactive", freq)); > +} > + > +static void > +vrtc_set_reg_c(struct vrtc *vrtc, uint8_t newval) > +{ > + struct rtcdev *rtc; > + int oldirqf, newirqf; > + uint8_t oldval, changed; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + rtc =3D &vrtc->rtcdev; > + newval &=3D RTCIR_ALARM | RTCIR_PERIOD | RTCIR_UPDATE; > + > + oldirqf =3D rtc->reg_c & RTCIR_INT; > + if ((aintr_enabled(vrtc) && (newval & RTCIR_ALARM) !=3D 0) || > + (pintr_enabled(vrtc) && (newval & RTCIR_PERIOD) !=3D 0) || > + (uintr_enabled(vrtc) && (newval & RTCIR_UPDATE) !=3D 0)) { > + newirqf =3D RTCIR_INT; > + } else { > + newirqf =3D 0; > + } > + > + oldval =3D rtc->reg_c; > + rtc->reg_c =3D newirqf | newval; > + changed =3D oldval ^ rtc->reg_c; > + if (changed) { > + VM_CTR2(vrtc->vm, "RTC reg_c changed from %#x to > %#x", > + oldval, rtc->reg_c); > + } > + > + if (!oldirqf && newirqf) { > + VM_CTR1(vrtc->vm, "RTC irq %d asserted", RTC_IRQ); > + vatpic_pulse_irq(vrtc->vm, RTC_IRQ); > + vioapic_pulse_irq(vrtc->vm, RTC_IRQ); > + } else if (oldirqf && !newirqf) { > + VM_CTR1(vrtc->vm, "RTC irq %d deasserted", RTC_IRQ); > + } > +} > + > +static int > +vrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval) > +{ > + struct rtcdev *rtc; > + sbintime_t oldfreq, newfreq; > + time_t curtime, rtctime; > + int error; > + uint8_t oldval, changed; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + rtc =3D &vrtc->rtcdev; > + oldval =3D rtc->reg_b; > + oldfreq =3D vrtc_freq(vrtc); > + > + rtc->reg_b =3D newval; > + changed =3D oldval ^ newval; > + if (changed) { > + VM_CTR2(vrtc->vm, "RTC reg_b changed from %#x to > %#x", > + oldval, newval); > + } > + > + if (changed & RTCSB_HALT) { > + if ((newval & RTCSB_HALT) =3D=3D 0) { > + rtctime =3D rtc_to_secs(vrtc); > + if (rtctime =3D=3D VRTC_BROKEN_TIME) { > + /* > + * Stop updating the RTC if the > date/time > + * programmed by the guest is not > correct. > + */ > + VM_CTR0(vrtc->vm, "Invalid RTC > date/time " > + "programming detected"); > + > + if (rtc_flag_broken_time) > + return (-1); > + } > + } else { > + curtime =3D vrtc_curtime(vrtc); > + KASSERT(curtime =3D=3D vrtc->base_rtctime, ("%s: > mismatch " > + "between vrtc basetime (%#lx) and > curtime (%#lx)", > + __func__, vrtc->base_rtctime, curtime)); > + > + /* > + * Force a refresh of the RTC date/time > fields so > + * they reflect the time right before the > guest set > + * the HALT bit. > + */ > + secs_to_rtc(curtime, vrtc, 1); > + > + /* > + * Updates are halted so mark 'base_rtctime' > to denote > + * that the RTC date/time is in flux. > + */ > + rtctime =3D VRTC_BROKEN_TIME; > + rtc->reg_b &=3D ~RTCSB_UINTR; > + } > + error =3D vrtc_time_update(vrtc, rtctime); > + KASSERT(error =3D=3D 0, ("vrtc_time_update error %d", > error)); > + } > + > + /* > + * Side effect of changes to the interrupt enable bits. > + */ > + if (changed & RTCSB_ALL_INTRS) > + vrtc_set_reg_c(vrtc, vrtc->rtcdev.reg_c); > + > + /* > + * Change the callout frequency if it has changed. > + */ > + newfreq =3D vrtc_freq(vrtc); > + if (newfreq !=3D oldfreq) > + vrtc_callout_reset(vrtc, newfreq); > + else > + vrtc_callout_check(vrtc, newfreq); > + > + /* > + * The side effect of bits that control the RTC date/time > format > + * is handled lazily when those fields are actually read. > + */ > + return (0); > +} > + > +static void > +vrtc_set_reg_a(struct vrtc *vrtc, uint8_t newval) > +{ > + sbintime_t oldfreq, newfreq; > + uint8_t oldval, changed; > + > + KASSERT(VRTC_LOCKED(vrtc), ("%s: vrtc not locked", > __func__)); + > + newval &=3D ~RTCSA_TUP; > + oldval =3D vrtc->rtcdev.reg_a; > + oldfreq =3D vrtc_freq(vrtc); > + > + if (divider_enabled(oldval) && !divider_enabled(newval)) { > + VM_CTR2(vrtc->vm, "RTC divider held in reset at > %#lx/%#lx", > + vrtc->base_rtctime, vrtc->base_uptime); > + } else if (!divider_enabled(oldval) && > divider_enabled(newval)) { > + /* > + * If the dividers are coming out of reset then > update > + * 'base_uptime' before this happens. This is done to > + * maintain the illusion that the RTC date/time was > frozen > + * while the dividers were disabled. > + */ > + vrtc->base_uptime =3D sbinuptime(); > + VM_CTR2(vrtc->vm, "RTC divider out of reset at > %#lx/%#lx", > + vrtc->base_rtctime, vrtc->base_uptime); > + } else { > + /* NOTHING */ > + } > + > + vrtc->rtcdev.reg_a =3D newval; > + changed =3D oldval ^ newval; > + if (changed) { > + VM_CTR2(vrtc->vm, "RTC reg_a changed from %#x to > %#x", > + oldval, newval); > + } > + > + /* > + * Side effect of changes to rate select and divider enable > bits. > + */ > + newfreq =3D vrtc_freq(vrtc); > + if (newfreq !=3D oldfreq) > + vrtc_callout_reset(vrtc, newfreq); > + else > + vrtc_callout_check(vrtc, newfreq); > +} > + > +int > +vrtc_set_time(struct vm *vm, time_t secs) > +{ > + struct vrtc *vrtc; > + int error; > + > + vrtc =3D vm_rtc(vm); > + VRTC_LOCK(vrtc); > + error =3D vrtc_time_update(vrtc, secs); > + VRTC_UNLOCK(vrtc); > + > + if (error) { > + VM_CTR2(vrtc->vm, "Error %d setting RTC time to > %#lx", error, > + secs); > + } else { > + VM_CTR1(vrtc->vm, "RTC time set to %#lx", secs); > + } > + > + return (error); > +} > + > +time_t > +vrtc_get_time(struct vm *vm) > +{ > + struct vrtc *vrtc; > + time_t t; > + > + vrtc =3D vm_rtc(vm); > + VRTC_LOCK(vrtc); > + t =3D vrtc_curtime(vrtc); > + VRTC_UNLOCK(vrtc); > + >=20 > *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** > _______________________________________________ > svn-src-all@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/svn-src-all > To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" ... /usr/local/libexec/ccache/world/cc -target x86_64-unknown-freebsd11.0 -O2 = -pipe -O3 -fvectorize -fslp-vectorize -fblocks -march=3Dnative -mmmx -msse = -msse2 -msse3 -mssse3 -mavx -maes -mpclmul -funroll-loops -march=3Dnative = -Wall -I/usr/src/lib/libvgl -std=3Dgnu99 -fstack-protector -Wsystem-headers= -Werror -Wall -Wno-format-y2k -Wno-uninitialized -Wno-pointer-sign -Wno-em= pty-body -Wno-string-plus-int -Wno-unused-const-variable -Wno-tautological-= compare -Wno-unused-value -Wno-parentheses-equality -Wno-unused-function -W= no-enum-conversion -Wno-switch -Wno-switch-enum -Wno-knr-promoted-parameter= -Qunused-arguments -c /usr/src/lib/libvgl/simple.c -o simple.o --- all_subdir_libvmmapi --- /usr/src/lib/libvmmapi/vmmapi.c:1153:21: error: variable has incomplete typ= e 'struct vm_rtc_data' struct vm_rtc_data rtcdata; ^ /usr/src/lib/libvmmapi/vmmapi.c:1153:9: note: forward declaration of 'struc= t vm_rtc_data' struct vm_rtc_data rtcdata; ^ /usr/src/lib/libvmmapi/vmmapi.c:1159:25: error: use of undeclared identifie= r 'VM_RTC_WRITE' error =3D ioctl(ctx->fd, VM_RTC_WRITE, &rtcdata); ^ /usr/src/lib/libvmmapi/vmmapi.c:1166:21: error: variable has incomplete typ= e 'struct vm_rtc_data' struct vm_rtc_data rtcdata; ^ /usr/src/lib/libvmmapi/vmmapi.c:1166:9: note: forward declaration of 'struc= t vm_rtc_data' struct vm_rtc_data rtcdata; ^ /usr/src/lib/libvmmapi/vmmapi.c:1171:25: error: use of undeclared identifie= r 'VM_RTC_READ' error =3D ioctl(ctx->fd, VM_RTC_READ, &rtcdata); ^ /usr/src/lib/libvmmapi/vmmapi.c:1180:21: error: variable has incomplete typ= e 'struct vm_rtc_time' struct vm_rtc_time rtctime; ^ /usr/src/lib/libvmmapi/vmmapi.c:1180:9: note: forward declaration of 'struc= t vm_rtc_time' struct vm_rtc_time rtctime; ^ /usr/src/lib/libvmmapi/vmmapi.c:1185:25: error: use of undeclared identifie= r 'VM_RTC_SETTIME' error =3D ioctl(ctx->fd, VM_RTC_SETTIME, &rtctime); ^ /usr/src/lib/libvmmapi/vmmapi.c:1192:21: error: variable has incomplete typ= e 'struct vm_rtc_time' struct vm_rtc_time rtctime; ^ /usr/src/lib/libvmmapi/vmmapi.c:1192:9: note: forward declaration of 'struc= t vm_rtc_time' struct vm_rtc_time rtctime; ^ /usr/src/lib/libvmmapi/vmmapi.c:1196:25: error: use of undeclared identifie= r 'VM_RTC_GETTIME' error =3D ioctl(ctx->fd, VM_RTC_GETTIME, &rtctime); ^ 8 errors generated. *** [vmmapi.So] Error code 1 make[5]: stopped in /usr/src/lib/libvmmapi 1 error make[5]: stopped in /usr/src/lib/libvmmapi *** [all_subdir_libvmmapi] Error code 2 make[4]: stopped in /usr/src/lib --- all_subdir_libunbound --- A failure has been detected in another branch of the parallel make make[5]: stopped in /usr/src/lib/libunbound *** [all_subdir_libunbound] Error code 2 make[4]: stopped in /usr/src/lib --- all_subdir_libvgl --- A failure has been detected in another branch of the parallel make make[5]: stopped in /usr/src/lib/libvgl *** [all_subdir_libvgl] Error code 2 make[4]: stopped in /usr/src/lib --- all_subdir_libstand --- A failure has been detected in another branch of the parallel make make[5]: stopped in /usr/src/lib/libstand *** [all_subdir_libstand] Error code 2 make[4]: stopped in /usr/src/lib 4 errors make[4]: stopped in /usr/src/lib A failure has been detected in another branch of the parallel make make[3]: stopped in /usr/src *** [libraries] Error code 2 make[2]: stopped in /usr/src 1 error make[2]: stopped in /usr/src *** [_libraries] Error code 2 make[1]: stopped in /usr/src 1 error make[1]: stopped in /usr/src *** [buildworld] Error code 2 make: stopped in /usr/src 1 error make: stopped in /usr/src root@nonamehost:/usr/src #=20