ia64/xen-unstable

changeset 13033:cd89771ba550

[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>
author kfraser@localhost.localdomain
date Thu Dec 14 16:27:10 2006 +0000 (2006-12-14)
parents afc6b5a60866
children 4d2ae322ef02
files xen/arch/x86/domain.c xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/i8254.c xen/arch/x86/traps.c xen/include/asm-x86/hvm/vpt.h
line diff
     1.1 --- a/xen/arch/x86/domain.c	Thu Dec 14 16:00:31 2006 +0000
     1.2 +++ b/xen/arch/x86/domain.c	Thu Dec 14 16:27:10 2006 +0000
     1.3 @@ -136,6 +136,10 @@ int vcpu_initialise(struct vcpu *v)
     1.4  
     1.5      pae_l3_cache_init(&v->arch.pae_l3_cache);
     1.6  
     1.7 +    /* This should move to arch_domain_create(). */
     1.8 +    if ( !is_idle_domain(d) && (v->vcpu_id == 0) )
     1.9 +        pit_init(v, cpu_khz);
    1.10 +
    1.11      if ( is_hvm_domain(d) )
    1.12      {
    1.13          if ( (rc = hvm_vcpu_initialise(v)) != 0 )
     2.1 --- a/xen/arch/x86/hvm/hvm.c	Thu Dec 14 16:00:31 2006 +0000
     2.2 +++ b/xen/arch/x86/hvm/hvm.c	Thu Dec 14 16:27:10 2006 +0000
     2.3 @@ -222,7 +222,6 @@ int hvm_vcpu_initialise(struct vcpu *v)
     2.4  
     2.5      init_timer(&platform->pl_time.periodic_tm.timer,
     2.6                 pt_timer_fn, v, v->processor);
     2.7 -    pit_init(v, cpu_khz);
     2.8      rtc_init(v, RTC_PORT(0), RTC_IRQ);
     2.9      pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
    2.10  
     3.1 --- a/xen/arch/x86/hvm/i8254.c	Thu Dec 14 16:00:31 2006 +0000
     3.2 +++ b/xen/arch/x86/hvm/i8254.c	Thu Dec 14 16:27:10 2006 +0000
     3.3 @@ -184,13 +184,19 @@ void pit_time_fired(struct vcpu *v, void
     3.4  
     3.5  static inline void pit_load_count(PITChannelState *s, int val)
     3.6  {
     3.7 -    u32   period;
     3.8 +    u32 period;
     3.9 +    PITChannelState *ch0 =
    3.10 +        &current->domain->arch.hvm_domain.pl_time.vpit.channels[0];
    3.11 +
    3.12      if (val == 0)
    3.13          val = 0x10000;
    3.14      s->count_load_time = hvm_get_clock(s->vcpu);
    3.15      s->count = val;
    3.16      period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
    3.17  
    3.18 +    if (s != ch0)
    3.19 +        return;
    3.20 +
    3.21  #ifdef DEBUG_PIT
    3.22      printk("HVM_PIT: pit-load-counter(%p), count=0x%x, period=%uns mode=%d, load_time=%lld\n",
    3.23              s,
    3.24 @@ -419,13 +425,12 @@ static void speaker_ioport_write(void *o
    3.25  
    3.26  static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
    3.27  {
    3.28 -    int out;
    3.29      PITState *pit = opaque;
    3.30 -    out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
    3.31 -    pit->dummy_refresh_clock ^= 1;
    3.32 -
    3.33 -    return (pit->speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
    3.34 -      (pit->dummy_refresh_clock << 4);
    3.35 +    int out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
    3.36 +    /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
    3.37 +    unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
    3.38 +    return ((pit->speaker_data_on << 1) | pit_get_gate(pit, 2) |
    3.39 +            (out << 5) | refresh_clock << 4);
    3.40  }
    3.41  
    3.42  static int handle_speaker_io(ioreq_t *p)
    3.43 @@ -439,7 +444,7 @@ static int handle_speaker_io(ioreq_t *p)
    3.44          printk("HVM_SPEAKER:wrong SPEAKER IO!\n");
    3.45          return 1;
    3.46      }
    3.47 -    
    3.48 +
    3.49      if (p->dir == 0) {/* write */
    3.50          speaker_ioport_write(vpit, p->addr, p->data);
    3.51      } else if (p->dir == 1) {/* read */
    3.52 @@ -448,3 +453,21 @@ static int handle_speaker_io(ioreq_t *p)
    3.53  
    3.54      return 1;
    3.55  }
    3.56 +
    3.57 +int pv_pit_handler(int port, int data, int write)
    3.58 +{
    3.59 +    ioreq_t ioreq = {
    3.60 +        .size = 1,
    3.61 +        .type = IOREQ_TYPE_PIO,
    3.62 +        .addr = port,
    3.63 +        .dir  = write ? 0 : 1,
    3.64 +        .data = write ? data : 0,
    3.65 +    };
    3.66 +
    3.67 +    if (port == 0x61)
    3.68 +        handle_speaker_io(&ioreq);
    3.69 +    else
    3.70 +        handle_pit_io(&ioreq);
    3.71 +
    3.72 +    return !write ? ioreq.data : 0;
    3.73 +}
     4.1 --- a/xen/arch/x86/traps.c	Thu Dec 14 16:00:31 2006 +0000
     4.2 +++ b/xen/arch/x86/traps.c	Thu Dec 14 16:27:10 2006 +0000
     4.3 @@ -59,6 +59,7 @@
     4.4  #include <asm/debugger.h>
     4.5  #include <asm/msr.h>
     4.6  #include <asm/x86_emulate.h>
     4.7 +#include <asm/hvm/vpt.h>
     4.8  
     4.9  /*
    4.10   * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
    4.11 @@ -1035,18 +1036,7 @@ static inline int admin_io_okay(
    4.12      return ioports_access_permitted(v->domain, port, port + bytes - 1);
    4.13  }
    4.14  
    4.15 -static inline int guest_inb_okay(
    4.16 -    unsigned int port, struct vcpu *v, struct cpu_user_regs *regs)
    4.17 -{
    4.18 -    /*
    4.19 -     * Allow read access to port 0x61. Bit 4 oscillates with period 30us, and
    4.20 -     * so it is often used for timing loops in BIOS code. This hack can go
    4.21 -     * away when we have separate read/write permission rangesets.
    4.22 -     * Note that we could emulate bit 4 instead of directly reading port 0x61,
    4.23 -     * but there's not really a good reason to do so.
    4.24 -     */
    4.25 -    return (admin_io_okay(port, 1, v, regs) || (port == 0x61));
    4.26 -}
    4.27 +#define guest_inb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
    4.28  #define guest_inw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
    4.29  #define guest_inl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
    4.30  #define guest_outb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
    4.31 @@ -1141,7 +1131,10 @@ static int emulate_privileged_op(struct 
    4.32              switch ( op_bytes )
    4.33              {
    4.34              case 1:
    4.35 -                data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : ~0);
    4.36 +                /* emulate PIT counter 2 */
    4.37 +                data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : 
    4.38 +                       ((port == 0x42 || port == 0x43 || port == 0x61) ?
    4.39 +                       pv_pit_handler(port, 0, 0) : ~0)); 
    4.40                  break;
    4.41              case 2:
    4.42                  data = (u16)(guest_inw_okay(port, v, regs) ? inw(port) : ~0);
    4.43 @@ -1176,6 +1169,8 @@ static int emulate_privileged_op(struct 
    4.44              case 1:
    4.45                  if ( guest_outb_okay(port, v, regs) )
    4.46                      outb((u8)data, port);
    4.47 +                else if ( port == 0x42 || port == 0x43 || port == 0x61 )
    4.48 +                    pv_pit_handler(port, data, 1);
    4.49                  break;
    4.50              case 2:
    4.51                  if ( guest_outw_okay(port, v, regs) )
    4.52 @@ -1240,6 +1235,11 @@ static int emulate_privileged_op(struct 
    4.53          case 1:
    4.54              if ( guest_inb_okay(port, v, regs) )
    4.55                  io_emul(regs);
    4.56 +            else if ( port == 0x42 || port == 0x43 || port == 0x61 )
    4.57 +            {
    4.58 +                regs->eax &= ~0xffUL;
    4.59 +                regs->eax |= pv_pit_handler(port, 0, 0);
    4.60 +            } 
    4.61              else
    4.62                  regs->eax |= (u8)~0;
    4.63              break;
    4.64 @@ -1277,6 +1277,8 @@ static int emulate_privileged_op(struct 
    4.65          case 1:
    4.66              if ( guest_outb_okay(port, v, regs) )
    4.67                  io_emul(regs);
    4.68 +            else if ( port == 0x42 || port == 0x43 || port == 0x61 )
    4.69 +                pv_pit_handler(port, regs->eax, 1);
    4.70              break;
    4.71          case 2:
    4.72              if ( guest_outw_okay(port, v, regs) )
     5.1 --- a/xen/include/asm-x86/hvm/vpt.h	Thu Dec 14 16:00:31 2006 +0000
     5.2 +++ b/xen/include/asm-x86/hvm/vpt.h	Thu Dec 14 16:27:10 2006 +0000
     5.3 @@ -54,7 +54,6 @@ typedef struct PITChannelState {
     5.4  typedef struct PITState {
     5.5      PITChannelState channels[3];
     5.6      int speaker_data_on;
     5.7 -    int dummy_refresh_clock;
     5.8  } PITState;
     5.9  
    5.10  #define RTC_SIZE 14
    5.11 @@ -125,6 +124,7 @@ extern void pickup_deactive_ticks(struct
    5.12  extern struct periodic_time *create_periodic_time(
    5.13      u32 period, char irq, char one_shot, time_cb *cb, void *data);
    5.14  extern void destroy_periodic_time(struct periodic_time *pt);
    5.15 +int pv_pit_handler(int port, int data, int write);
    5.16  void pit_init(struct vcpu *v, unsigned long cpu_khz);
    5.17  void rtc_init(struct vcpu *v, int base, int irq);
    5.18  void rtc_deinit(struct domain *d);