Merge ^/head r274961 through r276472.

This commit is contained in:
Dimitry Andric 2014-12-31 16:50:46 +00:00
commit ccd2f3b61a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/clang350-import/; revision=276473
33 changed files with 1648 additions and 478 deletions

View File

@ -4,7 +4,7 @@
The compilation of software known as FreeBSD is distributed under the
following terms:
Copyright (c) 1992-2014 The FreeBSD Project. All rights reserved.
Copyright (c) 1992-2015 The FreeBSD Project. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions

View File

@ -256,7 +256,8 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
break;
case ZPOOL_PROP_HEALTH:
(void) strlcpy(buf, "FAULTED", len);
(void) strlcpy(buf,
zpool_pool_state_to_name(POOL_STATE_UNAVAIL), len);
break;
case ZPOOL_PROP_GUID:

View File

@ -32,6 +32,7 @@
#include <gelf.h>
#include <libelf.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "_libelf.h"
@ -50,7 +51,6 @@ _libelf_load_section_headers(Elf *e, void *ehdr)
Elf64_Ehdr *eh64;
int ec, swapbytes;
unsigned char *src;
unsigned char *rawend;
size_t fsz, i, shnum;
int (*xlator)(unsigned char *_d, size_t _dsz, unsigned char *_s,
size_t _c, int _swap);
@ -61,7 +61,8 @@ _libelf_load_section_headers(Elf *e, void *ehdr)
#define CHECK_EHDR(E,EH) do { \
if (fsz != (EH)->e_shentsize || \
shoff + fsz * shnum > e->e_rawsize) { \
shnum > SIZE_MAX / fsz || \
fsz * shnum > e->e_rawsize - shoff) { \
LIBELF_SET_ERROR(HEADER, 0); \
return (0); \
} \
@ -87,7 +88,6 @@ _libelf_load_section_headers(Elf *e, void *ehdr)
swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder);
src = e->e_rawfile + shoff;
rawend = e->e_rawfile + e->e_rawsize;
/*
* If the file is using extended numbering then section #0
@ -104,8 +104,6 @@ _libelf_load_section_headers(Elf *e, void *ehdr)
}
for (; i < shnum; i++, src += fsz) {
if (src + sizeof(scn->s_shdr) > rawend)
return (0);
if ((scn = _libelf_allocate_scn(e, i)) == NULL)
return (0);

View File

@ -41,6 +41,7 @@ __RCSID("$NetBSD: t_access.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $");
#include <atf-c.h>
#ifdef __FreeBSD__
#include <sys/param.h>
#include <sys/stat.h>
#endif
@ -116,6 +117,10 @@ ATF_TC_HEAD(access_inval, tc)
ATF_TC_BODY(access_inval, tc)
{
#if defined(__FreeBSD__) && __FreeBSD_version < 1100033
atf_tc_expect_fail("arguments to access aren't validated; see "
"bug # 181155 for more details");
#endif
errno = 0;
ATF_REQUIRE(access("/usr", -1) != 0);

View File

@ -1146,3 +1146,55 @@ vm_set_intinfo(struct vmctx *ctx, int vcpu, uint64_t info1)
error = 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 = offset;
rtcdata.value = value;
error = 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 = offset;
error = ioctl(ctx->fd, VM_RTC_READ, &rtcdata);
if (error == 0)
*retval = 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 = secs;
error = 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 = ioctl(ctx->fd, VM_RTC_GETTIME, &rtctime);
if (error == 0)
*secs = rtctime.secs;
return (error);
}

View File

@ -133,6 +133,12 @@ void vm_copyin(struct vmctx *ctx, int vcpu, struct iovec *guest_iov,
void vm_copyout(struct vmctx *ctx, int vcpu, const void *host_src,
struct iovec *guest_iov, size_t len);
/* 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);

0
share/man/man4/iscsi.4 Executable file → Normal file
View File

View File

@ -286,6 +286,7 @@ int vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func);
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);
/*
* Inject exception 'vme' into the guest vcpu. This function returns 0 on

View File

@ -195,6 +195,15 @@ struct vm_intinfo {
uint64_t info2;
};
struct vm_rtc_time {
time_t secs;
};
struct vm_rtc_data {
int offset;
uint8_t value;
};
enum {
/* general routines */
IOCNUM_ABIVERS = 0,
@ -254,6 +263,12 @@ enum {
/* vm_cpuset */
IOCNUM_ACTIVATE_CPU = 90,
IOCNUM_GET_CPUSET = 91,
/* RTC */
IOCNUM_RTC_READ = 100,
IOCNUM_RTC_WRITE = 101,
IOCNUM_RTC_SETTIME = 102,
IOCNUM_RTC_GETTIME = 103,
};
#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

View File

@ -101,14 +101,22 @@
#define VM_FREEPOOL_DIRECT 1
/*
* Create two free page lists: VM_FREELIST_DEFAULT is for physical
* pages that are above the largest physical address that is
* accessible by ISA DMA and VM_FREELIST_ISADMA is for physical pages
* that are below that address.
* Create up to three free page lists: VM_FREELIST_DMA32 is for physical pages
* that have physical addresses below 4G but are not accessible by ISA DMA,
* and VM_FREELIST_ISADMA is for physical pages that are accessible by ISA
* DMA.
*/
#define VM_NFREELIST 2
#define VM_NFREELIST 3
#define VM_FREELIST_DEFAULT 0
#define VM_FREELIST_ISADMA 1
#define VM_FREELIST_DMA32 1
#define VM_FREELIST_ISADMA 2
/*
* Create the DMA32 free list only if the number of physical pages above
* physical address 4G is at least 16M, which amounts to 64GB of physical
* memory.
*/
#define VM_DMA32_NPAGES_THRESHOLD 16777216
/*
* An allocation size of 16MB is supported in order to optimize the

View File

@ -1322,9 +1322,12 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit)
if (reflect) {
/* Reflect the exception back into the guest */
bzero(&exception, sizeof(struct vm_exception));
exception.vector = idtvec;
exception.error_code_valid = errcode_valid;
exception.error_code = errcode_valid ? info1 : 0;
if (errcode_valid) {
exception.error_code = info1;
exception.error_code_valid = 1;
}
VCPU_CTR2(svm_sc->vm, vcpu, "Reflecting exception "
"%d/%#x into the guest", exception.vector,
exception.error_code);

View File

