[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XEN] Provide PV guests with emulated PIT.
# 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |