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