@ -104,7 +104,6 @@ vhpet_capabilities(void)
uint64_t cap = 0;
cap |= 0x8086 << 16; /* vendor id */
cap |= HPET_CAP_LEG_RT; /* legacy routing capable */
cap |= (VHPET_NUM_TIMERS - 1) << 8; /* number of timers */
cap |= 1; /* revision */
cap &= ~HPET_CAP_COUNT_SIZE; /* 32-bit timer */
@ -127,15 +126,6 @@ vhpet_timer_msi_enabled(struct vhpet *vhpet, int n)
{
const uint64_t msi_enable = HPET_TCAP_FSB_INT_DEL | HPET_TCNF_FSB_EN;
/*
* LegacyReplacement Route configuration takes precedence over MSI
* for timers 0 and 1.
*/
if (n == 0 || n == 1) {
if (vhpet->config & HPET_CNF_LEG_RT)
return (false);
}
if ((vhpet->timer[n].cap_config & msi_enable) == msi_enable)
return (true);
else
@ -152,41 +142,9 @@ vhpet_timer_ioapic_pin(struct vhpet *vhpet, int n)
if (vhpet_timer_msi_enabled(vhpet, n))
return (0);
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);
}
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, sbintime_t *nowptr)
static void
vhpet_timer_clear_isr(struct vhpet *vhpet, int n)
{
int pin, legacy_pin;
int pin;
if (vhpet->isr & (1 << n)) {
pin = vhpet_timer_ioapic_pin(vhpet, n);
KASSERT(pin != 0, ("vhpet timer %d irq incorrectly routed", n));
vioapic_deassert_irq(vhpet->vm, pin);
legacy_pin = vhpet_timer_atpic_pin(vhpet, n);
if (legacy_pin != -1)
vatpic_deassert_irq(vhpet->vm, legacy_pin);
vhpet->isr &= ~(1 << n);
}
}
@ -252,12 +205,6 @@ vhpet_timer_edge_trig(struct vhpet *vhpet, int n)
KASSERT(!vhpet_timer_msi_enabled(vhpet, n), ("vhpet_timer_edge_trig: "
"timer %d is using MSI", n));
/* The legacy replacement interrupts are always edge triggered */
if (vhpet->config & HPET_CNF_LEG_RT) {
if (n == 0 || n == 1)
return (true);
}
if ((vhpet->timer[n].cap_config & HPET_TCNF_INT_TYPE) == 0)
return (true);
else
@ -267,7 +214,7 @@ vhpet_timer_edge_trig(struct vhpet *vhpet, int n)
static void
vhpet_timer_interrupt(struct vhpet *vhpet, int n)
{
int pin, legacy_pin;
int pin;
/* 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 *vhpet, int n)
return;
}
legacy_pin = vhpet_timer_atpic_pin(vhpet, n);
if (vhpet_timer_edge_trig(vhpet, n)) {
vioapic_pulse_irq(vhpet->vm, pin);
if (legacy_pin != -1)
vatpic_pulse_irq(vhpet->vm, legacy_pin);
} else {
vhpet->isr |= 1 << n;
vioapic_assert_irq(vhpet->vm, pin);
if (legacy_pin != -1)
vatpic_assert_irq(vhpet->vm, legacy_pin);
}
}
@ -579,6 +520,13 @@ vhpet_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t val, int size,
counter = vhpet_counter(vhpet, nowptr);
oldval = vhpet->config;
update_register(&vhpet->config, data, mask);
/*
* LegacyReplacement Routing is not supported so clear the
* bit explicitly.
*/
vhpet->config &= ~HPET_CNF_LEG_RT;
if ((oldval ^ vhpet->config) & HPET_CNF_ENABLE) {
if (vhpet_counter_enabled(vhpet)) {
vhpet_start_counting(vhpet);

952
sys/amd64/vmm/io/vrtc.c Normal file
View File

@ -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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
#include <sys/cpuset.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/clock.h>
#include <sys/sysctl.h>
#include <machine/vmm.h>
#include <isa/rtc.h>
#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) == 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) != 0)
#define aintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b & RTCSB_AINTR) != 0)
#define pintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b & RTCSB_PINTR) != 0)
#define uintr_enabled(vrtc) (((vrtc)->rtcdev.reg_b & RTCSB_UINTR) != 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 = 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) == 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 == 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 = vrtc->base_rtctime;
if (update_enabled(vrtc)) {
now = sbinuptime();
delta = now - vrtc->base_uptime;
KASSERT(delta >= 0, ("vrtc_curtime: uptime went backwards: "
"%#lx to %#lx", vrtc->base_uptime, now));
t += delta / SBT_1S;
}
return (t);
}
static __inline uint8_t
rtcset(struct rtcdev *rtc, int val)
{
KASSERT(val >= 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 == 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 = rtctime;
ts.tv_nsec = 0;
clock_ts_to_ct(&ts, &ct);
KASSERT(ct.sec >= 0 && ct.sec <= 59, ("invalid clocktime sec %d",
ct.sec));
KASSERT(ct.min >= 0 && ct.min <= 59, ("invalid clocktime min %d",
ct.min));
KASSERT(ct.hour >= 0 && ct.hour <= 23, ("invalid clocktime hour %d",
ct.hour));
KASSERT(ct.dow >= 0 && ct.dow <= 6, ("invalid clocktime wday %d",
ct.dow));
KASSERT(ct.day >= 1 && ct.day <= 31, ("invalid clocktime mday %d",
ct.day));
KASSERT(ct.mon >= 1 && ct.mon <= 12, ("invalid clocktime month %d",
ct.mon));
KASSERT(ct.year >= POSIX_BASE_YEAR, ("invalid clocktime year %d",
ct.year));
rtc = &vrtc->rtcdev;
rtc->sec = rtcset(rtc, ct.sec);
rtc->min = rtcset(rtc, ct.min);
hour = ct.hour;
if ((rtc->reg_b & RTCSB_24HR) == 0)
hour = (hour % 12) + 1; /* convert to a 12-hour format */
rtc->hour = rtcset(rtc, hour);
if ((rtc->reg_b & RTCSB_24HR) == 0 && ct.hour >= 12)
rtc->hour |= 0x80; /* set MSB to indicate PM */
rtc->day_of_week = rtcset(rtc, ct.dow + 1);
rtc->day_of_month = rtcset(rtc, ct.day);
rtc->month = rtcset(rtc, ct.mon);
rtc->year = 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 = val;
return (0);
}
lower = val & 0xf;
upper = (val >> 4) & 0xf;
if (lower > 9 || upper > 9)
return (-1);
*retval = 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 = vrtc->vm;
rtc = &vrtc->rtcdev;
bzero(&ct, sizeof(struct clocktime));
error = 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 = 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 = 0;
hour = rtc->hour;
if ((rtc->reg_b & RTCSB_24HR) == 0) {
if (hour & 0x80) {
hour &= ~0x80;
pm = 1;
}
}
error = rtcget(rtc, hour, &ct.hour);
if ((rtc->reg_b & RTCSB_24HR) == 0) {
ct.hour -= 1;
if (pm)
ct.hour += 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.
*
* clock_ct_to_ts() does not depend on 'ct.dow' anyways so ignore it.
*/
ct.dow = -1;
error = 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 = 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 = 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 >= 70)
ct.year = 1900 + year;
else
ct.year = 2000 + year;
error = 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 = &vrtc->rtcdev;
alarm_sec = rtc->alarm_sec;
alarm_min = rtc->alarm_min;
alarm_hour = rtc->alarm_hour;
oldtime = vrtc->base_rtctime;
VM_CTR2(vrtc->vm, "Updating RTC time from %#lx to %#lx",
oldtime, newtime);
if (newtime == 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 == VRTC_BROKEN_TIME) {
vrtc->base_rtctime = 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 != VRTC_BROKEN_TIME)
vrtc->base_rtctime++;
else
vrtc->base_rtctime = 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 >= 0xC0 || alarm_sec == rtc->sec) &&
(alarm_min >= 0xC0 || alarm_min == rtc->min) &&
(alarm_hour >= 0xC0 || alarm_hour == rtc->hour)) {
vrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_ALARM);
}
}
} while (vrtc->base_rtctime != newtime);
if (uintr_enabled(vrtc))
vrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_UPDATE);
vrtc->base_uptime = sbinuptime();
return (0);
}
static sbintime_t
vrtc_freq(struct vrtc *vrtc)
{
int ratesel;
static sbintime_t pf[16] = {
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 = 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 == 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 = 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) != 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 = vrtc_curtime(vrtc);
error = vrtc_time_update(vrtc, rtctime);
KASSERT(error == 0, ("%s: vrtc_time_update error %d",
__func__, error));
}
freqsbt = vrtc_freq(vrtc);
KASSERT(freqsbt != 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 = callout_active(&vrtc->callout) ? 1 : 0;
KASSERT((freq == 0 && !active) || (freq != 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 = &vrtc->rtcdev;
newval &= RTCIR_ALARM | RTCIR_PERIOD | RTCIR_UPDATE;
oldirqf = rtc->reg_c & RTCIR_INT;
if ((aintr_enabled(vrtc) && (newval & RTCIR_ALARM) != 0) ||
(pintr_enabled(vrtc) && (newval & RTCIR_PERIOD) != 0) ||
(uintr_enabled(vrtc) && (newval & RTCIR_UPDATE) != 0)) {
newirqf = RTCIR_INT;
} else {
newirqf = 0;
}
oldval = rtc->reg_c;
rtc->reg_c = newirqf | newval;
changed = 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 = &vrtc->rtcdev;
oldval = rtc->reg_b;
oldfreq = vrtc_freq(vrtc);
rtc->reg_b = newval;
changed = 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) == 0) {
rtctime = rtc_to_secs(vrtc);
if (rtctime == 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 = vrtc_curtime(vrtc);
KASSERT(curtime == 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 = VRTC_BROKEN_TIME;
rtc->reg_b &= ~RTCSB_UINTR;
}
error = vrtc_time_update(vrtc, rtctime);
KASSERT(error == 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 = vrtc_freq(vrtc);
if (newfreq != 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 &= ~RTCSA_TUP;
oldval = vrtc->rtcdev.reg_a;
oldfreq = 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 = 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 = newval;
changed = 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 = vrtc_freq(vrtc);
if (newfreq != 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 = vm_rtc(vm);
VRTC_LOCK(vrtc);
error = 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 = vm_rtc(vm);
VRTC_LOCK(vrtc);
t = vrtc_curtime(vrtc);
VRTC_UNLOCK(vrtc);
return (t);
}
int
vrtc_nvram_write(struct vm *vm, int offset, uint8_t value)
{
struct vrtc *vrtc;
uint8_t *ptr;
vrtc = vm_rtc(vm);
/*
* Don't allow writes to RTC control registers or the date/time fields.
*/
if (offset < offsetof(struct rtcdev, nvram[0]) ||
offset >= sizeof(struct rtcdev)) {
VM_CTR1(vrtc->vm, "RTC nvram write to invalid offset %d",
offset);
return (EINVAL);
}
VRTC_LOCK(vrtc);
ptr = (uint8_t *)(&vrtc->rtcdev);
ptr[offset] = value;
VM_CTR2(vrtc->vm, "RTC nvram write %#x to offset %#x", value, offset);
VRTC_UNLOCK(vrtc);
return (0);
}
int
vrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval)
{
struct vrtc *vrtc;
time_t curtime;
uint8_t *ptr;
/*
* Allow all offsets in the RTC to be read.
*/
if (offset < 0 || offset >= sizeof(struct rtcdev))
return (EINVAL);
vrtc = vm_rtc(vm);
VRTC_LOCK(vrtc);
/*
* Update RTC date/time fields if necessary.
*/
if (offset < 10) {
curtime = vrtc_curtime(vrtc);
secs_to_rtc(curtime, vrtc, 0);
}
ptr = (uint8_t *)(&vrtc->rtcdev);
*retval = ptr[offset];
VRTC_UNLOCK(vrtc);
return (0);
}
int
vrtc_addr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *val)
{
struct vrtc *vrtc;
vrtc = vm_rtc(vm);
if (bytes != 1)
return (-1);
if (in) {
*val = 0xff;
return (0);
}
VRTC_LOCK(vrtc);
vrtc->addr = *val & 0x7f;
VRTC_UNLOCK(vrtc);
return (0);
}
int
vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *val)
{
struct vrtc *vrtc;
struct rtcdev *rtc;
time_t curtime;
int error, offset;
vrtc = vm_rtc(vm);
rtc = &vrtc->rtcdev;
if (bytes != 1)
return (-1);
VRTC_LOCK(vrtc);
offset = vrtc->addr;
if (offset >= sizeof(struct rtcdev)) {
VRTC_UNLOCK(vrtc);
return (-1);
}
error = 0;
curtime = vrtc_curtime(vrtc);
vrtc_time_update(vrtc, curtime);
if (in) {
/*
* Update RTC date/time fields if necessary.
*/
if (offset < 10)
secs_to_rtc(curtime, vrtc, 0);
if (offset == 12) {
/*
* XXX
* reg_c interrupt flags are updated only if the
* corresponding interrupt enable bit in reg_b is set.
*/
*val = vrtc->rtcdev.reg_c;
vrtc_set_reg_c(vrtc, 0);
} else {
*val = *((uint8_t *)rtc + offset);
}
VCPU_CTR2(vm, vcpuid, "Read value %#x from RTC offset %#x",
*val, offset);
} else {
switch (offset) {
case 10:
VCPU_CTR1(vm, vcpuid, "RTC reg_a set to %#x", *val);
vrtc_set_reg_a(vrtc, *val);
break;
case 11:
VCPU_CTR1(vm, vcpuid, "RTC reg_b set to %#x", *val);
error = vrtc_set_reg_b(vrtc, *val);
break;
case 12:
VCPU_CTR1(vm, vcpuid, "RTC reg_c set to %#x (ignored)",
*val);
break;
case 13:
VCPU_CTR1(vm, vcpuid, "RTC reg_d set to %#x (ignored)",
*val);
break;
case 0:
/*
* High order bit of 'seconds' is readonly.
*/
*val &= 0x7f;
/* FALLTHRU */
default:
VCPU_CTR2(vm, vcpuid, "RTC offset %#x set to %#x",
offset, *val);
*((uint8_t *)rtc + offset) = *val;
break;
}
}
VRTC_UNLOCK(vrtc);
return (error);
}
void
vrtc_reset(struct vrtc *vrtc)
{
struct rtcdev *rtc;
VRTC_LOCK(vrtc);
rtc = &vrtc->rtcdev;
vrtc_set_reg_b(vrtc, rtc->reg_b & ~(RTCSB_ALL_INTRS | RTCSB_SQWE));
vrtc_set_reg_c(vrtc, 0);
KASSERT(!callout_active(&vrtc->callout), ("rtc callout still active"));
VRTC_UNLOCK(vrtc);
}
struct vrtc *
vrtc_init(struct vm *vm)
{
struct vrtc *vrtc;
struct rtcdev *rtc;
time_t curtime;
vrtc = malloc(sizeof(struct vrtc), M_VRTC, M_WAITOK | M_ZERO);
vrtc->vm = vm;
mtx_init(&vrtc->mtx, "vrtc lock", NULL, MTX_DEF);
callout_init(&vrtc->callout, 1);
/* Allow dividers to keep time but disable everything else */
rtc = &vrtc->rtcdev;
rtc->reg_a = 0x20;
rtc->reg_b = RTCSB_24HR;
rtc->reg_c = 0;
rtc->reg_d = RTCSD_PWR;
/* Reset the index register to a safe value. */
vrtc->addr = RTC_STATUSD;
/*
* Initialize RTC time to 00:00:00 Jan 1, 1970.
*/
curtime = 0;
VRTC_LOCK(vrtc);
vrtc->base_rtctime = VRTC_BROKEN_TIME;
vrtc_time_update(vrtc, curtime);
secs_to_rtc(curtime, vrtc, 0);
VRTC_UNLOCK(vrtc);
return (vrtc);
}
void
vrtc_cleanup(struct vrtc *vrtc)
{
callout_drain(&vrtc->callout);
free(vrtc, M_VRTC);
}

50
sys/amd64/vmm/io/vrtc.h Normal file
View File

@ -0,0 +1,50 @@
/*-
* 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.
*
* $FreeBSD$
*/
#ifndef _VRTC_H_
#define _VRTC_H_
#include <isa/isareg.h>
struct vrtc;
struct vrtc *vrtc_init(struct vm *vm);
void vrtc_cleanup(struct vrtc *vrtc);
void vrtc_reset(struct vrtc *vrtc);
time_t vrtc_get_time(struct vm *vm);
int vrtc_set_time(struct vm *vm, time_t secs);
int vrtc_nvram_write(struct vm *vm, int offset, uint8_t value);
int vrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval);
int vrtc_addr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *val);
int vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,
uint32_t *val);
#endif

