xen-vtx-unstable

annotate xen/arch/x86/vmx_intercept.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 3feb7fa331ed b6c98fe62e1a
children e7c7196fa329 8ca0f98ba8e2
rev   line source
iap10@3749 1 /*
iap10@3749 2 * vmx_intercept.c: Handle performance critical I/O packets in hypervisor space
iap10@3749 3 * Copyright (c) 2004, Intel Corporation.
iap10@3749 4 *
iap10@3749 5 * This program is free software; you can redistribute it and/or modify it
iap10@3749 6 * under the terms and conditions of the GNU General Public License,
iap10@3749 7 * version 2, as published by the Free Software Foundation.
iap10@3749 8 *
iap10@3749 9 * This program is distributed in the hope it will be useful, but WITHOUT
iap10@3749 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
iap10@3749 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
iap10@3749 12 * more details.
iap10@3749 13 *
iap10@3749 14 * You should have received a copy of the GNU General Public License along with
iap10@3749 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
iap10@3749 16 * Place - Suite 330, Boston, MA 02111-1307 USA.
iap10@3749 17 *
iap10@3749 18 */
iap10@3749 19
iap10@3749 20 #include <xen/config.h>
iap10@3749 21 #include <xen/types.h>
iap10@3749 22 #include <asm/vmx.h>
iap10@3749 23 #include <asm/vmx_platform.h>
iap10@3749 24 #include <asm/vmx_virpit.h>
iap10@3749 25 #include <asm/vmx_intercept.h>
iap10@3749 26 #include <public/io/ioreq.h>
iap10@3749 27 #include <xen/lib.h>
iap10@3749 28 #include <xen/sched.h>
iap10@3749 29 #include <asm/current.h>
kaf24@5812 30 #include <io_ports.h>
iap10@3749 31
maf46@3930 32 #ifdef CONFIG_VMX
maf46@3930 33
arun@5609 34 /* Check if the request is handled inside xen
arun@5609 35 return value: 0 --not handled; 1 --handled */
arun@5609 36 int vmx_io_intercept(ioreq_t *p, int type)
iap10@3749 37 {
kaf24@5289 38 struct vcpu *d = current;
arun@5608 39 struct vmx_handler_t *handler = &(d->domain->arch.vmx_platform.vmx_handler);
iap10@3749 40 int i;
arun@4588 41 unsigned long addr, offset;
iap10@3749 42 for (i = 0; i < handler->num_slot; i++) {
arun@5609 43 if( type != handler->hdl_list[i].type)
arun@5609 44 continue;
iap10@3749 45 addr = handler->hdl_list[i].addr;
iap10@3749 46 offset = handler->hdl_list[i].offset;
iap10@3749 47 if (p->addr >= addr &&
kaf24@6730 48 p->addr < addr + offset)
kaf24@6730 49 return handler->hdl_list[i].action(p);
iap10@3749 50 }
iap10@3749 51 return 0;
iap10@3749 52 }
iap10@3749 53
arun@5609 54 int register_io_handler(unsigned long addr, unsigned long offset,
arun@5609 55 intercept_action_t action, int type)
iap10@3749 56 {
kaf24@5289 57 struct vcpu *d = current;
arun@5608 58 struct vmx_handler_t *handler = &(d->domain->arch.vmx_platform.vmx_handler);
iap10@3749 59 int num = handler->num_slot;
iap10@3749 60
iap10@3749 61 if (num >= MAX_IO_HANDLER) {
iap10@3749 62 printk("no extra space, register io interceptor failed!\n");
kaf24@4325 63 domain_crash_synchronous();
iap10@3749 64 }
iap10@3749 65
iap10@3749 66 handler->hdl_list[num].addr = addr;
iap10@3749 67 handler->hdl_list[num].offset = offset;
iap10@3749 68 handler->hdl_list[num].action = action;
arun@5609 69 handler->hdl_list[num].type = type;
iap10@3749 70 handler->num_slot++;
iap10@3749 71 return 1;
iap10@3749 72
iap10@3749 73 }
iap10@3749 74
iap10@3749 75 static void pit_cal_count(struct vmx_virpit_t *vpit)
iap10@3749 76 {
kaf24@6109 77 u64 nsec_delta = (unsigned int)((NOW() - vpit->inject_point));
kaf24@6109 78 if (nsec_delta > vpit->period)
maf46@3855 79 VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:long time has passed from last injection!");
kaf24@6109 80 vpit->count = vpit->init_val - ((nsec_delta * PIT_FREQ / 1000000000ULL) % vpit->init_val );
iap10@3749 81 }
iap10@3749 82
iap10@3749 83 static void pit_latch_io(struct vmx_virpit_t *vpit)
iap10@3749 84 {
iap10@3749 85 pit_cal_count(vpit);
iap10@3749 86
iap10@3749 87 switch(vpit->read_state) {
iap10@3749 88 case MSByte:
iap10@3749 89 vpit->count_MSB_latched=1;
iap10@3749 90 break;
iap10@3749 91 case LSByte:
iap10@3749 92 vpit->count_LSB_latched=1;
iap10@3749 93 break;
iap10@3749 94 case LSByte_multiple:
iap10@3749 95 vpit->count_LSB_latched=1;
iap10@3749 96 vpit->count_MSB_latched=1;
iap10@3749 97 break;
iap10@3749 98 case MSByte_multiple:
iap10@3749 99 VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT:latch PIT counter before MSB_multiple!");
iap10@3749 100 vpit->read_state=LSByte_multiple;
iap10@3749 101 vpit->count_LSB_latched=1;
iap10@3749 102 vpit->count_MSB_latched=1;
iap10@3749 103 break;
iap10@3749 104 default:
iap10@3749 105 BUG();
iap10@3749 106 }
iap10@3749 107 }
iap10@3749 108
iap10@3749 109 static int pit_read_io(struct vmx_virpit_t *vpit)
iap10@3749 110 {
iap10@3749 111 if(vpit->count_LSB_latched) {
iap10@3749 112 /* Read Least Significant Byte */
iap10@3749 113 if(vpit->read_state==LSByte_multiple) {
iap10@3749 114 vpit->read_state=MSByte_multiple;
iap10@3749 115 }
iap10@3749 116 vpit->count_LSB_latched=0;
iap10@3749 117 return (vpit->count & 0xFF);
iap10@3749 118 } else if(vpit->count_MSB_latched) {
iap10@3749 119 /* Read Most Significant Byte */
iap10@3749 120 if(vpit->read_state==MSByte_multiple) {
iap10@3749 121 vpit->read_state=LSByte_multiple;
iap10@3749 122 }
iap10@3749 123 vpit->count_MSB_latched=0;
iap10@3749 124 return ((vpit->count>>8) & 0xFF);
iap10@3749 125 } else {
iap10@3749 126 /* Unlatched Count Read */
iap10@3749 127 VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT: unlatched read");
iap10@3749 128 pit_cal_count(vpit);
iap10@3749 129 if(!(vpit->read_state & 0x1)) {
iap10@3749 130 /* Read Least Significant Byte */
iap10@3749 131 if(vpit->read_state==LSByte_multiple) {
iap10@3749 132 vpit->read_state=MSByte_multiple;
iap10@3749 133 }
iap10@3749 134 return (vpit->count & 0xFF);
iap10@3749 135 } else {
iap10@3749 136 /* Read Most Significant Byte */
iap10@3749 137 if(vpit->read_state==MSByte_multiple) {
iap10@3749 138 vpit->read_state=LSByte_multiple;
iap10@3749 139 }
iap10@3749 140 return ((vpit->count>>8) & 0xFF);
iap10@3749 141 }
iap10@3749 142 }
iap10@3749 143 }
iap10@3749 144
iap10@3749 145 /* vmx_io_assist light-weight version, specific to PIT DM */
iap10@3749 146 static void resume_pit_io(ioreq_t *p)
iap10@3749 147 {
kaf24@4923 148 struct cpu_user_regs *regs = guest_cpu_user_regs();
kaf24@4683 149 unsigned long old_eax = regs->eax;
iap10@3749 150 p->state = STATE_INVALID;
iap10@3749 151
iap10@3749 152 switch(p->size) {
iap10@3749 153 case 1:
kaf24@4683 154 regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
iap10@3749 155 break;
iap10@3749 156 case 2:
kaf24@4683 157 regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
iap10@3749 158 break;
iap10@3749 159 case 4:
kaf24@4683 160 regs->eax = (p->u.data & 0xffffffff);
iap10@3749 161 break;
iap10@3749 162 default:
iap10@3749 163 BUG();
iap10@3749 164 }
iap10@3749 165 }
iap10@3749 166
iap10@3749 167 /* the intercept action for PIT DM retval:0--not handled; 1--handled */
iap10@3749 168 int intercept_pit_io(ioreq_t *p)
iap10@3749 169 {
kaf24@5289 170 struct vcpu *d = current;
arun@5608 171 struct vmx_virpit_t *vpit = &(d->domain->arch.vmx_platform.vmx_pit);
iap10@3749 172
iap10@3749 173 if (p->size != 1 ||
iap10@3749 174 p->pdata_valid ||
kaf24@6730 175 p->type != IOREQ_TYPE_PIO)
iap10@3749 176 return 0;
iap10@3749 177
kaf24@5812 178 if (p->addr == PIT_MODE &&
kaf24@6730 179 p->dir == 0 && /* write */
kaf24@6730 180 ((p->u.data >> 4) & 0x3) == 0 && /* latch command */
iap10@3749 181 ((p->u.data >> 6) & 0x3) == (vpit->channel)) {/* right channel */
iap10@3749 182 pit_latch_io(vpit);
kaf24@6730 183 return 1;
iap10@3749 184 }
iap10@3749 185
kaf24@5812 186 if (p->addr == (PIT_CH0 + vpit->channel) &&
kaf24@6730 187 p->dir == 1) { /* read */
iap10@3749 188 p->u.data = pit_read_io(vpit);
iap10@3749 189 resume_pit_io(p);
kaf24@6730 190 return 1;
iap10@3749 191 }
iap10@3749 192
iap10@3749 193 return 0;
iap10@3749 194 }
iap10@3749 195
iap10@3749 196 /* hooks function for the PIT initialization response iopacket */
kaf24@5152 197 static void pit_timer_fn(void *data)
iap10@3749 198 {
kaf24@5152 199 struct vmx_virpit_t *vpit = data;
kaf24@6109 200 s_time_t next;
kaf24@6109 201 int missed_ticks;
kaf24@5842 202
kaf24@6109 203 missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period;
iap10@3749 204
kaf24@5152 205 /* Set the pending intr bit, and send evtchn notification to myself. */
iap10@3749 206 if (test_and_set_bit(vpit->vector, vpit->intr_bitmap))
kaf24@5152 207 vpit->pending_intr_nr++; /* already set, then count the pending intr */
iap10@3749 208
kaf24@5842 209 /* pick up missed timer tick */
kaf24@5842 210 if ( missed_ticks > 0 ) {
kaf24@5920 211 vpit->pending_intr_nr += missed_ticks;
kaf24@6109 212 vpit->scheduled += missed_ticks * vpit->period;
kaf24@5842 213 }
kaf24@6109 214 next = vpit->scheduled + vpit->period;
kaf24@6109 215 set_ac_timer(&vpit->pit_timer, next);
kaf24@6109 216 vpit->scheduled = next;
iap10@3749 217 }
iap10@3749 218
iap10@3749 219 /* Only some PIT operations such as load init counter need a hypervisor hook.
arun@3920 220 * leave all other operations in user space DM
iap10@3749 221 */
kaf24@5289 222 void vmx_hooks_assist(struct vcpu *d)
iap10@3749 223 {
arun@5608 224 vcpu_iodata_t * vio = get_vio(d->domain, d->vcpu_id);
iap10@3749 225 ioreq_t *p = &vio->vp_ioreq;
arun@5615 226 shared_iopage_t *sp = get_sp(d->domain);
arun@5615 227 u64 *intr = &(sp->sp_global.pic_intr[0]);
arun@5608 228 struct vmx_virpit_t *vpit = &(d->domain->arch.vmx_platform.vmx_pit);
kaf24@5647 229 int rw_mode, reinit = 0;
iap10@3749 230
arun@3920 231 /* load init count*/
arun@3920 232 if (p->state == STATE_IORESP_HOOK) {
arun@5558 233 /* set up actimer, handle re-init */
arun@5558 234 if ( active_ac_timer(&(vpit->pit_timer)) ) {
arun@5558 235 VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT: guest reset PIT with channel %lx!\n", (unsigned long) ((p->u.data >> 24) & 0x3) );
arun@5558 236 rem_ac_timer(&(vpit->pit_timer));
kaf24@5647 237 reinit = 1;
arun@5558 238 }
arun@5558 239 else
kaf24@6109 240 init_ac_timer(&vpit->pit_timer, pit_timer_fn, vpit, d->processor);
arun@5558 241
arun@3920 242 /* init count for this channel */
arun@3920 243 vpit->init_val = (p->u.data & 0xFFFF) ;
kaf24@6109 244 /* frequency(ns) of pit */
kaf24@6109 245 vpit->period = DIV_ROUND(((vpit->init_val) * 1000000000ULL), PIT_FREQ);
kaf24@6109 246 VMX_DBG_LOG(DBG_LEVEL_1,"VMX_PIT: guest set init pit freq:%u ns, initval:0x%x\n", vpit->period, vpit->init_val);
kaf24@6109 247 if (vpit->period < 900000) { /* < 0.9 ms */
kaf24@4654 248 printk("VMX_PIT: guest programmed too small an init_val: %x\n",
arun@3920 249 vpit->init_val);
kaf24@6109 250 vpit->period = 1000000;
arun@3920 251 }
iap10@3749 252 vpit->vector = ((p->u.data >> 16) & 0xFF);
iap10@3749 253 vpit->channel = ((p->u.data >> 24) & 0x3);
arun@3920 254 vpit->first_injected = 0;
iap10@3749 255
kaf24@6730 256 vpit->count_LSB_latched = 0;
kaf24@6730 257 vpit->count_MSB_latched = 0;
iap10@3749 258
iap10@3749 259 rw_mode = ((p->u.data >> 26) & 0x3);
iap10@3749 260 switch(rw_mode) {
iap10@3749 261 case 0x1:
iap10@3749 262 vpit->read_state=LSByte;
iap10@3749 263 break;
iap10@3749 264 case 0x2:
iap10@3749 265 vpit->read_state=MSByte;
iap10@3749 266 break;
iap10@3749 267 case 0x3:
iap10@3749 268 vpit->read_state=LSByte_multiple;
iap10@3749 269 break;
iap10@3749 270 default:
iap10@3749 271 printk("VMX_PIT:wrong PIT rw_mode!\n");
iap10@3749 272 break;
iap10@3749 273 }
iap10@3749 274
iap10@3749 275 vpit->intr_bitmap = intr;
iap10@3749 276
kaf24@6109 277 vpit->scheduled = NOW() + vpit->period;
kaf24@5842 278 set_ac_timer(&vpit->pit_timer, vpit->scheduled);
iap10@3749 279
iap10@3749 280 /*restore the state*/
iap10@3749 281 p->state = STATE_IORESP_READY;
iap10@3749 282
kaf24@6730 283 /* register handler to intercept the PIT io when vm_exit */
kaf24@5647 284 if (!reinit)
kaf24@6730 285 register_portio_handler(0x40, 4, intercept_pit_io);
iap10@3749 286 }
iap10@3749 287 }
maf46@3930 288 #endif /* CONFIG_VMX */
kaf24@6730 289
kaf24@6730 290 /*
kaf24@6730 291 * Local variables:
kaf24@6730 292 * mode: C
kaf24@6730 293 * c-set-style: "BSD"
kaf24@6730 294 * c-basic-offset: 4
kaf24@6730 295 * tab-width: 4
kaf24@6730 296 * indent-tabs-mode: nil
kaf24@6730 297 * End:
kaf24@6730 298 */