# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID cd89771ba5508e9d1d8c76448c11dc9809e1e70d
# Parent afc6b5a60866d79d86af934515cf13f847acf6fc
[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@xxxxxxxxx>
---
xen/arch/x86/domain.c | 4 ++++
xen/arch/x86/hvm/hvm.c | 1 -
xen/arch/x86/hvm/i8254.c | 41 ++++++++++++++++++++++++++++++++---------
xen/arch/x86/traps.c | 28 +++++++++++++++-------------
xen/include/asm-x86/hvm/vpt.h | 2 +-
5 files changed, 52 insertions(+), 24 deletions(-)
diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/domain.c Thu Dec 14 16:27:10 2006 +0000
@@ -136,6 +136,10 @@ int vcpu_initialise(struct vcpu *v)
pae_l3_cache_init(&v->arch.pae_l3_cache);
+ /* This should move to arch_domain_create(). */
+ if ( !is_idle_domain(d) && (v->vcpu_id == 0) )
+ pit_init(v, cpu_khz);
+
if ( is_hvm_domain(d) )
{
if ( (rc = hvm_vcpu_initialise(v)) != 0 )
diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/hvm/hvm.c Thu Dec 14 16:27:10 2006 +0000
@@ -222,7 +222,6 @@ int hvm_vcpu_initialise(struct vcpu *v)
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);
pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/hvm/i8254.c Thu Dec 14 16:27:10 2006 +0000
@@ -184,12 +184,18 @@ void pit_time_fired(struct vcpu *v, void
static inline void pit_load_count(PITChannelState *s, int val)
{
- u32 period;
+ u32 period;
+ PITChannelState *ch0 =
+ ¤t->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",
@@ -419,13 +425,12 @@ static void speaker_ioport_write(void *o
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);
+ PITState *pit = opaque;
+ 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;
+}
diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/traps.c Thu Dec 14 16:27:10 2006 +0000
@@ -59,6 +59,7 @@
#include <asm/debugger.h>
#include <asm/msr.h>
#include <asm/x86_emulate.h>
+#include <asm/hvm/vpt.h>
/*
* opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
@@ -1035,18 +1036,7 @@ static inline int admin_io_okay(
return ioports_access_permitted(v->domain, port, port + bytes - 1);
}
-static inline int guest_inb_okay(
- unsigned int port, struct vcpu *v, struct cpu_user_regs *regs)
-{
- /*
- * Allow read access to port 0x61. Bit 4 oscillates with period 30us, and
- * so it is often used for timing loops in BIOS code. This hack can go
- * away when we have separate read/write permission rangesets.
- * Note that we could emulate bit 4 instead of directly reading port 0x61,
- * but there's not really a good reason to do so.
- */
- return (admin_io_okay(port, 1, v, regs) || (port == 0x61));
-}
+#define guest_inb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
#define guest_inw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
#define guest_inl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
#define guest_outb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
@@ -1141,7 +1131,10 @@ static int emulate_privileged_op(struct
switch ( op_bytes )
{
case 1:
- data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : ~0);
+ /* emulate PIT counter 2 */
+ data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) :
+ ((port == 0x42 || port == 0x43 || port == 0x61) ?
+ pv_pit_handler(port, 0, 0) : ~0));
break;
case 2:
data = (u16)(guest_inw_okay(port, v, regs) ? inw(port) : ~0);
@@ -1176,6 +1169,8 @@ static int emulate_privileged_op(struct
case 1:
if ( guest_outb_okay(port, v, regs) )
outb((u8)data, port);
+ else if ( port == 0x42 || port == 0x43 || port == 0x61 )
+ pv_pit_handler(port, data, 1);
break;
case 2:
if ( guest_outw_okay(port, v, regs) )
@@ -1240,6 +1235,11 @@ static int emulate_privileged_op(struct
case 1:
if ( guest_inb_okay(port, v, regs) )
io_emul(regs);
+ else if ( port == 0x42 || port == 0x43 || port == 0x61 )
+ {
+ regs->eax &= ~0xffUL;
+ regs->eax |= pv_pit_handler(port, 0, 0);
+ }
else
regs->eax |= (u8)~0;
break;
@@ -1277,6 +1277,8 @@ static int emulate_privileged_op(struct
case 1:
if ( guest_outb_okay(port, v, regs) )
io_emul(regs);
+ else if ( port == 0x42 || port == 0x43 || port == 0x61 )
+ pv_pit_handler(port, regs->eax, 1);
break;
case 2:
if ( guest_outw_okay(port, v, regs) )
diff -r afc6b5a60866 -r cd89771ba550 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/include/asm-x86/hvm/vpt.h Thu Dec 14 16:27:10 2006 +0000
@@ -54,7 +54,6 @@ typedef struct PITState {
typedef struct PITState {
PITChannelState channels[3];
int speaker_data_on;
- int dummy_refresh_clock;
} PITState;
#define RTC_SIZE 14
@@ -125,6 +124,7 @@ extern struct periodic_time *create_peri
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);
+int pv_pit_handler(int port, int data, int write);
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);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|