View File

@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include "vioapic.h"
#include "vlapic.h"
#include "vpmtmr.h"
#include "vrtc.h"
#include "vmm_ipi.h"
#include "vmm_stat.h"
#include "vmm_lapic.h"
@ -136,6 +137,7 @@ struct vm {
struct vatpic *vatpic; /* (i) virtual atpic */
struct vatpit *vatpit; /* (i) virtual atpit */
struct vpmtmr *vpmtmr; /* (i) virtual ACPI PM timer */
struct vrtc *vrtc; /* (o) virtual RTC */
volatile cpuset_t active_cpus; /* (i) active vcpus */
int suspend; /* (i) stop VM execution */
volatile cpuset_t suspended_cpus; /* (i) suspended vcpus */
@ -375,6 +377,8 @@ vm_init(struct vm *vm, bool create)
vm->vatpic = vatpic_init(vm);
vm->vatpit = vatpit_init(vm);
vm->vpmtmr = vpmtmr_init(vm);
if (create)
vm->vrtc = vrtc_init(vm);
CPU_ZERO(&vm->active_cpus);
@ -437,6 +441,10 @@ vm_cleanup(struct vm *vm, bool destroy)
if (vm->iommu != NULL)
iommu_destroy_domain(vm->iommu);
if (destroy)
vrtc_cleanup(vm->vrtc);
else
vrtc_reset(vm->vrtc);
vpmtmr_cleanup(vm->vpmtmr);
vatpit_cleanup(vm->vatpit);
vhpet_cleanup(vm->vhpet);
@ -2222,6 +2230,13 @@ vm_pmtmr(struct vm *vm)
return (vm->vpmtmr);
}
struct vrtc *
vm_rtc(struct vm *vm)
{
return (vm->vrtc);
}
enum vm_reg_name
vm_segment_name(int seg)
{

View File

@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include "io/vatpic.h"
#include "io/vioapic.h"
#include "io/vhpet.h"
#include "io/vrtc.h"
struct vmmdev_softc {
struct vm *vm; /* vm instance cookie */
@ -174,6 +175,8 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
struct vm_activate_cpu *vac;
struct vm_cpuset *vm_cpuset;
struct vm_intinfo *vmii;
struct vm_rtc_time *rtctime;
struct vm_rtc_data *rtcdata;
sc = vmmdev_lookup2(cdev);
if (sc == NULL)
@ -482,6 +485,25 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
error = vm_get_intinfo(sc->vm, vmii->vcpuid, &vmii->info1,
&vmii->info2);
break;
case VM_RTC_WRITE:
rtcdata = (struct vm_rtc_data *)data;
error = vrtc_nvram_write(sc->vm, rtcdata->offset,
rtcdata->value);
break;
case VM_RTC_READ:
rtcdata = (struct vm_rtc_data *)data;
error = vrtc_nvram_read(sc->vm, rtcdata->offset,
&rtcdata->value);
break;
case VM_RTC_SETTIME:
rtctime = (struct vm_rtc_time *)data;
error = vrtc_set_time(sc->vm, rtctime->secs);
break;
case VM_RTC_GETTIME:
error = 0;
rtctime = (struct vm_rtc_time *)data;
rtctime->secs = vrtc_get_time(sc->vm);
break;
default:
error = ENOTTY;
break;

View File

@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include "vatpic.h"
#include "vatpit.h"
#include "vpmtmr.h"
#include "vrtc.h"
#include "vmm_ioport.h"
#include "vmm_ktr.h"
@ -60,6 +61,8 @@ ioport_handler_func_t ioport_handler[MAX_IOPORTS] = {
[IO_ELCR1] = vatpic_elc_handler,
[IO_ELCR2] = vatpic_elc_handler,
[IO_PMTMR] = vpmtmr_handler,
[IO_RTC] = vrtc_addr_handler,
[IO_RTC + 1] = vrtc_data_handler,
};
#ifdef KTR

View File

@ -106,7 +106,7 @@ ASENTRY_NP(dcache_inv_pou_all)
bx lr
#else
mrc CP15_CLIDR(r0)
ands r0, r0, #0x07000000
ands r0, r0, #0x38000000
mov r0, r0, lsr #26 /* Get LoUU (naturally aligned) */
beq 4f

View File

@ -84,11 +84,9 @@ ASENTRY_NP(_start)
*/
mrc CP15_SCTLR(r7)
tst r7, #CPU_CONTROL_DC_ENABLE
beq 1f
bic r7, #CPU_CONTROL_DC_ENABLE
mcr CP15_SCTLR(r7)
ISB
bl dcache_wbinv_poc_all
blne dcache_wbinv_poc_all
/* ! Do not write to memory between wbinv and disabling cache ! */
/*
* Now there are no dirty lines, but there may still be lines marked
@ -96,6 +94,7 @@ ASENTRY_NP(_start)
* before setting up new page tables and re-enabling the mmu.
*/
1:
bic r7, #CPU_CONTROL_DC_ENABLE
bic r7, #CPU_CONTROL_MMU_ENABLE
bic r7, #CPU_CONTROL_IC_ENABLE
bic r7, #CPU_CONTROL_UNAL_ENABLE
@ -340,7 +339,7 @@ END(reinit_mmu)
*
* Addresses must be 1MiB aligned
*/
ASENTRY_NP(build_pagetables)
build_pagetables:
/* Set the required page attributed */
#if defined(ARM_NEW_PMAP)
ldr r4, =PTE1_V|PTE1_A|PTE1_AP_KRW|TEX1_CLASS_0
@ -521,6 +520,7 @@ ENTRY_NP(sigcode)
/* Branch back to retry SYS_sigreturn */
b . - 16
END(sigcode)
.word SYS_sigreturn
.word SYS_exit
@ -533,5 +533,5 @@ ENTRY_NP(sigcode)
.global szsigcode
szsigcode:
.long esigcode-sigcode
END(sigcode)
/* End of locore.S */

View File

@ -2776,7 +2776,8 @@ vdev_get_stats(vdev_t *vd, vdev_stat_t *vs)
vs->vs_rsize = vdev_get_min_asize(vd);
if (vd->vdev_ops->vdev_op_leaf)
vs->vs_rsize += VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE;
vs->vs_esize = vd->vdev_max_asize - vd->vdev_asize;
if (vd->vdev_max_asize != 0)
vs->vs_esize = vd->vdev_max_asize - vd->vdev_asize;
vs->vs_configured_ashift = vd->vdev_top != NULL
? vd->vdev_top->vdev_ashift : vd->vdev_ashift;
vs->vs_logical_ashift = vd->vdev_logical_ashift;

View File

@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$");
*/
#define SDHC_PCI_MODE_KEY 0xf9
#define SDHC_PCI_MODE 0x150
#define SDHC_PCI_MODE_SD20 0x10
#define SDHC_PCI_MODE_SD20 0x10
#define SDHC_PCI_BASE_FREQ_KEY 0xfc
#define SDHC_PCI_BASE_FREQ 0xe1
@ -83,8 +83,9 @@ static const struct sdhci_device {
} sdhci_devices[] = {
{ 0x08221180, 0xffff, "RICOH R5C822 SD",
SDHCI_QUIRK_FORCE_DMA },
{ 0xe8221180, 0xffff, "RICOH SD",
SDHCI_QUIRK_FORCE_DMA },
{ 0xe8221180, 0xffff, "RICOH R5CE822 SD",
SDHCI_QUIRK_FORCE_DMA |
SDHCI_QUIRK_LOWER_FREQUENCY },
{ 0xe8231180, 0xffff, "RICOH R5CE823 SD",
SDHCI_QUIRK_LOWER_FREQUENCY },
{ 0x8034104c, 0xffff, "TI XX21/XX11 SD",
@ -109,7 +110,6 @@ static const struct sdhci_device {
};
struct sdhci_pci_softc {
device_t dev; /* Controller device */
u_int quirks; /* Chip specific quirks */
struct resource *irq_res; /* IRQ resource */
void *intrhand; /* Interrupt handle */
@ -117,6 +117,8 @@ struct sdhci_pci_softc {
int num_slots; /* Number of slots on this controller */
struct sdhci_slot slots[6];
struct resource *mem_res[6]; /* Memory resource */
uint8_t cfg_freq; /* Saved mode */
uint8_t cfg_mode; /* Saved frequency */
};
static int sdhci_enable_msi = 1;
@ -206,21 +208,43 @@ static void sdhci_pci_intr(void *arg);
static void
sdhci_lower_frequency(device_t dev)
{
struct sdhci_pci_softc *sc = device_get_softc(dev);
/* Enable SD2.0 mode. */
/*
* Enable SD2.0 mode.
* NB: for RICOH R5CE823, this changes the PCI device ID to 0xe822.
*/
pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1);
sc->cfg_mode = pci_read_config(dev, SDHC_PCI_MODE, 1);
pci_write_config(dev, SDHC_PCI_MODE, SDHC_PCI_MODE_SD20, 1);
pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1);
/*
* Some SD/MMC cards don't work with the default base
* clock frequency of 200MHz. Lower it to 50Hz.
* clock frequency of 200 MHz. Lower it to 50 MHz.
*/
pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1);
sc->cfg_freq = pci_read_config(dev, SDHC_PCI_BASE_FREQ, 1);
pci_write_config(dev, SDHC_PCI_BASE_FREQ, 50, 1);
pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1);
}
static void
sdhci_restore_frequency(device_t dev)
{
struct sdhci_pci_softc *sc = device_get_softc(dev);
/* Restore mode. */
pci_write_config(dev, SDHC_PCI_MODE_KEY, 0xfc, 1);
pci_write_config(dev, SDHC_PCI_MODE, sc->cfg_mode, 1);
pci_write_config(dev, SDHC_PCI_MODE_KEY, 0x00, 1);
/* Restore frequency. */
pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x01, 1);
pci_write_config(dev, SDHC_PCI_BASE_FREQ, sc->cfg_freq, 1);
pci_write_config(dev, SDHC_PCI_BASE_FREQ_KEY, 0x00, 1);
}
static int
sdhci_pci_probe(device_t dev)
{
@ -262,7 +286,6 @@ sdhci_pci_attach(device_t dev)
uint16_t subvendor;
int bar, err, rid, slots, i;
sc->dev = dev;
model = (uint32_t)pci_get_device(dev) << 16;
model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
subvendor = pci_get_subvendor(dev);
@ -352,6 +375,18 @@ sdhci_pci_detach(device_t dev)
bus_release_resource(dev, SYS_RES_MEMORY,
rman_get_rid(sc->mem_res[i]), sc->mem_res[i]);
}
if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
sdhci_restore_frequency(dev);
return (0);
}
static int
sdhci_pci_shutdown(device_t dev)
{
struct sdhci_pci_softc *sc = device_get_softc(dev);
if (sc->quirks & SDHCI_QUIRK_LOWER_FREQUENCY)
sdhci_restore_frequency(dev);
return (0);
}
@ -397,6 +432,7 @@ static device_method_t sdhci_methods[] = {
DEVMETHOD(device_probe, sdhci_pci_probe),
DEVMETHOD(device_attach, sdhci_pci_attach),
DEVMETHOD(device_detach, sdhci_pci_detach),
DEVMETHOD(device_shutdown, sdhci_pci_shutdown),
DEVMETHOD(device_suspend, sdhci_pci_suspend),
DEVMETHOD(device_resume, sdhci_pci_resume),

View File

@ -38,7 +38,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/rwlock.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/proc.h>
@ -57,7 +57,7 @@
#define NULL_NHASH(vp) (&null_node_hashtbl[vfs_hash_index(vp) & null_hash_mask])
static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
static struct mtx null_hashmtx;
static struct rwlock null_hash_lock;
static u_long null_hash_mask;
static MALLOC_DEFINE(M_NULLFSHASH, "nullfs_hash", "NULLFS hash table");
@ -75,7 +75,7 @@ nullfs_init(vfsp)
null_node_hashtbl = hashinit(desiredvnodes, M_NULLFSHASH,
&null_hash_mask);
mtx_init(&null_hashmtx, "nullhs", NULL, MTX_DEF);
rw_init(&null_hash_lock, "nullhs");
return (0);
}
@ -84,7 +84,7 @@ nullfs_uninit(vfsp)
struct vfsconf *vfsp;
{
mtx_destroy(&null_hashmtx);
rw_destroy(&null_hash_lock);
hashdestroy(null_node_hashtbl, M_NULLFSHASH, null_hash_mask);
return (0);
}
@ -111,7 +111,7 @@ null_hashget(mp, lowervp)
* reference count (but NOT the lower vnode's VREF counter).
*/
hd = NULL_NHASH(lowervp);
mtx_lock(&null_hashmtx);
rw_rlock(&null_hash_lock);
LIST_FOREACH(a, hd, null_hash) {
if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
/*
@ -122,11 +122,11 @@ null_hashget(mp, lowervp)
*/
vp = NULLTOV(a);
vref(vp);
mtx_unlock(&null_hashmtx);
rw_runlock(&null_hash_lock);
return (vp);
}
}
mtx_unlock(&null_hashmtx);
rw_runlock(&null_hash_lock);
return (NULLVP);
}
@ -144,7 +144,7 @@ null_hashins(mp, xp)
struct vnode *ovp;
hd = NULL_NHASH(xp->null_lowervp);
mtx_lock(&null_hashmtx);
rw_wlock(&null_hash_lock);
LIST_FOREACH(oxp, hd, null_hash) {
if (oxp->null_lowervp == xp->null_lowervp &&
NULLTOV(oxp)->v_mount == mp) {
@ -154,12 +154,12 @@ null_hashins(mp, xp)
*/
ovp = NULLTOV(oxp);
vref(ovp);
mtx_unlock(&null_hashmtx);
rw_wunlock(&null_hash_lock);
return (ovp);
}
}
LIST_INSERT_HEAD(hd, xp, null_hash);
mtx_unlock(&null_hashmtx);
rw_wunlock(&null_hash_lock);
return (NULLVP);
}
@ -277,9 +277,9 @@ null_hashrem(xp)
struct null_node *xp;
{
mtx_lock(&null_hashmtx);
rw_wlock(&null_hash_lock);
LIST_REMOVE(xp, null_hash);
mtx_unlock(&null_hashmtx);
rw_wunlock(&null_hash_lock);
}
#ifdef DIAGNOSTIC

