[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [HVM] Move RTC emulation into the hypervisor.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 71e2a165aa7f81602c569430b18ba1ea705f0b70
# Parent  da66691687dfd90c55420cfdf27f55d18cca7810
[HVM] Move RTC emulation into the hypervisor.
Signed-off-by: Xiaowei Yang <xiaowei.yang@xxxxxxxxx>
---
 tools/ioemu/Makefile.target         |    8 
 tools/ioemu/target-i386-dm/rtc-dm.c |  107 +++++++++
 xen/arch/x86/hvm/Makefile           |    1 
 xen/arch/x86/hvm/hvm.c              |   11 -
 xen/arch/x86/hvm/i8254.c            |   16 -
 xen/arch/x86/hvm/i8259.c            |   48 +++-
 xen/arch/x86/hvm/intercept.c        |   16 -
 xen/arch/x86/hvm/io.c               |    7 
 xen/arch/x86/hvm/rtc.c              |  393 ++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/intr.c         |    4 
 xen/arch/x86/hvm/svm/svm.c          |    4 
 xen/arch/x86/hvm/vmx/vmx.c          |    4 
 xen/arch/x86/time.c                 |    7 
 xen/common/Makefile                 |    3 
 xen/common/time.c                   |   77 +++++++
 xen/include/asm-x86/hvm/vpic.h      |    2 
 xen/include/asm-x86/hvm/vpit.h      |   56 ++++-
 xen/include/xen/time.h              |   14 +
 18 files changed, 722 insertions(+), 56 deletions(-)

diff -r da66691687df -r 71e2a165aa7f tools/ioemu/Makefile.target
--- a/tools/ioemu/Makefile.target       Wed Oct 18 18:13:57 2006 +0100
+++ b/tools/ioemu/Makefile.target       Wed Oct 18 18:35:21 2006 +0100
@@ -294,7 +294,11 @@ endif
 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 @@ ifeq ($(TARGET_BASE_ARCH), i386)
 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
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/Makefile Wed Oct 18 18:35:21 2006 +0100
@@ -4,6 +4,7 @@ obj-y += hvm.o
 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
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Wed Oct 18 18:35:21 2006 +0100
@@ -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);
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c  Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/i8254.c  Wed Oct 18 18:35:21 2006 +0100
@@ -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
     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(PITCha
     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
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/i8259.c
--- a/xen/arch/x86/hvm/i8259.c  Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/i8259.c  Wed Oct 18 18:35:21 2006 +0100
@@ -598,23 +598,47 @@ int cpu_get_pic_interrupt(struct vcpu *v
     return intno;
 }
 
-int is_pit_irq(struct vcpu *v, int irq, int type)
-{
-    int pit_vec;
-
-    if (type == APIC_DM_EXTINT)
-        pit_vec = v->domain->arch.hvm_domain.vpic.pics[0].irq_base;
-    else
-        pit_vec =
-          v->domain->arch.hvm_domain.vioapic.redirtbl[0].RedirForm.vector;
-
-    return (irq == pit_vec);
+int is_periodic_irq(struct vcpu *v, int irq, int type)
+{
+    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)
+            vec = v->domain->arch.hvm_domain.vpic.pics[0].irq_base;
+        else
+            vec =
+              v->domain->arch.hvm_domain.vioapic.redirtbl[0].RedirForm.vector;
+
+        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);
     }
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c      Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/intercept.c      Wed Oct 18 18:35:21 2006 +0100
@@ -315,17 +315,14 @@ void pickup_deactive_ticks(struct period
  * period: fire frequency in ns.
  */
 struct periodic_time * create_periodic_time(
-        PITChannelState *s,
         u32 period, 
         char irq,
-        char one_shot)
-{
-    struct vcpu *v = s->vcpu;
-    struct periodic_time *pt = 
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+        char one_shot,
+        time_cb *cb,
+        void *data)
+{
+    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_t
     pt->scheduled = NOW() + period;
     set_timer (&pt->timer,pt->scheduled);
     pt->enabled = 1;
-    pt->priv = s;
+    pt->cb = cb;
+    pt->priv = data;
     return pt;
 }
 
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/io.c     Wed Oct 18 18:35:21 2006 +0100
@@ -683,7 +683,7 @@ void hvm_interrupt_post(struct vcpu *v, 
     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, 
             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) {
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c       Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/svm/intr.c       Wed Oct 18 18:35:21 2006 +0100
@@ -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 */
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed Oct 18 18:35:21 2006 +0100
@@ -921,6 +921,7 @@ static void svm_relinquish_guest_resourc
     }
 
     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 vc
 {
     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 vc
     }
     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);
 }
 
 
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Wed Oct 18 18:35:21 2006 +0100
@@ -146,6 +146,7 @@ static void vmx_relinquish_guest_resourc
     }
 
     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 @@ void vmx_migrate_timers(struct vcpu *v)
 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(
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/time.c       Wed Oct 18 18:35:21 2006 +0100
@@ -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
diff -r da66691687df -r 71e2a165aa7f xen/common/Makefile
--- a/xen/common/Makefile       Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/common/Makefile       Wed Oct 18 18:35:21 2006 +0100
@@ -20,8 +20,9 @@ obj-y += string.o
 obj-y += string.o
 obj-y += symbols.o
 obj-y += sysctl.o
+obj-y += time.o
+obj-y += timer.o
 obj-y += trace.o
-obj-y += timer.o
 obj-y += version.o
 obj-y += vsprintf.o
 obj-y += xmalloc.o
diff -r da66691687df -r 71e2a165aa7f xen/include/asm-x86/hvm/vpic.h
--- a/xen/include/asm-x86/hvm/vpic.h    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/include/asm-x86/hvm/vpic.h    Wed Oct 18 18:35:21 2006 +0100
@@ -75,7 +75,7 @@ uint32_t pic_intack_read(struct hvm_virp
 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);
diff -r da66691687df -r 71e2a165aa7f xen/include/asm-x86/hvm/vpit.h
--- a/xen/include/asm-x86/hvm/vpit.h    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/include/asm-x86/hvm/vpit.h    Wed Oct 18 18:35:21 2006 +0100
@@ -25,11 +25,12 @@
 #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>
 
 #define PIT_FREQ 1193181
-#define PIT_BASE        0x40
+#define PIT_BASE 0x40
 
 typedef struct PITChannelState {
     int count; /* can be 65536 */
@@ -49,10 +50,32 @@ typedef struct PITChannelState {
     struct vcpu      *vcpu;
     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);
 
diff -r da66691687df -r 71e2a165aa7f xen/include/xen/time.h
--- a/xen/include/xen/time.h    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/include/xen/time.h    Wed Oct 18 18:35:21 2006 +0100
@@ -49,6 +49,20 @@ typedef s64 s_time_t;
 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))
diff -r da66691687df -r 71e2a165aa7f tools/ioemu/target-i386-dm/rtc-dm.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/target-i386-dm/rtc-dm.c       Wed Oct 18 18:35:21 2006 +0100
@@ -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) {}
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/rtc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/rtc.c    Wed Oct 18 18:35:21 2006 +0100
@@ -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);
+}
diff -r da66691687df -r 71e2a165aa7f xen/common/time.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/time.c Wed Oct 18 18:35:21 2006 +0100
@@ -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;
+}

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.