1 /*
2  * vpt.h: Virtual Platform Timer definitions
3  *
4  * Copyright (c) 2004, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef __ASM_X86_HVM_VPT_H__
20 #define __ASM_X86_HVM_VPT_H__
21 
22 #include <xen/init.h>
23 #include <xen/lib.h>
24 #include <xen/time.h>
25 #include <xen/errno.h>
26 #include <xen/time.h>
27 #include <xen/timer.h>
28 #include <xen/list.h>
29 #include <asm/hvm/vpic.h>
30 #include <asm/hvm/irq.h>
31 #include <public/hvm/save.h>
32 
33 /*
34  * Abstract layer of periodic time, one short time.
35  */
36 typedef void time_cb(struct vcpu *v, void *opaque);
37 
38 struct periodic_time {
39     struct list_head list;
40     bool_t on_list;
41     bool_t one_shot;
42     bool_t do_not_freeze;
43     bool_t irq_issued;
44     bool_t warned_timeout_too_short;
45 #define PTSRC_isa    1 /* ISA time source */
46 #define PTSRC_lapic  2 /* LAPIC time source */
47     u8 source;                  /* PTSRC_ */
48     u8 irq;
49     struct vcpu *vcpu;          /* vcpu timer interrupt delivers to */
50     u32 pending_intr_nr;        /* pending timer interrupts */
51     u64 period;                 /* frequency in ns */
52     s_time_t scheduled;         /* scheduled timer interrupt */
53     u64 last_plt_gtime;         /* platform time when last IRQ is injected */
54     struct timer timer;         /* ac_timer */
55     time_cb *cb;
56     void *priv;                 /* point back to platform time source */
57 };
58 
59 
60 #define PIT_FREQ 1193182
61 #define PIT_BASE 0x40
62 
63 typedef struct PITState {
64     /* Hardware state */
65     struct hvm_hw_pit hw;
66     /* Last time the counters read zero, for calcuating counter reads */
67     int64_t count_load_time[3];
68     /* Channel 0 IRQ handling. */
69     struct periodic_time pt0;
70     spinlock_t lock;
71 } PITState;
72 
73 struct hpet_registers {
74     /* Memory-mapped, software visible registers */
75     uint64_t capability;        /* capabilities */
76     uint64_t config;            /* configuration */
77     uint64_t isr;               /* interrupt status reg */
78     uint64_t mc64;              /* main counter */
79     struct {                    /* timers */
80         uint64_t config;        /* configuration/cap */
81         uint64_t cmp;           /* comparator */
82         uint64_t fsb;           /* FSB route, not supported now */
83     } timers[HPET_TIMER_NUM];
84 
85     /* Hidden register state */
86     uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
87     uint64_t comparator64[HPET_TIMER_NUM]; /* 64 bit running comparator */
88 };
89 
90 typedef struct HPETState {
91     struct hpet_registers hpet;
92     uint64_t stime_freq;
93     uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
94     uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns      */
95     uint64_t mc_offset;
96     struct periodic_time pt[HPET_TIMER_NUM];
97     rwlock_t lock;
98 } HPETState;
99 
100 typedef struct RTCState {
101     /* Hardware state */
102     struct hvm_hw_rtc hw;
103     /* RTC's idea of the current time */
104     struct tm current_tm;
105     /* update-ended timer */
106     struct timer update_timer;
107     struct timer update_timer2;
108     uint64_t next_update_time;
109     /* alarm timer */
110     struct timer alarm_timer;
111     /* periodic timer */
112     struct periodic_time pt;
113     s_time_t start_time;
114     s_time_t check_ticks_since;
115     int period;
116     uint8_t pt_dead_ticks;
117     uint32_t use_timer;
118     spinlock_t lock;
119 } RTCState;
120 
121 #define FREQUENCE_PMTIMER  3579545  /* Timer should run at 3.579545 MHz */
122 typedef struct PMTState {
123     struct vcpu *vcpu;          /* Keeps sync with this vcpu's guest-time */
124     uint64_t last_gtime;        /* Last (guest) time we updated the timer */
125     uint32_t not_accounted;     /* time not accounted at last update */
126     uint64_t scale;             /* Multiplier to get from tsc to timer ticks */
127     struct timer timer;         /* To make sure we send SCIs */
128     spinlock_t lock;
129 } PMTState;
130 
131 struct pl_time {    /* platform time */
132     struct RTCState  vrtc;
133     struct HPETState vhpet;
134     struct PMTState  vpmt;
135     /* guest_time = Xen sys time + stime_offset */
136     int64_t stime_offset;
137     /* Ensures monotonicity in appropriate timer modes. */
138     uint64_t last_guest_time;
139     spinlock_t pl_time_lock;
140     struct domain *domain;
141 };
142 
143 void pt_save_timer(struct vcpu *v);
144 void pt_restore_timer(struct vcpu *v);
145 int pt_update_irq(struct vcpu *v);
146 void pt_intr_post(struct vcpu *v, struct hvm_intack intack);
147 void pt_migrate(struct vcpu *v);
148 
149 void pt_adjust_global_vcpu_target(struct vcpu *v);
150 #define pt_global_vcpu_target(d) \
151     (is_hvm_domain(d) && (d)->arch.hvm_domain.i8259_target ? \
152      (d)->arch.hvm_domain.i8259_target : \
153      (d)->vcpu ? (d)->vcpu[0] : NULL)
154 
155 void pt_may_unmask_irq(struct domain *d, struct periodic_time *vlapic_pt);
156 
157 /* Is given periodic timer active? */
158 #define pt_active(pt) ((pt)->on_list || (pt)->pending_intr_nr)
159 
160 /*
161  * Create/destroy a periodic (or one-shot!) timer.
162  * The given periodic timer structure must be initialised with zero bytes,
163  * except for the 'source' field which must be initialised with the
164  * correct PTSRC_ value. The initialised timer structure can then be passed
165  * to {create,destroy}_periodic_time() any number of times and in any order.
166  * Note that, for a given periodic timer, invocations of these functions MUST
167  * be serialised.
168  */
169 void create_periodic_time(
170     struct vcpu *v, struct periodic_time *pt, uint64_t delta,
171     uint64_t period, uint8_t irq, time_cb *cb, void *data);
172 void destroy_periodic_time(struct periodic_time *pt);
173 
174 int pv_pit_handler(int port, int data, int write);
175 void pit_reset(struct domain *d);
176 
177 void pit_init(struct domain *d, unsigned long cpu_khz);
178 void pit_stop_channel0_irq(PITState * pit);
179 void pit_deinit(struct domain *d);
180 void rtc_init(struct domain *d);
181 void rtc_migrate_timers(struct vcpu *v);
182 void rtc_deinit(struct domain *d);
183 void rtc_reset(struct domain *d);
184 void rtc_update_clock(struct domain *d);
185 
186 void pmtimer_init(struct vcpu *v);
187 void pmtimer_deinit(struct domain *d);
188 void pmtimer_reset(struct domain *d);
189 int pmtimer_change_ioport(struct domain *d, unsigned int version);
190 
191 void hpet_init(struct domain *d);
192 void hpet_deinit(struct domain *d);
193 void hpet_reset(struct domain *d);
194 
195 #endif /* __ASM_X86_HVM_VPT_H__ */
196