View File

@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/rwlock.h>
#include <sys/vnode.h>
static MALLOC_DEFINE(M_VFS_HASH, "vfs_hash", "VFS hash table");
@ -40,14 +41,14 @@ static MALLOC_DEFINE(M_VFS_HASH, "vfs_hash", "VFS hash table");
static LIST_HEAD(vfs_hash_head, vnode) *vfs_hash_tbl;
static LIST_HEAD(,vnode) vfs_hash_side;
static u_long vfs_hash_mask;
static struct mtx vfs_hash_mtx;
static struct rwlock vfs_hash_lock;
static void
vfs_hashinit(void *dummy __unused)
{
vfs_hash_tbl = hashinit(desiredvnodes, M_VFS_HASH, &vfs_hash_mask);
mtx_init(&vfs_hash_mtx, "vfs hash", NULL, MTX_DEF);
rw_init(&vfs_hash_lock, "vfs hash");
LIST_INIT(&vfs_hash_side);
}
@ -75,7 +76,7 @@ vfs_hash_get(const struct mount *mp, u_int hash, int flags, struct thread *td, s
int error;
while (1) {
mtx_lock(&vfs_hash_mtx);
rw_rlock(&vfs_hash_lock);
LIST_FOREACH(vp, vfs_hash_bucket(mp, hash), v_hashlist) {
if (vp->v_hash != hash)
continue;
@ -84,7 +85,7 @@ vfs_hash_get(const struct mount *mp, u_int hash, int flags, struct thread *td, s
if (fn != NULL && fn(vp, arg))
continue;
VI_LOCK(vp);
mtx_unlock(&vfs_hash_mtx);
rw_runlock(&vfs_hash_lock);
error = vget(vp, flags | LK_INTERLOCK, td);
if (error == ENOENT && (flags & LK_NOWAIT) == 0)
break;
@ -94,7 +95,7 @@ vfs_hash_get(const struct mount *mp, u_int hash, int flags, struct thread *td, s
return (0);
}
if (vp == NULL) {
mtx_unlock(&vfs_hash_mtx);
rw_runlock(&vfs_hash_lock);
*vpp = NULL;
return (0);
}
@ -105,9 +106,9 @@ void
vfs_hash_remove(struct vnode *vp)
{
mtx_lock(&vfs_hash_mtx);
rw_wlock(&vfs_hash_lock);
LIST_REMOVE(vp, v_hashlist);
mtx_unlock(&vfs_hash_mtx);
rw_wunlock(&vfs_hash_lock);
}
int
@ -118,7 +119,7 @@ vfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, stru
*vpp = NULL;
while (1) {
mtx_lock(&vfs_hash_mtx);
rw_wlock(&vfs_hash_lock);
LIST_FOREACH(vp2,
vfs_hash_bucket(vp->v_mount, hash), v_hashlist) {
if (vp2->v_hash != hash)
@ -128,13 +129,13 @@ vfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, stru
if (fn != NULL && fn(vp2, arg))
continue;
VI_LOCK(vp2);
mtx_unlock(&vfs_hash_mtx);
rw_wunlock(&vfs_hash_lock);
error = vget(vp2, flags | LK_INTERLOCK, td);
if (error == ENOENT && (flags & LK_NOWAIT) == 0)
break;
mtx_lock(&vfs_hash_mtx);
rw_wlock(&vfs_hash_lock);
LIST_INSERT_HEAD(&vfs_hash_side, vp, v_hashlist);
mtx_unlock(&vfs_hash_mtx);
rw_wunlock(&vfs_hash_lock);
vput(vp);
if (!error)
*vpp = vp2;
@ -146,7 +147,7 @@ vfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, stru
}
vp->v_hash = hash;
LIST_INSERT_HEAD(vfs_hash_bucket(vp->v_mount, hash), vp, v_hashlist);
mtx_unlock(&vfs_hash_mtx);
rw_wunlock(&vfs_hash_lock);
return (0);
}
@ -154,9 +155,9 @@ void
vfs_hash_rehash(struct vnode *vp, u_int hash)
{
mtx_lock(&vfs_hash_mtx);
rw_wlock(&vfs_hash_lock);
LIST_REMOVE(vp, v_hashlist);
LIST_INSERT_HEAD(vfs_hash_bucket(vp->v_mount, hash), vp, v_hashlist);
vp->v_hash = hash;
mtx_unlock(&vfs_hash_mtx);
rw_wunlock(&vfs_hash_lock);
}

View File

@ -160,13 +160,11 @@
#define VM_FREEPOOL_DIRECT 1
/*
* we support 2 free lists:
*
* - DEFAULT for direct mapped (KSEG0) pages.
* Note: This usage of DEFAULT may be misleading because we use
* DEFAULT for allocating direct mapped pages. The normal page
* allocations use HIGHMEM if available, and then DEFAULT.
* - HIGHMEM for other pages
* Create up to two free lists on !__mips_n64: VM_FREELIST_DEFAULT is for
* physical pages that are above the largest physical address that is
* accessible through the direct map (KSEG0) and VM_FREELIST_LOWMEM is for
* physical pages that are below that address. VM_LOWMEM_BOUNDARY is the
* physical address for the end of the direct map (KSEG0).
*/
#ifdef __mips_n64
#define VM_NFREELIST 1
@ -174,10 +172,10 @@
#define VM_FREELIST_DIRECT VM_FREELIST_DEFAULT
#else
#define VM_NFREELIST 2
#define VM_FREELIST_DEFAULT 1
#define VM_FREELIST_HIGHMEM 0
#define VM_FREELIST_DIRECT VM_FREELIST_DEFAULT
#define VM_HIGHMEM_ADDRESS ((vm_paddr_t)0x20000000)
#define VM_FREELIST_DEFAULT 0
#define VM_FREELIST_LOWMEM 1
#define VM_FREELIST_DIRECT VM_FREELIST_LOWMEM
#define VM_LOWMEM_BOUNDARY ((vm_paddr_t)0x20000000)
#endif
/*

View File

@ -35,7 +35,8 @@ SRCS+= iommu.c \
vhpet.c \
vioapic.c \
vlapic.c \
vpmtmr.c
vpmtmr.c \
vrtc.c
# intel-specific files
.PATH: ${.CURDIR}/../../amd64/vmm/intel

View File

@ -1,5 +1,5 @@
/*-
* Copyright (C) 1992-2014 The FreeBSD Project. All rights reserved.
* Copyright (C) 1992-2015 The FreeBSD Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -30,7 +30,7 @@
/* FreeBSD */
#define COPYRIGHT_FreeBSD \
"Copyright (c) 1992-2014 The FreeBSD Project.\n"
"Copyright (c) 1992-2015 The FreeBSD Project.\n"
/* Foundation */
#define TRADEMARK_Foundation \

View File

@ -101,7 +101,32 @@ MALLOC_DEFINE(M_FICT_PAGES, "vm_fictitious", "Fictitious VM pages");
static struct vm_freelist
vm_phys_free_queues[MAXMEMDOM][VM_NFREELIST][VM_NFREEPOOL][VM_NFREEORDER];
static int vm_nfreelists = VM_FREELIST_DEFAULT + 1;
static int vm_nfreelists;
/*
* Provides the mapping from VM_FREELIST_* to free list indices (flind).
*/
static int vm_freelist_to_flind[VM_NFREELIST];
CTASSERT(VM_FREELIST_DEFAULT == 0);
#ifdef VM_FREELIST_ISADMA
#define VM_ISADMA_BOUNDARY 16777216
#endif
#ifdef VM_FREELIST_DMA32
#define VM_DMA32_BOUNDARY ((vm_paddr_t)1 << 32)
#endif
/*
* Enforce the assumptions made by vm_phys_add_seg() and vm_phys_init() about
* the ordering of the free list boundaries.
*/
#if defined(VM_ISADMA_BOUNDARY) && defined(VM_LOWMEM_BOUNDARY)
CTASSERT(VM_ISADMA_BOUNDARY < VM_LOWMEM_BOUNDARY);
#endif
#if defined(VM_LOWMEM_BOUNDARY) && defined(VM_DMA32_BOUNDARY)
CTASSERT(VM_LOWMEM_BOUNDARY < VM_DMA32_BOUNDARY);
#endif
static int cnt_prezero;
SYSCTL_INT(_vm_stats_misc, OID_AUTO, cnt_prezero, CTLFLAG_RD,
@ -120,9 +145,8 @@ SYSCTL_INT(_vm, OID_AUTO, ndomains, CTLFLAG_RD,
static vm_page_t vm_phys_alloc_domain_pages(int domain, int flind, int pool,
int order);
static void _vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind,
int domain);
static void vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind);
static void _vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int domain);
static void vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end);
static int vm_phys_paddr_to_segind(vm_paddr_t pa);
static void vm_phys_split_pages(vm_page_t m, int oind, struct vm_freelist *fl,
int order);
@ -298,7 +322,7 @@ vm_freelist_rem(struct vm_freelist *fl, vm_page_t m, int order)
* Create a physical memory segment.
*/
static void
_vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind, int domain)
_vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int domain)
{
struct vm_phys_seg *seg;
@ -314,16 +338,15 @@ _vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind, int domain)
seg->start = start;
seg->end = end;
seg->domain = domain;
seg->free_queues = &vm_phys_free_queues[domain][flind];
}
static void
vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind)
vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end)
{
int i;
if (mem_affinity == NULL) {
_vm_phys_create_seg(start, end, flind, 0);
_vm_phys_create_seg(start, end, 0);
return;
}
@ -336,11 +359,11 @@ vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind)
panic("No affinity info for start %jx",
(uintmax_t)start);
if (mem_affinity[i].end >= end) {
_vm_phys_create_seg(start, end, flind,
_vm_phys_create_seg(start, end,
mem_affinity[i].domain);
break;
}
_vm_phys_create_seg(start, mem_affinity[i].end, flind,
_vm_phys_create_seg(start, mem_affinity[i].end,
mem_affinity[i].domain);
start = mem_affinity[i].end;
}
@ -352,64 +375,149 @@ vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int flind)
void
vm_phys_add_seg(vm_paddr_t start, vm_paddr_t end)
{
vm_paddr_t paddr;
KASSERT((start & PAGE_MASK) == 0,
("vm_phys_define_seg: start is not page aligned"));
KASSERT((end & PAGE_MASK) == 0,
("vm_phys_define_seg: end is not page aligned"));
/*
* Split the physical memory segment if it spans two or more free
* list boundaries.
*/
paddr = start;
#ifdef VM_FREELIST_ISADMA
if (start < 16777216) {
if (end > 16777216) {
vm_phys_create_seg(start, 16777216,
VM_FREELIST_ISADMA);
vm_phys_create_seg(16777216, end, VM_FREELIST_DEFAULT);
} else
vm_phys_create_seg(start, end, VM_FREELIST_ISADMA);
if (VM_FREELIST_ISADMA >= vm_nfreelists)
vm_nfreelists = VM_FREELIST_ISADMA + 1;
} else
if (paddr < VM_ISADMA_BOUNDARY && end > VM_ISADMA_BOUNDARY) {
vm_phys_create_seg(paddr, VM_ISADMA_BOUNDARY);
paddr = VM_ISADMA_BOUNDARY;
}
#endif
#ifdef VM_FREELIST_HIGHMEM
if (end > VM_HIGHMEM_ADDRESS) {
if (start < VM_HIGHMEM_ADDRESS) {
vm_phys_create_seg(start, VM_HIGHMEM_ADDRESS,
VM_FREELIST_DEFAULT);
vm_phys_create_seg(VM_HIGHMEM_ADDRESS, end,
VM_FREELIST_HIGHMEM);
} else
vm_phys_create_seg(start, end, VM_FREELIST_HIGHMEM);
if (VM_FREELIST_HIGHMEM >= vm_nfreelists)
vm_nfreelists = VM_FREELIST_HIGHMEM + 1;
} else
#ifdef VM_FREELIST_LOWMEM
if (paddr < VM_LOWMEM_BOUNDARY && end > VM_LOWMEM_BOUNDARY) {
vm_phys_create_seg(paddr, VM_LOWMEM_BOUNDARY);
paddr = VM_LOWMEM_BOUNDARY;
}
#endif
vm_phys_create_seg(start, end, VM_FREELIST_DEFAULT);
#ifdef VM_FREELIST_DMA32
if (paddr < VM_DMA32_BOUNDARY && end > VM_DMA32_BOUNDARY) {
vm_phys_create_seg(paddr, VM_DMA32_BOUNDARY);
paddr = VM_DMA32_BOUNDARY;
}
#endif
vm_phys_create_seg(paddr, end);
}
/*
* Initialize the physical memory allocator.
*
* Requires that vm_page_array is initialized!
*/
void
vm_phys_init(void)
{
struct vm_freelist *fl;
struct vm_phys_seg *seg;
#ifdef VM_PHYSSEG_SPARSE
long pages;
#endif
int dom, flind, oind, pind, segind;
u_long npages;
int dom, flind, freelist, oind, pind, segind;
/*
* Compute the number of free lists, and generate the mapping from the
* manifest constants VM_FREELIST_* to the free list indices.
*
* Initially, the entries of vm_freelist_to_flind[] are set to either
* 0 or 1 to indicate which free lists should be created.
*/
npages = 0;
for (segind = vm_phys_nsegs - 1; segind >= 0; segind--) {
seg = &vm_phys_segs[segind];
#ifdef VM_FREELIST_ISADMA
if (seg->end <= VM_ISADMA_BOUNDARY)
vm_freelist_to_flind[VM_FREELIST_ISADMA] = 1;
else
#endif
#ifdef VM_FREELIST_LOWMEM
if (seg->end <= VM_LOWMEM_BOUNDARY)
vm_freelist_to_flind[VM_FREELIST_LOWMEM] = 1;
else
#endif
#ifdef VM_FREELIST_DMA32
if (
#ifdef VM_DMA32_NPAGES_THRESHOLD
/*
* Create the DMA32 free list only if the amount of
* physical memory above physical address 4G exceeds the
* given threshold.
*/
npages > VM_DMA32_NPAGES_THRESHOLD &&
#endif
seg->end <= VM_DMA32_BOUNDARY)
vm_freelist_to_flind[VM_FREELIST_DMA32] = 1;
else
#endif
{
npages += atop(seg->end - seg->start);
vm_freelist_to_flind[VM_FREELIST_DEFAULT] = 1;
}
}
/* Change each entry into a running total of the free lists. */
for (freelist = 1; freelist < VM_NFREELIST; freelist++) {
vm_freelist_to_flind[freelist] +=
vm_freelist_to_flind[freelist - 1];
}
vm_nfreelists = vm_freelist_to_flind[VM_NFREELIST - 1];
KASSERT(vm_nfreelists > 0, ("vm_phys_init: no free lists"));
/* Change each entry into a free list index. */
for (freelist = 0; freelist < VM_NFREELIST; freelist++)
vm_freelist_to_flind[freelist]--;
/*
* Initialize the first_page and free_queues fields of each physical
* memory segment.
*/
#ifdef VM_PHYSSEG_SPARSE
pages = 0;
npages = 0;
#endif
for (segind = 0; segind < vm_phys_nsegs; segind++) {
seg = &vm_phys_segs[segind];
#ifdef VM_PHYSSEG_SPARSE
seg->first_page = &vm_page_array[pages];
pages += atop(seg->end - seg->start);
seg->first_page = &vm_page_array[npages];
npages += atop(seg->end - seg->start);
#else
seg->first_page = PHYS_TO_VM_PAGE(seg->start);
#endif
#ifdef VM_FREELIST_ISADMA
if (seg->end <= VM_ISADMA_BOUNDARY) {
flind = vm_freelist_to_flind[VM_FREELIST_ISADMA];
KASSERT(flind >= 0,
("vm_phys_init: ISADMA flind < 0"));
} else
#endif
#ifdef VM_FREELIST_LOWMEM
if (seg->end <= VM_LOWMEM_BOUNDARY) {
flind = vm_freelist_to_flind[VM_FREELIST_LOWMEM];
KASSERT(flind >= 0,
("vm_phys_init: LOWMEM flind < 0"));
} else
#endif
#ifdef VM_FREELIST_DMA32
if (seg->end <= VM_DMA32_BOUNDARY) {
flind = vm_freelist_to_flind[VM_FREELIST_DMA32];
KASSERT(flind >= 0,
("vm_phys_init: DMA32 flind < 0"));
} else
#endif
{
flind = vm_freelist_to_flind[VM_FREELIST_DEFAULT];
KASSERT(flind >= 0,
("vm_phys_init: DEFAULT flind < 0"));
}
seg->free_queues = &vm_phys_free_queues[seg->domain][flind];
}
/*
* Initialize the free queues.
*/
for (dom = 0; dom < vm_ndomains; dom++) {
for (flind = 0; flind < vm_nfreelists; flind++) {
for (pind = 0; pind < VM_NFREEPOOL; pind++) {
@ -419,6 +527,7 @@ vm_phys_init(void)
}
}
}
rw_init(&vm_phys_fictitious_reg_lock, "vmfctr");
}
@ -498,25 +607,29 @@ vm_phys_alloc_pages(int pool, int order)
}
/*
* Find and dequeue a free page on the given free list, with the
* specified pool and order
* Allocate a contiguous, power of two-sized set of physical pages from the
* specified free list. The free list must be specified using one of the
* manifest constants VM_FREELIST_*.
*
* The free page queues must be locked.
*/
vm_page_t
vm_phys_alloc_freelist_pages(int flind, int pool, int order)
vm_phys_alloc_freelist_pages(int freelist, int pool, int order)
{
vm_page_t m;
int dom, domain;
KASSERT(flind < VM_NFREELIST,
("vm_phys_alloc_freelist_pages: freelist %d is out of range", flind));
KASSERT(freelist < VM_NFREELIST,
("vm_phys_alloc_freelist_pages: freelist %d is out of range",
freelist));
KASSERT(pool < VM_NFREEPOOL,
("vm_phys_alloc_freelist_pages: pool %d is out of range", pool));
KASSERT(order < VM_NFREEORDER,
("vm_phys_alloc_freelist_pages: order %d is out of range", order));
for (dom = 0; dom < vm_ndomains; dom++) {
domain = vm_rr_selectdomain();
m = vm_phys_alloc_domain_pages(domain, flind, pool, order);
m = vm_phys_alloc_domain_pages(domain,
vm_freelist_to_flind[freelist], pool, order);
if (m != NULL)
return (m);
}

View File

@ -72,7 +72,7 @@ void vm_phys_add_page(vm_paddr_t pa);
void vm_phys_add_seg(vm_paddr_t start, vm_paddr_t end);
vm_page_t vm_phys_alloc_contig(u_long npages, vm_paddr_t low, vm_paddr_t high,
u_long alignment, vm_paddr_t boundary);
vm_page_t vm_phys_alloc_freelist_pages(int flind, int pool, int order);
vm_page_t vm_phys_alloc_freelist_pages(int freelist, int pool, int order);
vm_page_t vm_phys_alloc_pages(int pool, int order);
boolean_t vm_phys_domain_intersects(long mask, vm_paddr_t low, vm_paddr_t high);
int vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end,

View File

@ -634,7 +634,7 @@ usage(void)
" [-r rej-name] [-V t | nil | never] [-x number] [-z backup-ext]\n"
" [--posix] [origfile [patchfile]]\n"
" patch <patchfile\n");
my_exit(EXIT_SUCCESS);
my_exit(EXIT_FAILURE);
}
/*

View File

@ -428,7 +428,7 @@ checked_in(char *file)
void
version(void)
{
fprintf(stderr, "patch 2.0-12u10 FreeBSD\n");
printf("patch 2.0-12u10 FreeBSD\n");
my_exit(EXIT_SUCCESS);
}

View File

@ -30,10 +30,7 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <assert.h>
@ -41,47 +38,11 @@ __FBSDID("$FreeBSD$");
#include <vmmapi.h>
#include "acpi.h"
#include "inout.h"
#include "pci_lpc.h"
#include "rtc.h"
#define IO_RTC 0x70
#define IO_RTC 0x70
#define RTC_SEC 0x00 /* seconds */
#define RTC_SEC_ALARM 0x01
#define RTC_MIN 0x02
#define RTC_MIN_ALARM 0x03
#define RTC_HRS 0x04
#define RTC_HRS_ALARM 0x05
#define RTC_WDAY 0x06
#define RTC_DAY 0x07
#define RTC_MONTH 0x08
#define RTC_YEAR 0x09
#define RTC_CENTURY 0x32 /* current century */
#define RTC_STATUSA 0xA
#define RTCSA_TUP 0x80 /* time update, don't look now */
#define RTC_STATUSB 0xB
#define RTCSB_DST 0x01
#define RTCSB_24HR 0x02
#define RTCSB_BIN 0x04 /* 0 = BCD, 1 = Binary */
#define RTCSB_PINTR 0x40 /* 1 = enable periodic clock interrupt */
#define RTCSB_HALT 0x80 /* stop clock updates */
#define RTC_INTR 0x0c /* status register C (R) interrupt source */
#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
#define RTCSD_PWR 0x80 /* clock power OK */
#define RTC_NVRAM_START 0x0e
#define RTC_NVRAM_END 0x7f
#define RTC_NVRAM_SZ (128 - RTC_NVRAM_START)
#define nvoff(x) ((x) - RTC_NVRAM_START)
#define RTC_DIAG 0x0e
#define RTC_RSTCODE 0x0f
#define RTC_EQUIPMENT 0x14
#define RTC_LMEM_LSB 0x34
#define RTC_LMEM_MSB 0x35
#define RTC_HMEM_LSB 0x5b
@ -92,249 +53,30 @@ __FBSDID("$FreeBSD$");
#define m_16MB (16*1024*1024)
#define m_4GB (4ULL*1024*1024*1024)
static int addr;
static uint8_t rtc_nvram[RTC_NVRAM_SZ];
/* XXX initialize these to default values as they would be from BIOS */
static uint8_t status_a, status_b;
static struct {
uint8_t hours;
uint8_t mins;
uint8_t secs;
} rtc_alarm;
static u_char const bin2bcd_data[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99
};
#define bin2bcd(bin) (bin2bcd_data[bin])
#define rtcout(val) ((status_b & RTCSB_BIN) ? (val) : bin2bcd((val)))
static void
timevalfix(struct timeval *t1)
/*
* Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970
*
* XXX this always returns localtime to maintain compatibility with the
* original device model.
*/
static time_t
rtc_time(struct vmctx *ctx)
{
if (t1->tv_usec < 0) {
t1->tv_sec--;
t1->tv_usec += 1000000;
}
if (t1->tv_usec >= 1000000) {
t1->tv_sec++;
t1->tv_usec -= 1000000;
}
}
static void
timevalsub(struct timeval *t1, const struct timeval *t2)
{
t1->tv_sec -= t2->tv_sec;
t1->tv_usec -= t2->tv_usec;
timevalfix(t1);
}
static int
rtc_addr_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
uint32_t *eax, void *arg)
{
if (bytes != 1)
return (-1);
if (in) {
/* straight read of this register will return 0xFF */
*eax = 0xff;
return (0);
}
switch (*eax & 0x7f) {
case RTC_SEC:
case RTC_SEC_ALARM:
case RTC_MIN:
case RTC_MIN_ALARM:
case RTC_HRS:
case RTC_HRS_ALARM:
case RTC_WDAY:
case RTC_DAY:
case RTC_MONTH:
case RTC_YEAR:
case RTC_STATUSA:
case RTC_STATUSB:
case RTC_INTR:
case RTC_STATUSD:
case RTC_NVRAM_START ... RTC_NVRAM_END:
break;
default:
return (-1);
}
addr = *eax & 0x7f;
return (0);
}
static int
rtc_data_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
uint32_t *eax, void *arg)
{
int hour;
struct tm tm;
time_t t;
struct timeval cur, delta;
static struct timeval last;
static struct tm tm;
if (bytes != 1)
return (-1);
gettimeofday(&cur, NULL);
/*
* Increment the cached time only once per second so we can guarantee
* that the guest has at least one second to read the hour:min:sec
* separately and still get a coherent view of the time.
*/
delta = cur;
timevalsub(&delta, &last);
if (delta.tv_sec >= 1 && (status_b & RTCSB_HALT) == 0) {
t = cur.tv_sec;
localtime_r(&t, &tm);
last = cur;
}
if (in) {
switch (addr) {
case RTC_SEC_ALARM:
*eax = rtc_alarm.secs;
break;
case RTC_MIN_ALARM:
*eax = rtc_alarm.mins;
break;
case RTC_HRS_ALARM:
*eax = rtc_alarm.hours;
break;
case RTC_SEC:
*eax = rtcout(tm.tm_sec);
return (0);
case RTC_MIN:
*eax = rtcout(tm.tm_min);
return (0);
case RTC_HRS:
if (status_b & RTCSB_24HR)
hour = tm.tm_hour;
else
hour = (tm.tm_hour % 12) + 1;
*eax = rtcout(hour);
/*
* If we are representing time in the 12-hour format
* then set the MSB to indicate PM.
*/
if ((status_b & RTCSB_24HR) == 0 && tm.tm_hour >= 12)
*eax |= 0x80;
return (0);
case RTC_WDAY:
*eax = rtcout(tm.tm_wday + 1);
return (0);
case RTC_DAY:
*eax = rtcout(tm.tm_mday);
return (0);
case RTC_MONTH:
*eax = rtcout(tm.tm_mon + 1);
return (0);
case RTC_YEAR:
*eax = rtcout(tm.tm_year % 100);
return (0);
case RTC_STATUSA:
*eax = status_a;
return (0);
case RTC_STATUSB:
*eax = status_b;
return (0);
case RTC_INTR:
*eax = 0;
return (0);
case RTC_STATUSD:
*eax = RTCSD_PWR;
return (0);
case RTC_NVRAM_START ... RTC_NVRAM_END:
*eax = rtc_nvram[addr - RTC_NVRAM_START];
return (0);
default:
return (-1);
}
}
switch (addr) {
case RTC_STATUSA:
status_a = *eax & ~RTCSA_TUP;
break;
case RTC_STATUSB:
/* XXX not implemented yet XXX */
if (*eax & RTCSB_PINTR)
return (-1);
status_b = *eax;
break;
case RTC_STATUSD:
/* ignore write */
break;
case RTC_SEC_ALARM:
rtc_alarm.secs = *eax;
break;
case RTC_MIN_ALARM:
rtc_alarm.mins = *eax;
break;
case RTC_HRS_ALARM:
rtc_alarm.hours = *eax;
break;
case RTC_SEC:
case RTC_MIN:
case RTC_HRS:
case RTC_WDAY:
case RTC_DAY:
case RTC_MONTH:
case RTC_YEAR:
/*
* Ignore writes to the time of day registers
*/
break;
case RTC_NVRAM_START ... RTC_NVRAM_END:
rtc_nvram[addr - RTC_NVRAM_START] = *eax;
break;
default:
return (-1);
}
return (0);
time(&t);
localtime_r(&t, &tm);
return (timegm(&tm));
}
void
rtc_init(struct vmctx *ctx)
{
struct timeval cur;
struct tm tm;
size_t himem;
size_t lomem;
int err;
err = gettimeofday(&cur, NULL);
assert(err == 0);
(void) localtime_r(&cur.tv_sec, &tm);
memset(rtc_nvram, 0, sizeof(rtc_nvram));
rtc_nvram[nvoff(RTC_CENTURY)] = bin2bcd((tm.tm_year + 1900) / 100);
/* XXX init diag/reset code/equipment/checksum ? */
/*
@ -344,17 +86,22 @@ rtc_init(struct vmctx *ctx)
* 0x5b/0x5c/0x5d - 64KB chunks above 4GB
*/
lomem = (vm_get_lowmem_size(ctx) - m_16MB) / m_64KB;
rtc_nvram[nvoff(RTC_LMEM_LSB)] = lomem;
rtc_nvram[nvoff(RTC_LMEM_MSB)] = lomem >> 8;
err = vm_rtc_write(ctx, RTC_LMEM_LSB, lomem);
assert(err == 0);
err = vm_rtc_write(ctx, RTC_LMEM_MSB, lomem >> 8);
assert(err == 0);
himem = vm_get_highmem_size(ctx) / m_64KB;
rtc_nvram[nvoff(RTC_HMEM_LSB)] = himem;
rtc_nvram[nvoff(RTC_HMEM_SB)] = himem >> 8;
rtc_nvram[nvoff(RTC_HMEM_MSB)] = himem >> 16;
}
err = vm_rtc_write(ctx, RTC_HMEM_LSB, himem);
assert(err == 0);
err = vm_rtc_write(ctx, RTC_HMEM_SB, himem >> 8);
assert(err == 0);
err = vm_rtc_write(ctx, RTC_HMEM_MSB, himem >> 16);
assert(err == 0);
INOUT_PORT(rtc, IO_RTC, IOPORT_F_INOUT, rtc_addr_handler);
INOUT_PORT(rtc, IO_RTC + 1, IOPORT_F_INOUT, rtc_data_handler);
err = vm_rtc_settime(ctx, rtc_time(ctx));
assert(err == 0);
}
static void
rtc_dsdt(void)

