[HVM] Move RTC emulation into the hypervisor.

Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
This commit is contained in:
kfraser@localhost.localdomain committed 2006-10-18 18:35:21 +01:00
1 parent 2b30fc3c70
commit 4ca1612143
18 files changed
+712 -46

No files matched your search

+8
View File
@@ -294,7 +294,11 @@ OBJS+=gdbstub.o
endif
# qemu-dm objects
ifeq ($(ARCH),ia64)
LIBOBJS=helper2.o exec-dm.o i8259-dm.o
else
LIBOBJS=helper2.o exec-dm.o i8259-dm.o rtc-dm.o
endif
all: $(PROGS)
@@ -354,7 +358,11 @@ VL_OBJS+= ne2000.o rtl8139.o pcnet.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
ifeq ($(ARCH),ia64)
VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
else
VL_OBJS+= fdc.o serial.o pc.o
endif
VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
VL_OBJS+= usb-uhci.o
VL_OBJS+= piix4acpi.o
+107
View File
@@ -0,0 +1,107 @@
/*
* QEMU MC146818 RTC emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_CMOS
struct RTCState {
uint8_t cmos_data[128];
uint8_t cmos_index;
};
void rtc_set_memory(RTCState *s, int addr, int val)
{
if (addr >= 0 && addr <= 127)
s->cmos_data[addr] = val;
}
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
{
RTCState *s = opaque;
if ((addr & 1) == 0) {
s->cmos_index = data & 0x7f;
} else {
#ifdef DEBUG_CMOS
printf("cmos: write index=0x%02x val=0x%02x\n",
s->cmos_index, data);
#endif
s->cmos_data[s->cmos_index] = data;
}
}
static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
{
RTCState *s = opaque;
int ret;
if ((addr & 1) == 0) {
return 0xff;
} else {
ret = s->cmos_data[s->cmos_index];
#ifdef DEBUG_CMOS
printf("cmos: read index=0x%02x val=0x%02x\n",
s->cmos_index, ret);
#endif
return ret;
}
}
static void rtc_save(QEMUFile *f, void *opaque)
{
RTCState *s = opaque;
qemu_put_buffer(f, s->cmos_data, 128);
qemu_put_8s(f, &s->cmos_index);
}
static int rtc_load(QEMUFile *f, void *opaque, int version_id)
{
RTCState *s = opaque;
if (version_id != 1)
return -EINVAL;
qemu_get_buffer(f, s->cmos_data, 128);
qemu_get_8s(f, &s->cmos_index);
return 0;
}
RTCState *rtc_init(int base, int irq)
{
RTCState *s;
s = qemu_mallocz(sizeof(RTCState));
if (!s)
return NULL;
register_ioport_write(base, 2, 1, cmos_ioport_write, s);
register_ioport_read(base, 2, 1, cmos_ioport_read, s);
register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
return s;
}
void rtc_set_date(RTCState *s, const struct tm *tm) {}
+1
View File
@@ -4,6 +4,7 @@ subdir-y += vmx
obj-y += hvm.o
obj-y += i8254.o
obj-y += i8259.o
obj-y += rtc.o
obj-y += instrlen.o
obj-y += intercept.o
obj-y += io.o
+7 -4
View File
@@ -40,8 +40,10 @@
#include <asm/processor.h>
#include <asm/types.h>
#include <asm/msr.h>
#include <asm/mc146818rtc.h>
#include <asm/spinlock.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/vpit.h>
#include <asm/hvm/support.h>
#include <public/sched.h>
#include <public/hvm/ioreq.h>
@@ -277,6 +279,7 @@ void hvm_setup_platform(struct domain* d)
init_timer(&platform->pl_time.periodic_tm.timer,
pt_timer_fn, v, v->processor);
pit_init(v, cpu_khz);
rtc_init(v, RTC_PORT(0), RTC_IRQ);
}
void pic_irq_request(void *data, int level)
@@ -368,7 +371,7 @@ void hvm_hlt(unsigned long rflags)
{
struct vcpu *v = current;
struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
s_time_t next_pit = -1, next_wakeup;
s_time_t next_pt = -1, next_wakeup;
/*
* If we halt with interrupts disabled, that's a pretty sure sign that we
@@ -379,10 +382,10 @@ void hvm_hlt(unsigned long rflags)
return hvm_vcpu_down();
if ( !v->vcpu_id )
next_pit = get_scheduled(v, pt->irq, pt);
next_pt = get_scheduled(v, pt->irq, pt);
next_wakeup = get_apictime_scheduled(v);
if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 )
next_wakeup = next_pit;
if ( (next_pt != -1 && next_pt < next_wakeup) || next_wakeup == -1 )
next_wakeup = next_pt;
if ( next_wakeup != - 1 )
set_timer(&current->arch.hvm_vcpu.hlt_timer, next_wakeup);
do_sched_op_compat(SCHEDOP_block, 0);
+2 -14
View File
@@ -49,7 +49,6 @@
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
#define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
static int handle_pit_io(ioreq_t *p);
static int handle_speaker_io(ioreq_t *p);
@@ -77,17 +76,6 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
return res.ll;
}
/*
* get processor time.
* unit: TSC
*/
int64_t hvm_get_clock(struct vcpu *v)
{
uint64_t gtsc;
gtsc = hvm_get_guest_time(v);
return gtsc;
}
static int pit_get_count(PITChannelState *s)
{
uint64_t d;
@@ -215,11 +203,11 @@ static inline void pit_load_count(PITChannelState *s, int val)
switch (s->mode) {
case 2:
/* create periodic time */
s->pt = create_periodic_time (s, period, 0, 0);
s->pt = create_periodic_time (period, 0, 0, pit_time_fired, s);
break;
case 1:
/* create one shot time */
s->pt = create_periodic_time (s, period, 0, 1);
s->pt = create_periodic_time (period, 0, 1, pit_time_fired, s);
#ifdef DEBUG_PIT
printk("HVM_PIT: create one shot time.\n");
#endif
+29 -5
View File
@@ -598,23 +598,47 @@ int cpu_get_pic_interrupt(struct vcpu *v, int *type)
return intno;
}
int is_pit_irq(struct vcpu *v, int irq, int type)
int is_periodic_irq(struct vcpu *v, int irq, int type)
{
int pit_vec;
int vec;
struct periodic_time *pt =
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
struct RTCState *vrtc =
&(v->domain->arch.hvm_domain.pl_time.vrtc);
if (pt->irq == 0) { /* Is it pit irq? */
if (type == APIC_DM_EXTINT)
pit_vec = v->domain->arch.hvm_domain.vpic.pics[0].irq_base;
vec = v->domain->arch.hvm_domain.vpic.pics[0].irq_base;
else
pit_vec =
vec =
v->domain->arch.hvm_domain.vioapic.redirtbl[0].RedirForm.vector;
return (irq == pit_vec);
if (irq == vec)
return 1;
}
if (pt->irq == 8) { /* Or rtc irq? */
if (type == APIC_DM_EXTINT)
vec = v->domain->arch.hvm_domain.vpic.pics[1].irq_base;
else
vec =
v->domain->arch.hvm_domain.vioapic.redirtbl[8].RedirForm.vector;
if (irq == vec)
return is_rtc_periodic_irq(vrtc);
}
return 0;
}
int is_irq_enabled(struct vcpu *v, int irq)
{
struct hvm_vioapic *vioapic = &v->domain->arch.hvm_domain.vioapic;
struct hvm_virpic *vpic=&v->domain->arch.hvm_domain.vpic;
if (vioapic->redirtbl[irq].RedirForm.mask == 0)
return 1;
if ( irq & 8 ) {
return !( (1 << (irq&7)) & vpic->pics[1].imr);
}
+6 -8
View File
@@ -315,17 +315,14 @@ void pickup_deactive_ticks(struct periodic_time *pt)
* period: fire frequency in ns.
*/
struct periodic_time * create_periodic_time(
PITChannelState *s,
u32 period,
char irq,
char one_shot)
char one_shot,
time_cb *cb,
void *data)
{
struct vcpu *v = s->vcpu;
struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
struct periodic_time *pt = &(current->domain->arch.hvm_domain.pl_time.periodic_tm);
if ( pt->enabled ) {
if ( v->vcpu_id != 0 ) {
printk("HVM_PIT: start 2nd periodic time on non BSP!\n");
}
stop_timer (&pt->timer);
pt->enabled = 0;
}
@@ -345,7 +342,8 @@ struct periodic_time * create_periodic_time(
pt->scheduled = NOW() + period;
set_timer (&pt->timer,pt->scheduled);
pt->enabled = 1;
pt->priv = s;
pt->cb = cb;
pt->priv = data;
return pt;
}
+3 -2
View File
@@ -683,7 +683,7 @@ void hvm_interrupt_post(struct vcpu *v, int vector, int type)
struct periodic_time *pt =
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
if ( is_pit_irq(v, vector, type) ) {
if ( pt->enabled && is_periodic_irq(v, vector, type) ) {
if ( !pt->first_injected ) {
pt->pending_intr_nr = 0;
pt->last_plt_gtime = hvm_get_guest_time(v);
@@ -694,8 +694,9 @@ void hvm_interrupt_post(struct vcpu *v, int vector, int type)
pt->pending_intr_nr--;
pt->last_plt_gtime += pt->period_cycles;
hvm_set_guest_time(v, pt->last_plt_gtime);
pit_time_fired(v, pt->priv);
}
if (pt->cb)
pt->cb(v, pt->priv);
}
switch(type) {
+393
View File
@@ -0,0 +1,393 @@
/*
* QEMU MC146818 RTC emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <asm/mc146818rtc.h>
#include <asm/hvm/vpit.h>
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
#include <asm/current.h>
/* #define DEBUG_RTC */
void rtc_periodic_cb(struct vcpu *v, void *opaque)
{
RTCState *s = opaque;
s->cmos_data[RTC_REG_C] |= 0xc0;
}
int is_rtc_periodic_irq(void *opaque)
{
RTCState *s = opaque;
return !(s->cmos_data[RTC_REG_C] & RTC_AF ||
s->cmos_data[RTC_REG_C] & RTC_UF);
}
static void rtc_timer_update(RTCState *s, int64_t current_time)
{
int period_code;
int period;
period_code = s->cmos_data[RTC_REG_A] & 0x0f;
if (period_code != 0 && (s->cmos_data[RTC_REG_B] & RTC_PIE)) {
if (period_code <= 2)
period_code += 7;
period = 1 << (period_code - 1); /* period in 32 Khz cycles */
period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
#ifdef DEBUG_RTC
printk("HVM_RTC: period = %uns\n", period);
#endif
s->pt = create_periodic_time(period, RTC_IRQ, 0, rtc_periodic_cb, s);
} else if (s->pt) {
destroy_periodic_time(s->pt);
s->pt = NULL;
}
}
static void rtc_set_time(RTCState *s);
static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data)
{
RTCState *s = opaque;
if ((addr & 1) == 0) {
s->cmos_index = data & 0x7f;
if (s->cmos_index < RTC_SIZE)
return 1;
} else if (s->cmos_index < RTC_SIZE) {
#ifdef DEBUG_RTC
printk("HVM_RTC: write index=0x%02x val=0x%02x\n",
s->cmos_index, data);
#endif
switch(s->cmos_index) {
case RTC_SECONDS_ALARM:
case RTC_MINUTES_ALARM:
case RTC_HOURS_ALARM:
s->cmos_data[s->cmos_index] = data;
break;
case RTC_SECONDS:
case RTC_MINUTES:
case RTC_HOURS:
case RTC_DAY_OF_WEEK:
case RTC_DAY_OF_MONTH:
case RTC_MONTH:
case RTC_YEAR:
s->cmos_data[s->cmos_index] = data;
/* if in set mode, do not update the time */
if (!(s->cmos_data[RTC_REG_B] & RTC_SET)) {
rtc_set_time(s);
}
break;
case RTC_REG_A:
/* UIP bit is read only */
s->cmos_data[RTC_REG_A] = (data & ~RTC_UIP) |
(s->cmos_data[RTC_REG_A] & RTC_UIP);
rtc_timer_update(s, hvm_get_clock(s->vcpu));
break;
case RTC_REG_B:
if (data & RTC_SET) {
/* set mode: reset UIP mode */
s->cmos_data[RTC_REG_A] &= ~RTC_UIP;
data &= ~RTC_UIE;
} else {
/* if disabling set mode, update the time */
if (s->cmos_data[RTC_REG_B] & RTC_SET) {
rtc_set_time(s);
}
}
s->cmos_data[RTC_REG_B] = data;
rtc_timer_update(s, hvm_get_clock(s->vcpu));
break;
case RTC_REG_C:
case RTC_REG_D:
/* cannot write to them */
break;
return 1;
}
}
return 0;
}
static inline int to_bcd(RTCState *s, int a)
{
if (s->cmos_data[RTC_REG_B] & 0x04) {
return a;
} else {
return ((a / 10) << 4) | (a % 10);
}
}
static inline int from_bcd(RTCState *s, int a)
{
if (s->cmos_data[RTC_REG_B] & 0x04) {
return a;
} else {
return ((a >> 4) * 10) + (a & 0x0f);
}
}
static void rtc_set_time(RTCState *s)
{
struct tm *tm = &s->current_tm;
tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
(s->cmos_data[RTC_HOURS] & 0x80)) {
tm->tm_hour += 12;
}
tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
}
static void rtc_copy_date(RTCState *s)
{
const struct tm *tm = &s->current_tm;
s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
if (s->cmos_data[RTC_REG_B] & 0x02) {
/* 24 hour format */
s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
} else {
/* 12 hour format */
s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
if (tm->tm_hour >= 12)
s->cmos_data[RTC_HOURS] |= 0x80;
}
s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
}
/* month is between 0 and 11. */
static int get_days_in_month(int month, int year)
{
static const int days_tab[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int d;
if ((unsigned )month >= 12)
return 31;
d = days_tab[month];
if (month == 1) {
if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
d++;
}
return d;
}
/* update 'tm' to the next second */
static void rtc_next_second(struct tm *tm)
{
int days_in_month;
tm->tm_sec++;
if ((unsigned)tm->tm_sec >= 60) {
tm->tm_sec = 0;
tm->tm_min++;
if ((unsigned)tm->tm_min >= 60) {
tm->tm_min = 0;
tm->tm_hour++;
if ((unsigned)tm->tm_hour >= 24) {
tm->tm_hour = 0;
/* next day */
tm->tm_wday++;
if ((unsigned)tm->tm_wday >= 7)
tm->tm_wday = 0;
days_in_month = get_days_in_month(tm->tm_mon,
tm->tm_year + 1900);
tm->tm_mday++;
if (tm->tm_mday < 1) {
tm->tm_mday = 1;
} else if (tm->tm_mday > days_in_month) {
tm->tm_mday = 1;
tm->tm_mon++;
if (tm->tm_mon >= 12) {
tm->tm_mon = 0;
tm->tm_year++;
}
}
}
}
}
}
static void rtc_update_second(void *opaque)
{
RTCState *s = opaque;
/* if the oscillator is not in normal operation, we do not update */
if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
s->next_second_time += 1000000000ULL;
set_timer(&s->second_timer, s->next_second_time);
} else {
rtc_next_second(&s->current_tm);
if (!(s->cmos_data[RTC_REG_B] & RTC_SET)) {
/* update in progress bit */
s->cmos_data[RTC_REG_A] |= RTC_UIP;
}
/* Delay time before update cycle */
set_timer(&s->second_timer2, s->next_second_time + 244000);
}
}
static void rtc_update_second2(void *opaque)
{
RTCState *s = opaque;
struct hvm_domain *plat=&s->vcpu->domain->arch.hvm_domain;
struct hvm_virpic *pic= &plat->vpic;
if (!(s->cmos_data[RTC_REG_B] & RTC_SET)) {
rtc_copy_date(s);
}
/* check alarm */
if (s->cmos_data[RTC_REG_B] & RTC_AIE) {
if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
s->cmos_data[RTC_REG_C] |= 0xa0;
pic_set_irq(pic, s->irq, 0);
pic_set_irq(pic, s->irq, 1);
}
}
/* update ended interrupt */
if (s->cmos_data[RTC_REG_B] & RTC_UIE) {
s->cmos_data[RTC_REG_C] |= 0x90;
pic_set_irq(pic, s->irq, 0);
pic_set_irq(pic, s->irq, 1);
}
/* clear update in progress bit */
s->cmos_data[RTC_REG_A] &= ~RTC_UIP;
s->next_second_time += 1000000000ULL;
set_timer(&s->second_timer, s->next_second_time);
}
static uint32_t rtc_ioport_read(void *opaque, uint32_t addr)
{
RTCState *s = opaque;
struct hvm_domain *plat=&s->vcpu->domain->arch.hvm_domain;
struct hvm_virpic *pic= &plat->vpic;
int ret;
if ((addr & 1) == 0) {
return 0xff;
} else {
switch(s->cmos_index) {
case RTC_SECONDS:
case RTC_MINUTES:
case RTC_HOURS:
case RTC_DAY_OF_WEEK:
case RTC_DAY_OF_MONTH:
case RTC_MONTH:
case RTC_YEAR:
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_A:
ret = s->cmos_data[s->cmos_index];
break;
case RTC_REG_C:
ret = s->cmos_data[s->cmos_index];
pic_set_irq(pic, s->irq, 0);
s->cmos_data[RTC_REG_C] = 0x00;
break;
default:
ret = s->cmos_data[s->cmos_index];
break;
}
#ifdef DEBUG_RTC
printk("HVM_RTC: read index=0x%02x val=0x%02x\n",
s->cmos_index, ret);
#endif
return ret;
}
}
static int handle_rtc_io(ioreq_t *p)
{
struct vcpu *v = current;
struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
if (p->size != 1 ||
p->pdata_valid ||
p->type != IOREQ_TYPE_PIO){
printk("HVM_RTC: wrong RTC IO!\n");
return 1;
}
if (p->dir == 0) { /* write */
if (rtc_ioport_write(vrtc, p->addr, p->u.data & 0xFF))
return 1;
} else if (p->dir == 1 && vrtc->cmos_index < RTC_SIZE) { /* read */
p->u.data = rtc_ioport_read(vrtc, p->addr);
return 1;
}
return 0;
}
void rtc_init(struct vcpu *v, int base, int irq)
{
RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
s->vcpu = v;
s->irq = irq;
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
s->current_tm = gmtime(get_localtime(v->domain));
rtc_copy_date(s);
init_timer(&s->second_timer, rtc_update_second, s, v->processor);
init_timer(&s->second_timer2, rtc_update_second2, s, v->processor);
s->next_second_time = NOW() + 1000000000ULL;
set_timer(&s->second_timer2, s->next_second_time);
register_portio_handler(base, 2, handle_rtc_io);
}
void rtc_deinit(struct domain *d)
{
RTCState *s = &d->arch.hvm_domain.pl_time.vrtc;
kill_timer(&s->second_timer);
kill_timer(&s->second_timer2);
}
+2 -2
View File
@@ -140,8 +140,8 @@ asmlinkage void svm_intr_assist(void)
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
/* Re-injecting a PIT interruptt? */
if (re_injecting &&
is_pit_irq(v, intr_vector, intr_type)) {
if (re_injecting && pt->enabled &&
is_periodic_irq(v, intr_vector, intr_type)) {
++pt->pending_intr_nr;
}
/* let's inject this interrupt */
+4
View File
@@ -921,6 +921,7 @@ static void svm_relinquish_guest_resources(struct domain *d)
}
kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
rtc_deinit(d);
if ( d->arch.hvm_domain.shared_page_va )
unmap_domain_page_global(
@@ -935,6 +936,7 @@ static void svm_migrate_timers(struct vcpu *v)
{
struct periodic_time *pt =
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
if ( pt->enabled )
{
@@ -943,6 +945,8 @@ static void svm_migrate_timers(struct vcpu *v)
}
if ( VLAPIC(v) != NULL )
migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor);
migrate_timer(&vrtc->second_timer, v->processor);
migrate_timer(&vrtc->second_timer2, v->processor);
}
+4
View File
@@ -146,6 +146,7 @@ static void vmx_relinquish_guest_resources(struct domain *d)
}
kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
rtc_deinit(d);
if ( d->arch.hvm_domain.shared_page_va )
unmap_domain_page_global(
@@ -487,6 +488,7 @@ static void stop_vmx(void)
void vmx_migrate_timers(struct vcpu *v)
{
struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
if ( pt->enabled )
{
@@ -495,6 +497,8 @@ void vmx_migrate_timers(struct vcpu *v)
}
if ( VLAPIC(v) != NULL )
migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor);
migrate_timer(&vrtc->second_timer, v->processor);
migrate_timer(&vrtc->second_timer2, v->processor);
}
static void vmx_store_cpu_guest_regs(
+7
View File
@@ -919,6 +919,13 @@ void send_timer_event(struct vcpu *v)
send_guest_vcpu_virq(v, VIRQ_TIMER);
}
/* Return secs after 00:00:00 localtime, 1 January, 1970. */
unsigned long get_localtime(struct domain *d)
{
return wc_sec + (wc_nsec + NOW()) / 1000000000ULL
+ d->time_offset_seconds;
}
/*
* Local variables:
* mode: C
+2 -1
View File
@@ -20,8 +20,9 @@ obj-y += softirq.o
obj-y += string.o
obj-y += symbols.o
obj-y += sysctl.o
obj-y += trace.o
obj-y += time.o
obj-y += timer.o
obj-y += trace.o
obj-y += version.o
obj-y += vsprintf.o
obj-y += xmalloc.o
+77
View File
@@ -0,0 +1,77 @@
/******************************************************************************
* time.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <xen/config.h>
#include <xen/time.h>
/* Nonzero if YEAR is a leap year (every 4 years,
except every 100th isn't, and every 400th is). */
#define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
/* How many days are in each month. */
const unsigned short int __mon_lengths[2][12] = {
/* Normal years. */
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
/* Leap years. */
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
struct tm gmtime(unsigned long t)
{
struct tm tbuf;
long days, rem;
int y;
unsigned short int *ip;
days = t / SECS_PER_DAY;
rem = t % SECS_PER_DAY;
tbuf.tm_hour = rem / SECS_PER_HOUR;
rem %= SECS_PER_HOUR;
tbuf.tm_min = rem / 60;
tbuf.tm_sec = rem % 60;
/* January 1, 1970 was a Thursday. */
tbuf.tm_wday = (4 + days) % 7;
if ( tbuf.tm_wday < 0 )
tbuf.tm_wday += 7;
y = 1970;
while ( days >= (rem = __isleap(y) ? 366 : 365) )
{
++y;
days -= rem;
}
while ( days < 0 )
{
--y;
days += __isleap(y) ? 366 : 365;
}
tbuf.tm_year = y - 1900;
tbuf.tm_yday = days;
ip = (unsigned short int *)__mon_lengths[__isleap(y)];
for ( y = 0; days >= ip[y]; ++y )
days -= ip[y];
tbuf.tm_mon = y;
tbuf.tm_mday = days + 1;
tbuf.tm_isdst = -1;
return tbuf;
}
+1 -1
View File
@@ -75,7 +75,7 @@ void pic_update_irq(struct hvm_virpic *s); /* Caller must hold s->lock */
uint32_t pic_intack_read(struct hvm_virpic *s);
void register_pic_io_hook (void);
int cpu_get_pic_interrupt(struct vcpu *v, int *type);
int is_pit_irq(struct vcpu *v, int irq, int type);
int is_periodic_irq(struct vcpu *v, int irq, int type);
int is_irq_enabled(struct vcpu *v, int irq);
void do_pic_irqs (struct hvm_virpic *s, uint16_t irqs);
void do_pic_irqs_clear (struct hvm_virpic *s, uint16_t irqs);
+45 -9
View File
@@ -25,6 +25,7 @@
#include <xen/lib.h>
#include <xen/time.h>
#include <xen/errno.h>
#include <xen/time.h>
#include <xen/timer.h>
#include <asm/hvm/vpic.h>
@@ -50,9 +51,31 @@ typedef struct PITChannelState {
struct periodic_time *pt;
} PITChannelState;
typedef struct PITState {
PITChannelState channels[3];
int speaker_data_on;
int dummy_refresh_clock;
} PITState;
#define RTC_SIZE 14
typedef struct RTCState {
uint8_t cmos_data[RTC_SIZE]; /* Only handle time/interrupt part in HV */
uint8_t cmos_index;
struct tm current_tm;
int irq;
/* second update */
int64_t next_second_time;
struct timer second_timer;
struct timer second_timer2;
struct vcpu *vcpu;
struct periodic_time *pt;
} RTCState;
/*
* Abstract layer of periodic time, one short time.
*/
typedef void time_cb(struct vcpu *v, void *opaque);
struct periodic_time {
char enabled; /* enabled */
char one_shot; /* one shot time */
@@ -64,19 +87,15 @@ struct periodic_time {
s_time_t scheduled; /* scheduled timer interrupt */
u64 last_plt_gtime; /* platform time when last IRQ is injected */
struct timer timer; /* ac_timer */
time_cb *cb;
void *priv; /* ponit back to platform time source */
};
typedef struct PITState {
PITChannelState channels[3];
int speaker_data_on;
int dummy_refresh_clock;
} PITState;
struct pl_time { /* platform time */
struct periodic_time periodic_tm;
struct PITState vpit;
/* TODO: RTC/ACPI time */
struct RTCState vrtc;
/* TODO: ACPI time */
};
static __inline__ s_time_t get_scheduled(
@@ -90,13 +109,30 @@ static __inline__ s_time_t get_scheduled(
return -1;
}
extern u64 hvm_get_guest_time(struct vcpu *v);
/*
* get processor time.
* unit: TSC
*/
static __inline__ int64_t hvm_get_clock(struct vcpu *v)
{
uint64_t gtsc;
gtsc = hvm_get_guest_time(v);
return gtsc;
}
#define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
/* to hook the ioreq packet to get the PIT initialization info */
extern void hvm_hooks_assist(struct vcpu *v);
extern void pickup_deactive_ticks(struct periodic_time *vpit);
extern u64 hvm_get_guest_time(struct vcpu *v);
extern struct periodic_time *create_periodic_time(PITChannelState *v, u32 period, char irq, char one_shot);
extern struct periodic_time *create_periodic_time(u32 period, char irq, char one_shot, time_cb *cb, void *data);
extern void destroy_periodic_time(struct periodic_time *pt);
void pit_init(struct vcpu *v, unsigned long cpu_khz);
void rtc_init(struct vcpu *v, int base, int irq);
void rtc_deinit(struct domain *d);
int is_rtc_periodic_irq(void *opaque);
void pt_timer_fn(void *data);
void pit_time_fired(struct vcpu *v, void *priv);
+14
View File
@@ -49,6 +49,20 @@ struct domain;
typedef s64 s_time_t;
s_time_t get_s_time(void);
unsigned long get_localtime(struct domain *d);
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
struct tm gmtime(unsigned long t);
#define NOW() ((s_time_t)get_s_time())
#define SECONDS(_s) ((s_time_t)((_s) * 1000000000ULL))
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.