ia64/xen-unstable

changeset 3749:8518c7b4c3f3

bitkeeper revision 1.1159.1.556 (420951de12d7YPCDmxFldoqZYbe2cw)

Subject: [PATCH] pit-in-hv.patch

- Use ac_timer for PIT interrupt injection (more accurate time keeping)
- Accelerate some critical PIT I/O operations in the hypervisor
(saves 15us per op). Cuts down guest timer interrupt handler execution time
by a third.
- If the domain is scheduled out, make sure that interrupts are not lost
- Add a generic framework for device I/O interception

Signed-off-by: Edwin Zhai <edwin.zhai@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
Signed-off-by: ian@xensource.com
author iap10@labyrinth.cl.cam.ac.uk
date Tue Feb 08 23:57:18 2005 +0000 (2005-02-08)
parents 31070c4d28c6
children 7e23d55c92a3
files .rootkeys tools/ioemu/iodev/cpu.cc tools/ioemu/iodev/pic.cc tools/ioemu/iodev/pic.h tools/ioemu/iodev/pit82c54.cc tools/ioemu/iodev/pit82c54.h tools/ioemu/iodev/pit_wrap.cc xen/arch/x86/domain.c xen/arch/x86/vmx.c xen/arch/x86/vmx_intercept.c xen/arch/x86/vmx_io.c xen/include/asm-x86/vmx_intercept.h xen/include/asm-x86/vmx_platform.h xen/include/asm-x86/vmx_virpit.h xen/include/public/io/ioreq.h
line diff
     1.1 --- a/.rootkeys	Tue Feb 08 23:17:38 2005 +0000
     1.2 +++ b/.rootkeys	Tue Feb 08 23:57:18 2005 +0000
     1.3 @@ -915,6 +915,7 @@ 3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/
     1.4  3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S
     1.5  3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
     1.6  41c0c411tD3C7TpfDMiFTf7BaNd_Dg xen/arch/x86/vmx.c
     1.7 +420951dcf1rSGnCH0AEYN2KjWGLG6A xen/arch/x86/vmx_intercept.c
     1.8  41c0c411ODt8uEmV-yUxpQLpqimE5Q xen/arch/x86/vmx_io.c
     1.9  41f97ef5139vN42cOYHfX_Ac8WOOjA xen/arch/x86/vmx_platform.c
    1.10  41c0c4128URE0dxcO15JME_MuKBPfg xen/arch/x86/vmx_vmcs.c
    1.11 @@ -1057,7 +1058,9 @@ 3ddb79c4HugMq7IYGxcQKFBpKwKhzA xen/inclu
    1.12  40cf1596saFaHD5DC5zvrSn7CDCWGQ xen/include/asm-x86/uaccess.h
    1.13  41c0c412k6GHYF3cJtDdw37ee3TVaw xen/include/asm-x86/vmx.h
    1.14  41c0c412hck3QX-6_MaXaISGkngQuA xen/include/asm-x86/vmx_cpu.h
    1.15 +420951dcGoqsqnmjjAtEtm6-3dM9KA xen/include/asm-x86/vmx_intercept.h
    1.16  41c0c41243jC1mcArZx_t3YkBL4lTA xen/include/asm-x86/vmx_platform.h
    1.17 +420951dcqyUCe_gXA_XJPu1ix_poKg xen/include/asm-x86/vmx_virpit.h
    1.18  41c0c412lQ0NVVN9PsOSznQ-qhOiPA xen/include/asm-x86/vmx_vmcs.h
    1.19  418fbcfe_WliJPToeVM-9VStvym-hw xen/include/asm-x86/x86_32/asm_defns.h
    1.20  3ddb79c2ADvRmdexd9y3AYK9_NTx-Q xen/include/asm-x86/x86_32/current.h
     2.1 --- a/tools/ioemu/iodev/cpu.cc	Tue Feb 08 23:17:38 2005 +0000
     2.2 +++ b/tools/ioemu/iodev/cpu.cc	Tue Feb 08 23:57:18 2005 +0000
     2.3 @@ -144,7 +144,11 @@ void bx_cpu_c::dispatch_ioreq(ioreq_t *r
     2.4  			}
     2.5  		}
     2.6  	}
     2.7 -	req->state = STATE_IORESP_READY;
     2.8 +
     2.9 +        /* No state change if state = STATE_IORESP_HOOK */
    2.10 +        if (req->state == STATE_IOREQ_INPROCESS)
    2.11 +                req->state = STATE_IORESP_READY;
    2.12 +
    2.13  	send_event = 1;
    2.14  }
    2.15  
     3.1 --- a/tools/ioemu/iodev/pic.cc	Tue Feb 08 23:17:38 2005 +0000
     3.2 +++ b/tools/ioemu/iodev/pic.cc	Tue Feb 08 23:57:18 2005 +0000
     3.3 @@ -855,6 +855,21 @@ bx_pic_c::IAC(void)
     3.4    BX_DBG_IAC_REPORT(vector, irq);
     3.5    return(vector);
     3.6  }
     3.7 + 
     3.8 +  Bit8u
     3.9 +bx_pic_c::irq_to_vec(Bit8u irq)
    3.10 +{
    3.11 +  Bit8u vector = 0;
    3.12 +
    3.13 +  if (irq >= 8 && irq <= 15)
    3.14 +    vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
    3.15 +  else if (irq != 2 && irq <= 7)
    3.16 +    vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
    3.17 +  else
    3.18 +    BX_ERROR(("invalid irq!\n"));
    3.19 +
    3.20 +  return vector;
    3.21 +}
    3.22  
    3.23    void
    3.24  bx_pic_c::show_pic_state(void)
     4.1 --- a/tools/ioemu/iodev/pic.h	Tue Feb 08 23:17:38 2005 +0000
     4.2 +++ b/tools/ioemu/iodev/pic.h	Tue Feb 08 23:57:18 2005 +0000
     4.3 @@ -67,7 +67,6 @@ typedef struct {
     4.4  
     4.5  
     4.6  class bx_pic_c : public bx_pic_stub_c {
     4.7 -
     4.8  public:
     4.9    bx_pic_c(void);
    4.10    ~bx_pic_c(void);
    4.11 @@ -77,6 +76,7 @@ public:
    4.12    virtual void   raise_irq(unsigned irq_no);
    4.13    virtual Bit8u  IAC(void);
    4.14    virtual void   show_pic_state(void);
    4.15 +  Bit8u  irq_to_vec(Bit8u);
    4.16  
    4.17  private:
    4.18    struct {
     5.1 --- a/tools/ioemu/iodev/pit82c54.cc	Tue Feb 08 23:17:38 2005 +0000
     5.2 +++ b/tools/ioemu/iodev/pit82c54.cc	Tue Feb 08 23:57:18 2005 +0000
     5.3 @@ -608,6 +608,37 @@ pit_82C54::clock(Bit8u cnum) {
     5.4      return 0;
     5.5    }
     5.6  
     5.7 +#ifdef BX_VMX_PIT
     5.8 +//extra operations when use vmx pit device model
     5.9 +  void pit_82C54::write_initcount_vmx(Bit8u cnum) {
    5.10 +    if(cnum>MAX_COUNTER) {
    5.11 +      BX_ERROR(("Counter number incorrect\n"));
    5.12 +    }
    5.13 +
    5.14 +    ioreq_t *req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
    5.15 +    extern bx_pic_c *thePic;
    5.16 +    counter_type & thisctr = counter[cnum];
    5.17 +    if(req->pdata_valid) {
    5.18 +      BX_ERROR(("VMX_PIT:err!pit is port io!\n"));
    5.19 +    }
    5.20 +
    5.21 +    if (thisctr.mode == 2) {//periodic mode, need HV to help send interrupt
    5.22 +      req->state = STATE_IORESP_HOOK;
    5.23 +
    5.24 +//      req->u.data = thisctr.inlatch * 1000 / PIT_FREQ;//init count:16 bit
    5.25 +      req->u.data = thisctr.inlatch;			//init count:16 bit
    5.26 +      //get the pit irq(0)'s vector from pic DM
    5.27 +      req->u.data |= ((thePic->irq_to_vec(0)) << 16 );	//timer vec:8 bit
    5.28 +      req->u.data |= (cnum << 24);			//PIT channel(0~2):2 bit
    5.29 +      req->u.data |= ((thisctr.rw_mode) << 26);		//rw mode:2 bit
    5.30 +
    5.31 +      BX_INFO(("VMX_PIT:whole pit hook packet = 0x%llx \n", (req->u.data ) ));
    5.32 +      BX_INFO(("VMX_PIT:init counter = %d ms\n", (req->u.data & 0xFFFF) ));
    5.33 +    }
    5.34 +
    5.35 +  }
    5.36 +#endif
    5.37 +
    5.38    void pit_82C54::write(Bit8u address, Bit8u data) {
    5.39      if(address>MAX_ADDRESS) {
    5.40        BX_ERROR(("Counter address incorrect in data write."));
    5.41 @@ -709,6 +740,9 @@ pit_82C54::clock(Bit8u cnum) {
    5.42  	thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
    5.43  	thisctr.null_count=1;
    5.44  	thisctr.count_written=1;
    5.45 +#ifdef BX_VMX_PIT
    5.46 +	write_initcount_vmx(address);
    5.47 +#endif
    5.48  	break;
    5.49        case MSByte_multiple:
    5.50  	thisctr.write_state=LSByte_multiple;
    5.51 @@ -716,6 +750,9 @@ pit_82C54::clock(Bit8u cnum) {
    5.52  	thisctr.inlatch=(thisctr.inlatch & 0xFF) | (data<<8);
    5.53  	thisctr.null_count=1;
    5.54  	thisctr.count_written=1;
    5.55 +#ifdef BX_VMX_PIT
    5.56 +	write_initcount_vmx(address);
    5.57 +#endif
    5.58  	break;
    5.59        default:
    5.60  	BX_ERROR(("write counter in invalid write state."));
     6.1 --- a/tools/ioemu/iodev/pit82c54.h	Tue Feb 08 23:17:38 2005 +0000
     6.2 +++ b/tools/ioemu/iodev/pit82c54.h	Tue Feb 08 23:57:18 2005 +0000
     6.3 @@ -15,6 +15,11 @@
     6.4  
     6.5  #include "bochs.h"
     6.6  
     6.7 +#ifdef BX_USE_VMX
     6.8 +#define BX_VMX_PIT 1
     6.9 +#define PIT_FREQ 1193181
    6.10 +#endif
    6.11 +
    6.12  
    6.13  class pit_82C54 : public logfunctions {
    6.14  
    6.15 @@ -108,6 +113,10 @@ private:
    6.16  
    6.17    void print_counter(counter_type & thisctr);
    6.18  
    6.19 +#ifdef BX_USE_VMX
    6.20 +  void write_initcount_vmx(Bit8u cnum);
    6.21 +#endif
    6.22 +
    6.23  public:
    6.24    void init (void);
    6.25    void reset (unsigned type);
     7.1 --- a/tools/ioemu/iodev/pit_wrap.cc	Tue Feb 08 23:17:38 2005 +0000
     7.2 +++ b/tools/ioemu/iodev/pit_wrap.cc	Tue Feb 08 23:57:18 2005 +0000
     7.3 @@ -326,11 +326,13 @@ bx_pit_c::write( Bit32u   address, Bit32
     7.4          (unsigned) address, (unsigned) value));
     7.5    }
     7.6  
     7.7 +#ifndef BX_VMX_PIT
     7.8    if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
     7.9      DEV_pic_raise_irq(0);
    7.10    } else {
    7.11      DEV_pic_lower_irq(0);
    7.12    }
    7.13 +#endif
    7.14  
    7.15    if(time_passed ||
    7.16       (BX_PIT_THIS s.last_next_event_time
    7.17 @@ -419,12 +421,16 @@ bx_pit_c::periodic( Bit32u   usec_delta 
    7.18      BX_PIT_THIS s.timer.clock_all(timedelta);
    7.19      if ( (prev_timer0_out==0) ) {
    7.20        if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
    7.21 +#ifndef BX_VMX_PIT
    7.22  	DEV_pic_raise_irq(0);
    7.23 +#endif
    7.24          prev_timer0_out=1;
    7.25        }
    7.26      } else {
    7.27        if ((BX_PIT_THIS s.timer.read_OUT(0))==0) {
    7.28 +#ifndef BX_VMX_PIT
    7.29  	DEV_pic_lower_irq(0);
    7.30 +#endif
    7.31          prev_timer0_out=0;
    7.32        }
    7.33      }
     8.1 --- a/xen/arch/x86/domain.c	Tue Feb 08 23:17:38 2005 +0000
     8.2 +++ b/xen/arch/x86/domain.c	Tue Feb 08 23:57:18 2005 +0000
     8.3 @@ -756,6 +756,7 @@ static void relinquish_list(struct domai
     8.4  #ifdef CONFIG_VMX
     8.5  static void vmx_domain_relinquish_memory(struct exec_domain *ed)
     8.6  {
     8.7 +    struct vmx_virpit_t *vpit = &(ed->arch.arch_vmx.vmx_platform.vmx_pit);
     8.8      /*
     8.9       * Free VMCS
    8.10       */
    8.11 @@ -764,6 +765,7 @@ static void vmx_domain_relinquish_memory
    8.12      ed->arch.arch_vmx.vmcs = 0;
    8.13      
    8.14      monitor_rm_pagetable(ed);
    8.15 +    rem_ac_timer(&(vpit->pit_timer));
    8.16  }
    8.17  #endif
    8.18  
     9.1 --- a/xen/arch/x86/vmx.c	Tue Feb 08 23:17:38 2005 +0000
     9.2 +++ b/xen/arch/x86/vmx.c	Tue Feb 08 23:57:18 2005 +0000
     9.3 @@ -34,6 +34,7 @@
     9.4  #include <asm/spinlock.h>
     9.5  #include <asm/vmx.h>
     9.6  #include <asm/vmx_vmcs.h>
     9.7 +#include <asm/vmx_intercept.h>
     9.8  #include <public/io/ioreq.h>
     9.9  
    9.10  #ifdef CONFIG_VMX
    9.11 @@ -359,7 +360,6 @@ static void vmx_io_instruction(struct xe
    9.12      }
    9.13      p = &vio->vp_ioreq;
    9.14      p->dir = test_bit(3, &exit_qualification);  
    9.15 -    set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
    9.16  
    9.17      p->pdata_valid = 0;
    9.18      p->count = 1;
    9.19 @@ -396,6 +396,14 @@ static void vmx_io_instruction(struct xe
    9.20  
    9.21      p->addr = addr;
    9.22      p->port_mm = 0;
    9.23 +
    9.24 +    /* Check if the packet needs to be intercepted */
    9.25 +    if (vmx_io_intercept(p)) {
    9.26 +	/* no blocking & no evtchn notification */
    9.27 +        return;
    9.28 +    } 
    9.29 +
    9.30 +    set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
    9.31      p->state = STATE_IOREQ_READY;
    9.32      evtchn_send(IOPACKET_PORT);
    9.33      do_block();
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/xen/arch/x86/vmx_intercept.c	Tue Feb 08 23:57:18 2005 +0000
    10.3 @@ -0,0 +1,257 @@
    10.4 +/*
    10.5 + * vmx_intercept.c: Handle performance critical I/O packets in hypervisor space
    10.6 + * Copyright (c) 2004, Intel Corporation.
    10.7 + *
    10.8 + * This program is free software; you can redistribute it and/or modify it
    10.9 + * under the terms and conditions of the GNU General Public License,
   10.10 + * version 2, as published by the Free Software Foundation.
   10.11 + *
   10.12 + * This program is distributed in the hope it will be useful, but WITHOUT
   10.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   10.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   10.15 + * more details.
   10.16 + *
   10.17 + * You should have received a copy of the GNU General Public License along with
   10.18 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
   10.19 + * Place - Suite 330, Boston, MA 02111-1307 USA.
   10.20 + *
   10.21 + */
   10.22 +
   10.23 +#include <xen/config.h>
   10.24 +#include <xen/types.h>
   10.25 +#include <asm/vmx.h>
   10.26 +#include <asm/vmx_platform.h>
   10.27 +#include <asm/vmx_virpit.h>
   10.28 +#include <asm/vmx_intercept.h>
   10.29 +#include <public/io/ioreq.h>
   10.30 +
   10.31 +#include <xen/lib.h>
   10.32 +#include <xen/sched.h>
   10.33 +#include <asm/current.h>
   10.34 +
   10.35 +/* for intercepting io request after vm_exit, return value: 0--not handle; 1--handled */
   10.36 +int vmx_io_intercept(ioreq_t *p)
   10.37 +{
   10.38 +    struct exec_domain *d = current;
   10.39 +    struct vmx_handler_t *handler = &(d->arch.arch_vmx.vmx_platform.vmx_handler);
   10.40 +    int i;
   10.41 +    unsigned addr, offset;
   10.42 +    for (i = 0; i < handler->num_slot; i++) {
   10.43 +        addr   = handler->hdl_list[i].addr;
   10.44 +        offset = handler->hdl_list[i].offset;
   10.45 +        if (p->addr >= addr &&
   10.46 +	    p->addr <  addr + offset)
   10.47 +	    return handler->hdl_list[i].action(p);
   10.48 +    }
   10.49 +    return 0;
   10.50 +}
   10.51 +
   10.52 +int register_io_handler(unsigned long addr, unsigned long offset, intercept_action_t action)
   10.53 +{
   10.54 +    struct exec_domain *d = current;
   10.55 +    struct vmx_handler_t *handler = &(d->arch.arch_vmx.vmx_platform.vmx_handler);
   10.56 +    int num = handler->num_slot;
   10.57 +
   10.58 +    if (num >= MAX_IO_HANDLER) {
   10.59 +        printk("no extra space, register io interceptor failed!\n");
   10.60 +        domain_crash();
   10.61 +    }
   10.62 +
   10.63 +    handler->hdl_list[num].addr = addr;
   10.64 +    handler->hdl_list[num].offset = offset;
   10.65 +    handler->hdl_list[num].action = action;
   10.66 +    handler->num_slot++;
   10.67 +    return 1;
   10.68 +
   10.69 +}
   10.70 +
   10.71 +static void pit_cal_count(struct vmx_virpit_t *vpit)
   10.72 +{
   10.73 +    unsigned int usec_delta = (unsigned int)((NOW() - vpit->inject_point) / 1000);
   10.74 +    if (usec_delta > vpit->period * 1000)
   10.75 +        VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:long time has passed from last injection!\n");
   10.76 +    vpit->count = vpit->init_val - ((usec_delta * PIT_FREQ / 1000000) % vpit->init_val );
   10.77 +}
   10.78 +
   10.79 +static void pit_latch_io(struct vmx_virpit_t *vpit)
   10.80 +{
   10.81 +    pit_cal_count(vpit);
   10.82 +
   10.83 +    switch(vpit->read_state) {
   10.84 +    case MSByte:
   10.85 +        vpit->count_MSB_latched=1;
   10.86 +        break;
   10.87 +    case LSByte:
   10.88 +        vpit->count_LSB_latched=1;
   10.89 +        break;
   10.90 +    case LSByte_multiple:
   10.91 +        vpit->count_LSB_latched=1;
   10.92 +        vpit->count_MSB_latched=1;
   10.93 +        break;
   10.94 +    case MSByte_multiple:
   10.95 +        VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:latch PIT counter before MSB_multiple!");
   10.96 +        vpit->read_state=LSByte_multiple;
   10.97 +        vpit->count_LSB_latched=1;
   10.98 +        vpit->count_MSB_latched=1;
   10.99 +        break;
  10.100 +    default:
  10.101 +        BUG();
  10.102 +    }
  10.103 +}
  10.104 +
  10.105 +static int pit_read_io(struct vmx_virpit_t *vpit)
  10.106 +{
  10.107 +    if(vpit->count_LSB_latched) {
  10.108 +        /* Read Least Significant Byte */
  10.109 +        if(vpit->read_state==LSByte_multiple) {
  10.110 +            vpit->read_state=MSByte_multiple;
  10.111 +        }
  10.112 +        vpit->count_LSB_latched=0;
  10.113 +        return (vpit->count & 0xFF);
  10.114 +    } else if(vpit->count_MSB_latched) {
  10.115 +        /* Read Most Significant Byte */
  10.116 +        if(vpit->read_state==MSByte_multiple) {
  10.117 +            vpit->read_state=LSByte_multiple;
  10.118 +        }
  10.119 +        vpit->count_MSB_latched=0;
  10.120 +        return ((vpit->count>>8) & 0xFF);
  10.121 +    } else {
  10.122 +        /* Unlatched Count Read */
  10.123 +        VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT: unlatched read");
  10.124 +        pit_cal_count(vpit);
  10.125 +        if(!(vpit->read_state & 0x1)) {
  10.126 +            /* Read Least Significant Byte */
  10.127 +            if(vpit->read_state==LSByte_multiple) {
  10.128 +                vpit->read_state=MSByte_multiple;
  10.129 +            }
  10.130 +            return (vpit->count & 0xFF);
  10.131 +        } else {
  10.132 +            /* Read Most Significant Byte */
  10.133 +            if(vpit->read_state==MSByte_multiple) {
  10.134 +                vpit->read_state=LSByte_multiple;
  10.135 +            }
  10.136 +            return ((vpit->count>>8) & 0xFF);
  10.137 +        }
  10.138 +    }
  10.139 +}
  10.140 +
  10.141 +/* vmx_io_assist light-weight version, specific to PIT DM */ 
  10.142 +static void resume_pit_io(ioreq_t *p)
  10.143 +{
  10.144 +    execution_context_t *ec = get_execution_context();
  10.145 +    unsigned long old_eax = ec->eax;
  10.146 +    p->state = STATE_INVALID;
  10.147 +
  10.148 +    switch(p->size) {
  10.149 +    case 1:
  10.150 +        ec->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
  10.151 +        break;
  10.152 +    case 2:
  10.153 +        ec->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
  10.154 +        break;
  10.155 +    case 4:
  10.156 +        ec->eax = (p->u.data & 0xffffffff);
  10.157 +        break;
  10.158 +    default:
  10.159 +        BUG();
  10.160 +    }
  10.161 +}
  10.162 +
  10.163 +/* the intercept action for PIT DM retval:0--not handled; 1--handled */
  10.164 +int intercept_pit_io(ioreq_t *p)
  10.165 +{
  10.166 +    struct exec_domain *d = current;
  10.167 +    struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
  10.168 +
  10.169 +    if (p->size != 1 ||
  10.170 +        p->pdata_valid ||
  10.171 +        p->port_mm)
  10.172 +        return 0;
  10.173 +    
  10.174 +    if (p->addr == 0x43 &&
  10.175 +	p->dir == 0 &&				/* write */
  10.176 +        ((p->u.data >> 4) & 0x3) == 0 &&	/* latch command */
  10.177 +        ((p->u.data >> 6) & 0x3) == (vpit->channel)) {/* right channel */
  10.178 +        pit_latch_io(vpit);
  10.179 +	return 1;
  10.180 +    }
  10.181 +
  10.182 +    if (p->addr == (0x40 + vpit->channel) &&
  10.183 +	p->dir == 1) {	/* read */
  10.184 +        p->u.data = pit_read_io(vpit);
  10.185 +        resume_pit_io(p);
  10.186 +	return 1;
  10.187 +    }
  10.188 +
  10.189 +    return 0;
  10.190 +}
  10.191 +
  10.192 +/* hooks function for the PIT initialization response iopacket */
  10.193 +static void pit_timer_fn(unsigned long data)
  10.194 +{
  10.195 +    struct vmx_virpit_t *vpit = (struct vmx_virpit_t*)data;
  10.196 +
  10.197 +    /* rearm itself */
  10.198 +    vpit->pit_timer.expires = NOW() + MILLISECS(vpit->period);
  10.199 +
  10.200 +    /*set the pending intr bit in shared page, send evtchn notification to myself*/
  10.201 +    if (test_and_set_bit(vpit->vector, vpit->intr_bitmap))
  10.202 +        vpit->pending_intr_nr++; /* if originaly set, then count the pending intr */
  10.203 +
  10.204 +    add_ac_timer(&(vpit->pit_timer));
  10.205 +}
  10.206 +
  10.207 +
  10.208 +/* Only some PIT operations such as load init counter need a hypervisor hook.
  10.209 + * leave many other operations in user space DM
  10.210 + */
  10.211 +void vmx_hooks_assist(struct exec_domain *d)
  10.212 +{
  10.213 +    vcpu_iodata_t *vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
  10.214 +    ioreq_t *p = &vio->vp_ioreq;
  10.215 +    unsigned long *intr = &(vio->vp_intr[0]);
  10.216 +    struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
  10.217 +    int rw_mode;
  10.218 +
  10.219 +    if (p->state == STATE_IORESP_HOOK) { /*load init count*/
  10.220 +        vpit->init_val = (p->u.data & 0xFFFF) ; /* frequency(ms) of pit */
  10.221 +        vpit->period = (vpit->init_val) * 1000 / PIT_FREQ; /* frequency(ms) of pit */
  10.222 +        vpit->vector = ((p->u.data >> 16) & 0xFF);
  10.223 +        vpit->channel = ((p->u.data >> 24) & 0x3);
  10.224 +
  10.225 +	vpit->count_LSB_latched = 0;
  10.226 +	vpit->count_MSB_latched = 0;
  10.227 +
  10.228 +        rw_mode = ((p->u.data >> 26) & 0x3);
  10.229 +        switch(rw_mode) {
  10.230 +        case 0x1:
  10.231 +            vpit->read_state=LSByte;
  10.232 +            break;
  10.233 +        case 0x2:
  10.234 +            vpit->read_state=MSByte;
  10.235 +            break;
  10.236 +        case 0x3:
  10.237 +            vpit->read_state=LSByte_multiple;
  10.238 +            break;
  10.239 +        default:
  10.240 +            printk("VMX_PIT:wrong PIT rw_mode!\n");
  10.241 +            break;
  10.242 +        }
  10.243 +
  10.244 +        vpit->intr_bitmap = intr;
  10.245 +
  10.246 +        /* set up the actimer */
  10.247 +        init_ac_timer(&(vpit->pit_timer));
  10.248 +        vpit->pit_timer.cpu = 0; /*FIXME: change for SMP */
  10.249 +        vpit->pit_timer.data = (unsigned long)vpit;
  10.250 +        vpit->pit_timer.function = pit_timer_fn;
  10.251 +        pit_timer_fn((unsigned long)vpit); /* timer seed */
  10.252 +
  10.253 +        /*restore the state*/
  10.254 +        p->state = STATE_IORESP_READY;
  10.255 +
  10.256 +	/* register handler to intercept the PIT io when vm_exit */
  10.257 +	register_io_handler(0x40, 4, intercept_pit_io); 
  10.258 +    }
  10.259 +
  10.260 +}
    11.1 --- a/xen/arch/x86/vmx_io.c	Tue Feb 08 23:17:38 2005 +0000
    11.2 +++ b/xen/arch/x86/vmx_io.c	Tue Feb 08 23:57:18 2005 +0000
    11.3 @@ -31,6 +31,7 @@
    11.4  #include <xen/event.h>
    11.5  #include <public/io/ioreq.h>
    11.6  #include <asm/vmx_platform.h>
    11.7 +#include <asm/vmx_virpit.h>
    11.8  
    11.9  #ifdef CONFIG_VMX
   11.10  
   11.11 @@ -197,6 +198,11 @@ void vmx_io_assist(struct exec_domain *e
   11.12          domain_crash();
   11.13      }
   11.14      p = &vio->vp_ioreq;
   11.15 +
   11.16 +    if (p->state == STATE_IORESP_HOOK){
   11.17 +        vmx_hooks_assist(ed);
   11.18 +    }
   11.19 +
   11.20      /* clear IO wait VMX flag */
   11.21      if (test_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags)) {
   11.22          if (p->state != STATE_IORESP_READY) {
   11.23 @@ -337,6 +343,7 @@ void vmx_intr_assist(struct exec_domain 
   11.24  {
   11.25      int highest_vector = find_highest_pending_irq(d);
   11.26      unsigned long intr_fields, eflags;
   11.27 +    struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
   11.28  
   11.29      if (highest_vector == -1)
   11.30          return;
   11.31 @@ -355,12 +362,19 @@ void vmx_intr_assist(struct exec_domain 
   11.32          return;
   11.33      }
   11.34          
   11.35 -    clear_highest_bit(d, highest_vector); 
   11.36 +    if (vpit->pending_intr_nr && highest_vector == vpit->vector)
   11.37 +        vpit->pending_intr_nr--;
   11.38 +    else
   11.39 +        clear_highest_bit(d, highest_vector); 
   11.40 +
   11.41      intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | highest_vector);
   11.42      __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
   11.43  
   11.44      __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
   11.45  
   11.46 +    if (highest_vector == vpit->vector)
   11.47 +        vpit->inject_point = NOW();
   11.48 +
   11.49      return;
   11.50  }
   11.51  
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/xen/include/asm-x86/vmx_intercept.h	Tue Feb 08 23:57:18 2005 +0000
    12.3 @@ -0,0 +1,31 @@
    12.4 +
    12.5 +#ifndef _VMX_INTERCEPT_H
    12.6 +#define _VMX_INTERCEPT_H
    12.7 +
    12.8 +#include <xen/config.h>
    12.9 +#include <xen/init.h>
   12.10 +#include <xen/lib.h>
   12.11 +#include <xen/time.h>
   12.12 +#include <xen/errno.h>
   12.13 +#include <public/io/ioreq.h>
   12.14 +
   12.15 +
   12.16 +#define MAX_IO_HANDLER 6
   12.17 +
   12.18 +typedef int (*intercept_action_t)(ioreq_t*);
   12.19 +
   12.20 +struct vmx_handler_t {
   12.21 +    int num_slot;
   12.22 +    struct {
   12.23 +        unsigned long       addr;
   12.24 +        unsigned long       offset;
   12.25 +        intercept_action_t  action;
   12.26 +    } hdl_list[MAX_IO_HANDLER];
   12.27 +};
   12.28 +
   12.29 +/* global io interception point in HV */
   12.30 +extern int vmx_io_intercept(ioreq_t*);
   12.31 +extern int register_io_handler(unsigned long, unsigned long, intercept_action_t);
   12.32 +
   12.33 +
   12.34 +#endif /* _VMX_INTERCEPT_H */
    13.1 --- a/xen/include/asm-x86/vmx_platform.h	Tue Feb 08 23:17:38 2005 +0000
    13.2 +++ b/xen/include/asm-x86/vmx_platform.h	Tue Feb 08 23:57:18 2005 +0000
    13.3 @@ -21,6 +21,8 @@
    13.4  
    13.5  #include <public/xen.h>
    13.6  #include <asm/e820.h>
    13.7 +#include <asm/vmx_virpit.h>
    13.8 +#include <asm/vmx_intercept.h>
    13.9  
   13.10  #define MAX_OPERAND_NUM 3
   13.11  #define I_NAME_LEN  16
   13.12 @@ -79,6 +81,8 @@ struct mi_per_cpu_info
   13.13  struct virutal_platform_def {
   13.14      unsigned long          *real_mode_data; /* E820, etc. */
   13.15      unsigned long          shared_page_va;
   13.16 +    struct vmx_virpit_t    vmx_pit;
   13.17 +    struct vmx_handler_t   vmx_handler;
   13.18      struct mi_per_cpu_info mpci;            /* MMIO */
   13.19  };
   13.20  
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/xen/include/asm-x86/vmx_virpit.h	Tue Feb 08 23:57:18 2005 +0000
    14.3 @@ -0,0 +1,81 @@
    14.4 +
    14.5 +#ifndef _VMX_VIRPIT_H
    14.6 +#define _VMX_VIRPIT_H
    14.7 +#include <xen/config.h>
    14.8 +#include <xen/init.h>
    14.9 +#include <xen/lib.h>
   14.10 +#include <xen/time.h>
   14.11 +#include <xen/errno.h>
   14.12 +#include <xen/ac_timer.h>
   14.13 +#include <asm/vmx_vmcs.h>
   14.14 +
   14.15 +#define PIT_FREQ 1193181
   14.16 +
   14.17 +#define LSByte 0
   14.18 +#define MSByte 1
   14.19 +#define LSByte_multiple 2
   14.20 +#define MSByte_multiple 3
   14.21 +
   14.22 +struct vmx_virpit_t {
   14.23 +    /* for simulation of counter 0 in mode 2*/
   14.24 +    int vector;				/* the pit irq vector */
   14.25 +    unsigned int period;		/* the frequency. e.g. 10ms*/
   14.26 +    unsigned int channel;		/* the pit channel, counter 0~2 */
   14.27 +    unsigned long *intr_bitmap;
   14.28 +    unsigned int pending_intr_nr;	/* the couner for pending timer interrupts */
   14.29 +    unsigned long long inject_point;	/* the time inject virt intr */
   14.30 +    struct ac_timer pit_timer;		/* periodic timer for mode 2*/
   14.31 +
   14.32 +    /* virtual PIT state for handle related I/O */
   14.33 +    int read_state;
   14.34 +    int count_LSB_latched;
   14.35 +    int count_MSB_latched;
   14.36 +
   14.37 +    unsigned int count;		/* the 16 bit channel count */
   14.38 +    unsigned int init_val;	/* the init value for the counter */
   14.39 +
   14.40 +} ;
   14.41 +
   14.42 +/* to hook the ioreq packet to get the PIT initializaiton info */
   14.43 +extern void vmx_hooks_assist(struct exec_domain *d);
   14.44 +
   14.45 +#endif /* _VMX_VIRPIT_H_ */
   14.46 +
   14.47 +#ifndef _VMX_VIRPIT_H
   14.48 +#define _VMX_VIRPIT_H
   14.49 +#include <xen/config.h>
   14.50 +#include <xen/init.h>
   14.51 +#include <xen/lib.h>
   14.52 +#include <xen/time.h>
   14.53 +#include <xen/errno.h>
   14.54 +#include <xen/ac_timer.h>
   14.55 +#include <asm/vmx_vmcs.h>
   14.56 +
   14.57 +#define PIT_FREQ 1193181
   14.58 +
   14.59 +#define LSByte 0
   14.60 +#define MSByte 1
   14.61 +#define LSByte_multiple 2
   14.62 +#define MSByte_multiple 3
   14.63 +
   14.64 +struct vmx_virpit_t {
   14.65 +    /* for simulation of counter 0 in mode 2*/
   14.66 +    int vector;				/* the pit irq vector */
   14.67 +    unsigned int period;		/* the frequency. e.g. 10ms*/
   14.68 +    unsigned int channel;		/* the pit channel, counter 0~2 */
   14.69 +    unsigned long *intr_bitmap;
   14.70 +    unsigned int pending_intr_nr;	/* the couner for pending timer interrupts */
   14.71 +    unsigned long long inject_point;	/* the time inject virt intr */
   14.72 +    struct ac_timer pit_timer;		/* periodic timer for mode 2*/
   14.73 +
   14.74 +    /* virtual PIT state for handle related I/O */
   14.75 +    int read_state;
   14.76 +    int count_LSB_latched;
   14.77 +    int count_MSB_latched;
   14.78 +
   14.79 +    unsigned int count;		/* the 16 bit channel count */
   14.80 +    unsigned int init_val;	/* the init value for the counter */
   14.81 +
   14.82 +} ;
   14.83 +
   14.84 +#endif /* _VMX_VIRPIT_H_ */
    15.1 --- a/xen/include/public/io/ioreq.h	Tue Feb 08 23:17:38 2005 +0000
    15.2 +++ b/xen/include/public/io/ioreq.h	Tue Feb 08 23:57:18 2005 +0000
    15.3 @@ -27,6 +27,7 @@
    15.4  #define STATE_IOREQ_READY       1
    15.5  #define STATE_IOREQ_INPROCESS   2
    15.6  #define STATE_IORESP_READY      3
    15.7 +#define STATE_IORESP_HOOK       4
    15.8  
    15.9  #define IOPACKET_PORT   2
   15.10