View File

@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <string.h>
#include <getopt.h>
#include <time.h>
#include <assert.h>
#include <machine/cpufunc.h>
@ -157,6 +158,11 @@ usage(bool cpu_intel)
" [--inject-nmi]\n"
" [--force-reset]\n"
" [--force-poweroff]\n"
" [--get-rtc-time]\n"
" [--set-rtc-time=<secs>]\n"
" [--get-rtc-nvram]\n"
" [--set-rtc-nvram=<val>]\n"
" [--rtc-nvram-offset=<offset>]\n"
" [--get-active-cpus]\n"
" [--get-suspended-cpus]\n"
" [--get-intinfo]\n"
@ -220,6 +226,12 @@ usage(bool cpu_intel)
exit(1);
}
static int get_rtc_time, set_rtc_time;
static int get_rtc_nvram, set_rtc_nvram;
static int rtc_nvram_offset;
static uint8_t rtc_nvram_value;
static time_t rtc_secs;
static int get_stats, getcap, setcap, capval, get_gpa_pmap;
static int inject_nmi, assert_lapic_lvt;
static int force_reset, force_poweroff;
@ -545,6 +557,9 @@ enum {
UNASSIGN_PPTDEV,
GET_GPA_PMAP,
ASSERT_LAPIC_LVT,
SET_RTC_TIME,
SET_RTC_NVRAM,
RTC_NVRAM_OFFSET,
};
static void
@ -1269,6 +1284,11 @@ setup_options(bool cpu_intel)
{ "setcap", REQ_ARG, 0, SET_CAP },
{ "get-gpa-pmap", REQ_ARG, 0, GET_GPA_PMAP },
{ "assert-lapic-lvt", REQ_ARG, 0, ASSERT_LAPIC_LVT },
{ "get-rtc-time", NO_ARG, &get_rtc_time, 1 },
{ "set-rtc-time", REQ_ARG, 0, SET_RTC_TIME },
{ "rtc-nvram-offset", REQ_ARG, 0, RTC_NVRAM_OFFSET },
{ "get-rtc-nvram", NO_ARG, &get_rtc_nvram, 1 },
{ "set-rtc-nvram", REQ_ARG, 0, SET_RTC_NVRAM },
{ "getcap", NO_ARG, &getcap, 1 },
{ "get-stats", NO_ARG, &get_stats, 1 },
{ "get-desc-ds",NO_ARG, &get_desc_ds, 1 },
@ -1462,6 +1482,33 @@ setup_options(bool cpu_intel)
return (all_opts);
}
static const char *
wday_str(int idx)
{
static const char *weekdays[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
if (idx >= 0 && idx < 7)
return (weekdays[idx]);
else
return ("UNK");
}
static const char *
mon_str(int idx)
{
static const char *months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
if (idx >= 0 && idx < 12)
return (months[idx]);
else
return ("UNK");
}
int
main(int argc, char *argv[])
{
@ -1477,6 +1524,7 @@ main(int argc, char *argv[])
cpuset_t cpus;
bool cpu_intel;
uint64_t cs, ds, es, fs, gs, ss, tr, ldtr;
struct tm tm;
struct option *opts;
cpu_intel = cpu_vendor_intel();
@ -1594,6 +1642,17 @@ main(int argc, char *argv[])
capval = strtoul(optarg, NULL, 0);
setcap = 1;
break;
case SET_RTC_TIME:
rtc_secs = strtoul(optarg, NULL, 0);
set_rtc_time = 1;
break;
case SET_RTC_NVRAM:
rtc_nvram_value = (uint8_t)strtoul(optarg, NULL, 0);
set_rtc_nvram = 1;
break;
case RTC_NVRAM_OFFSET:
rtc_nvram_offset = strtoul(optarg, NULL, 0);
break;
case GET_GPA_PMAP:
gpa_pmap = strtoul(optarg, NULL, 0);
get_gpa_pmap = 1;
@ -1971,6 +2030,31 @@ main(int argc, char *argv[])
}
}
if (!error && set_rtc_nvram)
error = vm_rtc_write(ctx, rtc_nvram_offset, rtc_nvram_value);
if (!error && (get_rtc_nvram || get_all)) {
error = vm_rtc_read(ctx, rtc_nvram_offset, &rtc_nvram_value);
if (error == 0) {
printf("rtc nvram[%03d]: 0x%02x\n", rtc_nvram_offset,
rtc_nvram_value);
}
}
if (!error && set_rtc_time)
error = vm_rtc_settime(ctx, rtc_secs);
if (!error && (get_rtc_time || get_all)) {
error = vm_rtc_gettime(ctx, &rtc_secs);
if (error == 0) {
gmtime_r(&rtc_secs, &tm);
printf("rtc time %#lx: %s %s %02d %02d:%02d:%02d %d\n",
rtc_secs, wday_str(tm.tm_wday), mon_str(tm.tm_mon),
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1900 + tm.tm_year);
}
}
if (!error && (getcap || get_all)) {
int captype, val, getcaptype;

View File

@ -27,7 +27,7 @@
.\"
.\" Support for miscellaneous binary image activators
.\"
.Dd April 10, 2014
.Dd December 30, 2014
.Dt BINMISCCTL 8
.Os
.Sh NAME
@ -146,46 +146,148 @@ Look up and print out the activator entry identified with
Take a snapshot and print all the activator entries currently configured.
.El
.Sh EXAMPLES
Add an image activator to run the LLVM interpreter (lli) on bitcode
compiled files:
.Bd -ragged -offset indent
# binmiscctl add llvmbc --interpreter ''/usr/bin/lli --fake-argv0=#a''
--magic ''BC\\xc0\\xde'' --size 4 --set-enabled
.Ed
.Pp
Add an image activator to run the LLVM interpreter (lli) on bitcode
compiled files.
.Ar #a
gets replaced with the old
is replaced with the old
.Dv argv0
value so that 'lli' can fake its
.Dv argv0 .
Set its state to enabled.
.Pp
Set the state of the
.Ar llvmbc
image activator to disabled:
.Dl # binmiscctl disable llvmbc
.Pp
Set the state of the
.Ar llvmbc
image activator to disabled.
.Pp
image activator to enabled:
.Dl # binmiscctl enable llvmbc
.Pp
Set the state of the
.Ar llvmbc
image activator to enabled.
.Pp
.Dl # binmiscctl remove llvmbc
.Pp
Delete the
.Ar llvmbc
image activator.
.Pp
.Dl # binmiscctl lookup llvmbc
image activator:
.Dl # binmiscctl remove llvmbc
.Pp
Look up and list the record for the
.Ar llvmbc
image activator.
image activator:
.Dl # binmiscctl lookup llvmbc
.Pp
Add QEMU bsd-user program as an image activator for ARM little-endian binaries:
.Bd -literal -offset indent
# binmiscctl add armelf \e
--interpreter "/usr/local/bin/qemu-arm-static" \e
--magic "\ex7f\ex45\ex4c\ex46\ex01\ex01\ex01\ex00\ex00\ex00\e
\ex00\ex00\ex00\ex00\ex00\ex00\ex02\ex00\ex28\ex00" \e
--mask "\exff\exff\exff\exff\exff\exff\exff\ex00\exff\exff\e
\exff\exff\exff\exff\exff\exff\exfe\exff\exff\exff" \e
--size 20 --set-enabled
.Ed
.Pp
Add QEMU bsd-user program as an image activator for ARM big-endian binaries:
.Bd -literal -offset indent
# binmiscctl add armebelf \e
--interpreter "/usr/local/bin/qemu-arm-static" \e
--magic "\ex7f\ex45\ex4c\ex46\ex01\ex02\ex01\ex00\ex00\ex00\e
\ex00\ex00\ex00\ex00\ex00\ex00\ex00\ex02\ex00\ex28" \e
--mask "\exff\exff\exff\exff\exff\exff\exff\ex00\exff\exff\e
\exff\exff\exff\exff\exff\exff\exff\exfe\exff\exff" \e
--size 20 --set-enabled
.Ed
.Pp
Add QEMU bsd-user program as an image activator for MIPS32 binaries:
.Bd -literal -offset indent
# binmiscctl add mips32 \e
--interpreter "/usr/local/bin/qemu-mips-static" \e
--magic "\ex7f\ex45\ex4c\ex46\ex01\ex02\ex01\ex00\ex00\ex00\e
\ex00\ex00\ex00\ex00\ex00\ex00\ex00\ex02\ex00\ex08" \e
--mask "\exff\exff\exff\exff\exff\exff\exff\ex00\exff\exff\e
\exff\exff\exff\exff\exff\exff\exff\exfe\exff\exff" \e
--size 20 --set-enabled
.Ed
.Pp
Add QEMU bsd-user program as an image activator for MIPS64 binaries:
.Bd -literal -offset indent
# binmiscctl add mips64 \e
--interpreter "/usr/local/bin/qemu-mips64-static" \e
--magic "\ex7f\ex45\ex4c\ex46\ex02\ex02\ex01\ex00\ex00\ex00\e
\ex00\ex00\ex00\ex00\ex00\ex00\ex00\ex02\ex00\ex08" \e
--mask "\exff\exff\exff\exff\exff\exff\exff\ex00\exff\exff\e
\exff\exff\exff\exff\exff\exff\exff\exfe\exff\exff" \e
--size 20 --set-enabled
.Ed
.Pp
Add QEMU bsd-user program as an image activator for PowerPC binaries:
.Bd -literal -offset indent
# binmiscctl add powerpc \e
--interpreter "/usr/local/bin/qemu-ppc-static" \e
--magic "\ex7f\ex45\ex4c\ex46\ex01\ex02\ex01\ex00\ex00\ex00\e
\ex00\ex00\ex00\ex00\ex00\ex00\ex00\ex02\ex00\ex14" \e
--mask "\exff\exff\exff\exff\exff\exff\exff\ex00\exff\exff\e
\exff\exff\exff\exff\exff\exff\exff\exfe\exff\exff" \e
--size 20 --set-enabled
.Ed
.Pp
Add QEMU bsd-user program as an image activator for PowerPC64 binaries:
.Bd -literal -offset indent
# binmiscctl add powerpc64 \e
--interpreter "/usr/local/bin/qemu-ppc64-static" \e
--magic "\ex7f\ex45\ex4c\ex46\ex01\ex02\ex01\ex00\ex00\ex00\e
\ex00\ex00\ex00\ex00\ex00\ex00\ex00\ex02\ex00\ex15" \e
--mask "\exff\exff\exff\exff\exff\exff\exff\ex00\exff\exff\e
\exff\exff\exff\exff\exff\exff\exff\exfe\exff\exff" \e
--size 20 --set-enabled
.Ed
.Pp
Add QEMU bsd-user program as an image activator for SPARC64 binaries:
.Bd -literal -offset indent
# binmiscctl add sparc64 \e
--interpreter "/usr/local/bin/qemu-sparc64-static" \e
--magic "\ex7f\ex45\ex4c\ex46\ex02\ex02\ex01\ex00\ex00\ex00\e
\ex00\ex00\ex00\ex00\ex00\ex00\ex00\ex02\ex00\ex2b" \e
--mask "\exff\exff\exff\exff\exff\exff\exff\ex00\exff\exff\e
\exff\exff\exff\exff\exff\exff\exff\exfe\exff\exff" \e
--size 20 --set-enabled
.Ed
.Pp
.Ss "Create and use an ARMv6 chroot on an AMD64 host"
Use an existing source tree to build a chroot host with architecture
overrides:
.Bd -literal
D=/path/to/chroot
cd /usr/src
mkdir -p $D
make world TARGET=arm TARGET_ARCH=armv6 DESTDIR=$D
make distribution TARGET=arm TARGET_ARCH=armv6 DESTDIR=$D
.Ed
.Pp
With
.Pa emulators/qemu-user-static
from the
.Fx
Ports Collection, the emulator must be copied into the jail path
specified in the binmiscctl command.
Using the example above:
.Bd -literal
mkdir $D/usr/local/bin
cp /usr/local/bin/qemu-arm-static $D/usr/local/bin
.Ed
.Pp
Now the user can chroot into the environment normally, as root:
.Bd -literal
chroot $D
.Ed
.Sh SEE ALSO
.Xr lli 1 ,
.Xr execve 2
.Xr execve 2 ,
.Xr jail 8
.Sh HISTORY
The
.Cm binmiscctl