aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/i8254.c
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2006-12-14 16:27:10 +0000
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2006-12-14 16:27:10 +0000
commit0330b1b4b89d89ea5477681d9167e2d41ad36410 (patch)
treef3b569864dcd2310e929b6b1bc422df2a2c9f9bb /xen/arch/x86/hvm/i8254.c
parenta0bf728f15fb7dd7b87c7ee208e4ae269adf14d8 (diff)
downloadxen-0330b1b4b89d89ea5477681d9167e2d41ad36410.tar.gz
xen-0330b1b4b89d89ea5477681d9167e2d41ad36410.tar.bz2
xen-0330b1b4b89d89ea5477681d9167e2d41ad36410.zip
[XEN] Provide PV guests with emulated PIT.
This is needed for some video-controller BIOSes which use PIT channel 2 for delay loops. Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
Diffstat (limited to 'xen/arch/x86/hvm/i8254.c')
-rw-r--r--xen/arch/x86/hvm/i8254.c39
1 files changed, 31 insertions, 8 deletions
diff --git a/xen/arch/x86/hvm/i8254.c b/xen/arch/x86/hvm/i8254.c
index 516c114907..faee87564b 100644
--- a/xen/arch/x86/hvm/i8254.c
+++ b/xen/arch/x86/hvm/i8254.c
@@ -184,13 +184,19 @@ void pit_time_fired(struct vcpu *v, void *priv)
static inline void pit_load_count(PITChannelState *s, int val)
{
- u32 period;
+ u32 period;
+ PITChannelState *ch0 =
+ &current->domain->arch.hvm_domain.pl_time.vpit.channels[0];
+
if (val == 0)
val = 0x10000;
s->count_load_time = hvm_get_clock(s->vcpu);
s->count = val;
period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
+ if (s != ch0)
+ return;
+
#ifdef DEBUG_PIT
printk("HVM_PIT: pit-load-counter(%p), count=0x%x, period=%uns mode=%d, load_time=%lld\n",
s,
@@ -419,13 +425,12 @@ static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
{
- int out;
PITState *pit = opaque;
- out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
- pit->dummy_refresh_clock ^= 1;
-
- return (pit->speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
- (pit->dummy_refresh_clock << 4);
+ int out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
+ /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
+ unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
+ return ((pit->speaker_data_on << 1) | pit_get_gate(pit, 2) |
+ (out << 5) | refresh_clock << 4);
}
static int handle_speaker_io(ioreq_t *p)
@@ -439,7 +444,7 @@ static int handle_speaker_io(ioreq_t *p)
printk("HVM_SPEAKER:wrong SPEAKER IO!\n");
return 1;
}
-
+
if (p->dir == 0) {/* write */
speaker_ioport_write(vpit, p->addr, p->data);
} else if (p->dir == 1) {/* read */
@@ -448,3 +453,21 @@ static int handle_speaker_io(ioreq_t *p)
return 1;
}
+
+int pv_pit_handler(int port, int data, int write)
+{
+ ioreq_t ioreq = {
+ .size = 1,
+ .type = IOREQ_TYPE_PIO,
+ .addr = port,
+ .dir = write ? 0 : 1,
+ .data = write ? data : 0,
+ };
+
+ if (port == 0x61)
+ handle_speaker_io(&ioreq);
+ else
+ handle_pit_io(&ioreq);
+
+ return !write ? ioreq.data : 0;
+}