diff options
| author | Eddie Dong <eddie.dong@intel.com> | 2007-07-06 05:20:49 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:24 -0400 |
| commit | 85f455f7ddbed403b34b4d54b1eaf0e14126a126 (patch) | |
| tree | 1dba7aa8fee3c8f756e12049c496dee5baae752c | |
| parent | 152d3f2f246ce3c2a0cf2fc6c2214663cd99aa83 (diff) | |
KVM: Add support for in-kernel PIC emulation
Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
| -rw-r--r-- | drivers/kvm/Makefile | 2 | ||||
| -rw-r--r-- | drivers/kvm/i8259.c | 442 | ||||
| -rw-r--r-- | drivers/kvm/irq.c | 61 | ||||
| -rw-r--r-- | drivers/kvm/irq.h | 64 | ||||
| -rw-r--r-- | drivers/kvm/kvm.h | 11 | ||||
| -rw-r--r-- | drivers/kvm/kvm_main.c | 46 | ||||
| -rw-r--r-- | drivers/kvm/svm.c | 69 | ||||
| -rw-r--r-- | drivers/kvm/vmx.c | 80 | ||||
| -rw-r--r-- | include/linux/kvm.h | 19 |
9 files changed, 770 insertions, 24 deletions
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile index c0a789fa9d65..952dff38eb6c 100644 --- a/drivers/kvm/Makefile +++ b/drivers/kvm/Makefile | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Makefile for Kernel-based Virtual Machine module | 2 | # Makefile for Kernel-based Virtual Machine module |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | kvm-objs := kvm_main.o mmu.o x86_emulate.o | 5 | kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o |
| 6 | obj-$(CONFIG_KVM) += kvm.o | 6 | obj-$(CONFIG_KVM) += kvm.o |
| 7 | kvm-intel-objs = vmx.o | 7 | kvm-intel-objs = vmx.o |
| 8 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o | 8 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o |
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c new file mode 100644 index 000000000000..40ad10462238 --- /dev/null +++ b/drivers/kvm/i8259.c | |||
| @@ -0,0 +1,442 @@ | |||
| 1 | /* | ||
| 2 | * 8259 interrupt controller emulation | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003-2004 Fabrice Bellard | ||
| 5 | * Copyright (c) 2007 Intel Corporation | ||
| 6 | * | ||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 8 | * of this software and associated documentation files (the "Software"), to deal | ||
| 9 | * in the Software without restriction, including without limitation the rights | ||
| 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 11 | * copies of the Software, and to permit persons to whom the Software is | ||
| 12 | * furnished to do so, subject to the following conditions: | ||
| 13 | * | ||
| 14 | * The above copyright notice and this permission notice shall be included in | ||
| 15 | * all copies or substantial portions of the Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 23 | * THE SOFTWARE. | ||
| 24 | * Authors: | ||
| 25 | * Yaozu (Eddie) Dong <Eddie.dong@intel.com> | ||
| 26 | * Port from Qemu. | ||
| 27 | */ | ||
| 28 | #include <linux/mm.h> | ||
| 29 | #include "irq.h" | ||
| 30 | |||
| 31 | /* | ||
| 32 | * set irq level. If an edge is detected, then the IRR is set to 1 | ||
| 33 | */ | ||
| 34 | static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) | ||
| 35 | { | ||
| 36 | int mask; | ||
| 37 | mask = 1 << irq; | ||
| 38 | if (s->elcr & mask) /* level triggered */ | ||
| 39 | if (level) { | ||
| 40 | s->irr |= mask; | ||
| 41 | s->last_irr |= mask; | ||
| 42 | } else { | ||
| 43 | s->irr &= ~mask; | ||
| 44 | s->last_irr &= ~mask; | ||
| 45 | } | ||
| 46 | else /* edge triggered */ | ||
| 47 | if (level) { | ||
| 48 | if ((s->last_irr & mask) == 0) | ||
| 49 | s->irr |= mask; | ||
| 50 | s->last_irr |= mask; | ||
| 51 | } else | ||
| 52 | s->last_irr &= ~mask; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* | ||
| 56 | * return the highest priority found in mask (highest = smallest | ||
| 57 | * number). Return 8 if no irq | ||
| 58 | */ | ||
| 59 | static inline int get_priority(struct kvm_kpic_state *s, int mask) | ||
| 60 | { | ||
| 61 | int priority; | ||
| 62 | if (mask == 0) | ||
| 63 | return 8; | ||
| 64 | priority = 0; | ||
| 65 | while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) | ||
| 66 | priority++; | ||
| 67 | return priority; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * return the pic wanted interrupt. return -1 if none | ||
| 72 | */ | ||
| 73 | static int pic_get_irq(struct kvm_kpic_state *s) | ||
| 74 | { | ||
| 75 | int mask, cur_priority, priority; | ||
| 76 | |||
| 77 | mask = s->irr & ~s->imr; | ||
| 78 | priority = get_priority(s, mask); | ||
| 79 | if (priority == 8) | ||
| 80 | return -1; | ||
| 81 | /* | ||
| 82 | * compute current priority. If special fully nested mode on the | ||
| 83 | * master, the IRQ coming from the slave is not taken into account | ||
| 84 | * for the priority computation. | ||
| 85 | */ | ||
| 86 | mask = s->isr; | ||
| 87 | if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) | ||
| 88 | mask &= ~(1 << 2); | ||
| 89 | cur_priority = get_priority(s, mask); | ||
| 90 | if (priority < cur_priority) | ||
| 91 | /* | ||
| 92 | * higher priority found: an irq should be generated | ||
| 93 | */ | ||
| 94 | return (priority + s->priority_add) & 7; | ||
| 95 | else | ||
| 96 | return -1; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * raise irq to CPU if necessary. must be called every time the active | ||
| 101 | * irq may change | ||
| 102 | */ | ||
| 103 | static void pic_update_irq(struct kvm_pic *s) | ||
| 104 | { | ||
| 105 | int irq2, irq; | ||
| 106 | |||
| 107 | irq2 = pic_get_irq(&s->pics[1]); | ||
| 108 | if (irq2 >= 0) { | ||
| 109 | /* | ||
| 110 | * if irq request by slave pic, signal master PIC | ||
| 111 | */ | ||
| 112 | pic_set_irq1(&s->pics[0], 2, 1); | ||
| 113 | pic_set_irq1(&s->pics[0], 2, 0); | ||
| 114 | } | ||
| 115 | irq = pic_get_irq(&s->pics[0]); | ||
| 116 | if (irq >= 0) | ||
| 117 | s->irq_request(s->irq_request_opaque, 1); | ||
| 118 | else | ||
| 119 | s->irq_request(s->irq_request_opaque, 0); | ||
| 120 | } | ||
| 121 | |||
| 122 | void kvm_pic_set_irq(void *opaque, int irq, int level) | ||
| 123 | { | ||
| 124 | struct kvm_pic *s = opaque; | ||
| 125 | |||
| 126 | pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); | ||
| 127 | pic_update_irq(s); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * acknowledge interrupt 'irq' | ||
| 132 | */ | ||
| 133 | static inline void pic_intack(struct kvm_kpic_state *s, int irq) | ||
| 134 | { | ||
| 135 | if (s->auto_eoi) { | ||
| 136 | if (s->rotate_on_auto_eoi) | ||
| 137 | s->priority_add = (irq + 1) & 7; | ||
| 138 | } else | ||
| 139 | s->isr |= (1 << irq); | ||
| 140 | /* | ||
| 141 | * We don't clear a level sensitive interrupt here | ||
| 142 | */ | ||
| 143 | if (!(s->elcr & (1 << irq))) | ||
| 144 | s->irr &= ~(1 << irq); | ||
| 145 | } | ||
| 146 | |||
| 147 | int kvm_pic_read_irq(struct kvm_pic *s) | ||
| 148 | { | ||
| 149 | int irq, irq2, intno; | ||
| 150 | |||
| 151 | irq = pic_get_irq(&s->pics[0]); | ||
| 152 | if (irq >= 0) { | ||
| 153 | pic_intack(&s->pics[0], irq); | ||
| 154 | if (irq == 2) { | ||
| 155 | irq2 = pic_get_irq(&s->pics[1]); | ||
| 156 | if (irq2 >= 0) | ||
| 157 | pic_intack(&s->pics[1], irq2); | ||
| 158 | else | ||
| 159 | /* | ||
| 160 | * spurious IRQ on slave controller | ||
| 161 | */ | ||
| 162 | irq2 = 7; | ||
| 163 | intno = s->pics[1].irq_base + irq2; | ||
| 164 | irq = irq2 + 8; | ||
| 165 | } else | ||
| 166 | intno = s->pics[0].irq_base + irq; | ||
| 167 | } else { | ||
| 168 | /* | ||
| 169 | * spurious IRQ on host controller | ||
| 170 | */ | ||
| 171 | irq = 7; | ||
| 172 | intno = s->pics[0].irq_base + irq; | ||
| 173 | } | ||
| 174 | pic_update_irq(s); | ||
| 175 | |||
| 176 | return intno; | ||
| 177 | } | ||
| 178 | |||
| 179 | static void pic_reset(void *opaque) | ||
| 180 | { | ||
| 181 | struct kvm_kpic_state *s = opaque; | ||
| 182 | |||
| 183 | s->last_irr = 0; | ||
| 184 | s->irr = 0; | ||
| 185 | s->imr = 0; | ||
| 186 | s->isr = 0; | ||
| 187 | s->priority_add = 0; | ||
| 188 | s->irq_base = 0; | ||
| 189 | s->read_reg_select = 0; | ||
| 190 | s->poll = 0; | ||
| 191 | s->special_mask = 0; | ||
| 192 | s->init_state = 0; | ||
| 193 | s->auto_eoi = 0; | ||
| 194 | s->rotate_on_auto_eoi = 0; | ||
| 195 | s->special_fully_nested_mode = 0; | ||
| 196 | s->init4 = 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | static void pic_ioport_write(void *opaque, u32 addr, u32 val) | ||
| 200 | { | ||
| 201 | struct kvm_kpic_state *s = opaque; | ||
| 202 | int priority, cmd, irq; | ||
| 203 | |||
| 204 | addr &= 1; | ||
| 205 | if (addr == 0) { | ||
| 206 | if (val & 0x10) { | ||
| 207 | pic_reset(s); /* init */ | ||
| 208 | /* | ||
| 209 | * deassert a pending interrupt | ||
| 210 | */ | ||
| 211 | s->pics_state->irq_request(s->pics_state-> | ||
| 212 | irq_request_opaque, 0); | ||
| 213 | s->init_state = 1; | ||
| 214 | s->init4 = val & 1; | ||
| 215 | if (val & 0x02) | ||
| 216 | printk(KERN_ERR "single mode not supported"); | ||
| 217 | if (val & 0x08) | ||
| 218 | printk(KERN_ERR | ||
| 219 | "level sensitive irq not supported"); | ||
| 220 | } else if (val & 0x08) { | ||
| 221 | if (val & 0x04) | ||
| 222 | s->poll = 1; | ||
| 223 | if (val & 0x02) | ||
| 224 | s->read_reg_select = val & 1; | ||
| 225 | if (val & 0x40) | ||
| 226 | s->special_mask = (val >> 5) & 1; | ||
| 227 | } else { | ||
| 228 | cmd = val >> 5; | ||
| 229 | switch (cmd) { | ||
| 230 | case 0: | ||
| 231 | case 4: | ||
| 232 | s->rotate_on_auto_eoi = cmd >> 2; | ||
| 233 | break; | ||
| 234 | case 1: /* end of interrupt */ | ||
| 235 | case 5: | ||
| 236 | priority = get_priority(s, s->isr); | ||
| 237 | if (priority != 8) { | ||
| 238 | irq = (priority + s->priority_add) & 7; | ||
| 239 | s->isr &= ~(1 << irq); | ||
| 240 | if (cmd == 5) | ||
| 241 | s->priority_add = (irq + 1) & 7; | ||
| 242 | pic_update_irq(s->pics_state); | ||
| 243 | } | ||
| 244 | break; | ||
| 245 | case 3: | ||
| 246 | irq = val & 7; | ||
| 247 | s->isr &= ~(1 << irq); | ||
| 248 | pic_update_irq(s->pics_state); | ||
| 249 | break; | ||
| 250 | case 6: | ||
| 251 | s->priority_add = (val + 1) & 7; | ||
| 252 | pic_update_irq(s->pics_state); | ||
| 253 | break; | ||
| 254 | case 7: | ||
| 255 | irq = val & 7; | ||
| 256 | s->isr &= ~(1 << irq); | ||
| 257 | s->priority_add = (irq + 1) & 7; | ||
| 258 | pic_update_irq(s->pics_state); | ||
| 259 | break; | ||
| 260 | default: | ||
| 261 | break; /* no operation */ | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } else | ||
| 265 | switch (s->init_state) { | ||
| 266 | case 0: /* normal mode */ | ||
| 267 | s->imr = val; | ||
| 268 | pic_update_irq(s->pics_state); | ||
| 269 | break; | ||
| 270 | case 1: | ||
| 271 | s->irq_base = val & 0xf8; | ||
| 272 | s->init_state = 2; | ||
| 273 | break; | ||
| 274 | case 2: | ||
| 275 | if (s->init4) | ||
| 276 | s->init_state = 3; | ||
| 277 | else | ||
| 278 | s->init_state = 0; | ||
| 279 | break; | ||
| 280 | case 3: | ||
| 281 | s->special_fully_nested_mode = (val >> 4) & 1; | ||
| 282 | s->auto_eoi = (val >> 1) & 1; | ||
| 283 | s->init_state = 0; | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) | ||
| 289 | { | ||
| 290 | int ret; | ||
| 291 | |||
| 292 | ret = pic_get_irq(s); | ||
| 293 | if (ret >= 0) { | ||
| 294 | if (addr1 >> 7) { | ||
| 295 | s->pics_state->pics[0].isr &= ~(1 << 2); | ||
| 296 | s->pics_state->pics[0].irr &= ~(1 << 2); | ||
| 297 | } | ||
| 298 | s->irr &= ~(1 << ret); | ||
| 299 | s->isr &= ~(1 << ret); | ||
| 300 | if (addr1 >> 7 || ret != 2) | ||
| 301 | pic_update_irq(s->pics_state); | ||
| 302 | } else { | ||
| 303 | ret = 0x07; | ||
| 304 | pic_update_irq(s->pics_state); | ||
| 305 | } | ||
| 306 | |||
| 307 | return ret; | ||
| 308 | } | ||
| 309 | |||
| 310 | static u32 pic_ioport_read(void *opaque, u32 addr1) | ||
| 311 | { | ||
| 312 | struct kvm_kpic_state *s = opaque; | ||
| 313 | unsigned int addr; | ||
| 314 | int ret; | ||
| 315 | |||
| 316 | addr = addr1; | ||
| 317 | addr &= 1; | ||
| 318 | if (s->poll) { | ||
| 319 | ret = pic_poll_read(s, addr1); | ||
| 320 | s->poll = 0; | ||
| 321 | } else | ||
| 322 | if (addr == 0) | ||
| 323 | if (s->read_reg_select) | ||
| 324 | ret = s->isr; | ||
| 325 | else | ||
| 326 | ret = s->irr; | ||
| 327 | else | ||
| 328 | ret = s->imr; | ||
| 329 | return ret; | ||
| 330 | } | ||
| 331 | |||
| 332 | static void elcr_ioport_write(void *opaque, u32 addr, u32 val) | ||
| 333 | { | ||
| 334 | struct kvm_kpic_state *s = opaque; | ||
| 335 | s->elcr = val & s->elcr_mask; | ||
| 336 | } | ||
| 337 | |||
| 338 | static u32 elcr_ioport_read(void *opaque, u32 addr1) | ||
| 339 | { | ||
| 340 | struct kvm_kpic_state *s = opaque; | ||
| 341 | return s->elcr; | ||
| 342 | } | ||
| 343 | |||
| 344 | static int picdev_in_range(struct kvm_io_device *this, gpa_t addr) | ||
| 345 | { | ||
| 346 | switch (addr) { | ||
| 347 | case 0x20: | ||
| 348 | case 0x21: | ||
| 349 | case 0xa0: | ||
| 350 | case 0xa1: | ||
| 351 | case 0x4d0: | ||
| 352 | case 0x4d1: | ||
| 353 | return 1; | ||
| 354 | default: | ||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | static void picdev_write(struct kvm_io_device *this, | ||
| 360 | gpa_t addr, int len, const void *val) | ||
| 361 | { | ||
| 362 | struct kvm_pic *s = this->private; | ||
| 363 | unsigned char data = *(unsigned char *)val; | ||
| 364 | |||
| 365 | if (len != 1) { | ||
| 366 | if (printk_ratelimit()) | ||
| 367 | printk(KERN_ERR "PIC: non byte write\n"); | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | switch (addr) { | ||
| 371 | case 0x20: | ||
| 372 | case 0x21: | ||
| 373 | case 0xa0: | ||
| 374 | case 0xa1: | ||
| 375 | pic_ioport_write(&s->pics[addr >> 7], addr, data); | ||
| 376 | break; | ||
| 377 | case 0x4d0: | ||
| 378 | case 0x4d1: | ||
| 379 | elcr_ioport_write(&s->pics[addr & 1], addr, data); | ||
| 380 | break; | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | static void picdev_read(struct kvm_io_device *this, | ||
| 385 | gpa_t addr, int len, void *val) | ||
| 386 | { | ||
| 387 | struct kvm_pic *s = this->private; | ||
| 388 | unsigned char data = 0; | ||
| 389 | |||
| 390 | if (len != 1) { | ||
| 391 | if (printk_ratelimit()) | ||
| 392 | printk(KERN_ERR "PIC: non byte read\n"); | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | switch (addr) { | ||
| 396 | case 0x20: | ||
| 397 | case 0x21: | ||
| 398 | case 0xa0: | ||
| 399 | case 0xa1: | ||
| 400 | data = pic_ioport_read(&s->pics[addr >> 7], addr); | ||
| 401 | break; | ||
| 402 | case 0x4d0: | ||
| 403 | case 0x4d1: | ||
| 404 | data = elcr_ioport_read(&s->pics[addr & 1], addr); | ||
| 405 | break; | ||
| 406 | } | ||
| 407 | *(unsigned char *)val = data; | ||
| 408 | } | ||
| 409 | |||
| 410 | /* | ||
| 411 | * callback when PIC0 irq status changed | ||
| 412 | */ | ||
| 413 | static void pic_irq_request(void *opaque, int level) | ||
| 414 | { | ||
| 415 | struct kvm *kvm = opaque; | ||
| 416 | |||
| 417 | pic_irqchip(kvm)->output = level; | ||
| 418 | } | ||
| 419 | |||
| 420 | struct kvm_pic *kvm_create_pic(struct kvm *kvm) | ||
| 421 | { | ||
| 422 | struct kvm_pic *s; | ||
| 423 | s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); | ||
| 424 | if (!s) | ||
| 425 | return NULL; | ||
| 426 | s->pics[0].elcr_mask = 0xf8; | ||
| 427 | s->pics[1].elcr_mask = 0xde; | ||
| 428 | s->irq_request = pic_irq_request; | ||
| 429 | s->irq_request_opaque = kvm; | ||
| 430 | s->pics[0].pics_state = s; | ||
| 431 | s->pics[1].pics_state = s; | ||
| 432 | |||
| 433 | /* | ||
| 434 | * Initialize PIO device | ||
| 435 | */ | ||
| 436 | s->dev.read = picdev_read; | ||
| 437 | s->dev.write = picdev_write; | ||
| 438 | s->dev.in_range = picdev_in_range; | ||
| 439 | s->dev.private = s; | ||
| 440 | kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev); | ||
| 441 | return s; | ||
| 442 | } | ||
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c new file mode 100644 index 000000000000..b08005ca7050 --- /dev/null +++ b/drivers/kvm/irq.c | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* | ||
| 2 | * irq.c: API for in kernel interrupt controller | ||
| 3 | * Copyright (c) 2007, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License along with | ||
| 15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
| 16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
| 17 | * Authors: | ||
| 18 | * Yaozu (Eddie) Dong <Eddie.dong@intel.com> | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/module.h> | ||
| 23 | |||
| 24 | #include "kvm.h" | ||
| 25 | #include "irq.h" | ||
| 26 | |||
| 27 | /* | ||
| 28 | * check if there is pending interrupt without | ||
| 29 | * intack. | ||
| 30 | */ | ||
| 31 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v) | ||
| 32 | { | ||
| 33 | struct kvm_pic *s = pic_irqchip(v->kvm); | ||
| 34 | |||
| 35 | if (s->output) /* PIC */ | ||
| 36 | return 1; | ||
| 37 | /* | ||
| 38 | * TODO: APIC | ||
| 39 | */ | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); | ||
| 43 | |||
| 44 | /* | ||
| 45 | * Read pending interrupt vector and intack. | ||
| 46 | */ | ||
| 47 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v) | ||
| 48 | { | ||
| 49 | struct kvm_pic *s = pic_irqchip(v->kvm); | ||
| 50 | int vector; | ||
| 51 | |||
| 52 | s->output = 0; | ||
| 53 | vector = kvm_pic_read_irq(s); | ||
| 54 | if (vector != -1) | ||
| 55 | return vector; | ||
| 56 | /* | ||
| 57 | * TODO: APIC | ||
| 58 | */ | ||
| 59 | return -1; | ||
| 60 | } | ||
| 61 | EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); | ||
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h new file mode 100644 index 000000000000..bdb2fc34804b --- /dev/null +++ b/drivers/kvm/irq.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* | ||
| 2 | * irq.h: in kernel interrupt controller related definitions | ||
| 3 | * Copyright (c) 2007, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License along with | ||
| 15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
| 16 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
| 17 | * Authors: | ||
| 18 | * Yaozu (Eddie) Dong <Eddie.dong@intel.com> | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef __IRQ_H | ||
| 23 | #define __IRQ_H | ||
| 24 | |||
| 25 | #include "kvm.h" | ||
| 26 | |||
| 27 | typedef void irq_request_func(void *opaque, int level); | ||
| 28 | |||
| 29 | struct kvm_pic; | ||
| 30 | struct kvm_kpic_state { | ||
| 31 | u8 last_irr; /* edge detection */ | ||
| 32 | u8 irr; /* interrupt request register */ | ||
| 33 | u8 imr; /* interrupt mask register */ | ||
| 34 | u8 isr; /* interrupt service register */ | ||
| 35 | u8 priority_add; /* highest irq priority */ | ||
| 36 | u8 irq_base; | ||
| 37 | u8 read_reg_select; | ||
| 38 | u8 poll; | ||
| 39 | u8 special_mask; | ||
| 40 | u8 init_state; | ||
| 41 | u8 auto_eoi; | ||
| 42 | u8 rotate_on_auto_eoi; | ||
| 43 | u8 special_fully_nested_mode; | ||
| 44 | u8 init4; /* true if 4 byte init */ | ||
| 45 | u8 elcr; /* PIIX edge/trigger selection */ | ||
| 46 | u8 elcr_mask; | ||
| 47 | struct kvm_pic *pics_state; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct kvm_pic { | ||
| 51 | struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ | ||
| 52 | irq_request_func *irq_request; | ||
| 53 | void *irq_request_opaque; | ||
| 54 | int output; /* intr from master PIC */ | ||
| 55 | struct kvm_io_device dev; | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct kvm_pic *kvm_create_pic(struct kvm *kvm); | ||
| 59 | void kvm_pic_set_irq(void *opaque, int irq, int level); | ||
| 60 | int kvm_pic_read_irq(struct kvm_pic *s); | ||
| 61 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v); | ||
| 62 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v); | ||
| 63 | |||
| 64 | #endif | ||
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index a42a6f314a85..d71712ddebee 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
| @@ -408,8 +408,19 @@ struct kvm { | |||
| 408 | struct file *filp; | 408 | struct file *filp; |
| 409 | struct kvm_io_bus mmio_bus; | 409 | struct kvm_io_bus mmio_bus; |
| 410 | struct kvm_io_bus pio_bus; | 410 | struct kvm_io_bus pio_bus; |
| 411 | struct kvm_pic *vpic; | ||
| 411 | }; | 412 | }; |
| 412 | 413 | ||
| 414 | static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) | ||
| 415 | { | ||
| 416 | return kvm->vpic; | ||
| 417 | } | ||
| 418 | |||
| 419 | static inline int irqchip_in_kernel(struct kvm *kvm) | ||
| 420 | { | ||
| 421 | return pic_irqchip(kvm) != 0; | ||
| 422 | } | ||
| 423 | |||
| 413 | struct descriptor_table { | 424 | struct descriptor_table { |
| 414 | u16 limit; | 425 | u16 limit; |
| 415 | unsigned long base; | 426 | unsigned long base; |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index d154487b7729..09a04bc9541d 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "kvm.h" | 18 | #include "kvm.h" |
| 19 | #include "x86_emulate.h" | 19 | #include "x86_emulate.h" |
| 20 | #include "segment_descriptor.h" | 20 | #include "segment_descriptor.h" |
| 21 | #include "irq.h" | ||
| 21 | 22 | ||
| 22 | #include <linux/kvm.h> | 23 | #include <linux/kvm.h> |
| 23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| @@ -378,6 +379,7 @@ static void kvm_destroy_vm(struct kvm *kvm) | |||
| 378 | spin_unlock(&kvm_lock); | 379 | spin_unlock(&kvm_lock); |
| 379 | kvm_io_bus_destroy(&kvm->pio_bus); | 380 | kvm_io_bus_destroy(&kvm->pio_bus); |
| 380 | kvm_io_bus_destroy(&kvm->mmio_bus); | 381 | kvm_io_bus_destroy(&kvm->mmio_bus); |
| 382 | kfree(kvm->vpic); | ||
| 381 | kvm_free_vcpus(kvm); | 383 | kvm_free_vcpus(kvm); |
| 382 | kvm_free_physmem(kvm); | 384 | kvm_free_physmem(kvm); |
| 383 | kfree(kvm); | 385 | kfree(kvm); |
| @@ -1258,7 +1260,8 @@ EXPORT_SYMBOL_GPL(emulate_instruction); | |||
| 1258 | 1260 | ||
| 1259 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) | 1261 | int kvm_emulate_halt(struct kvm_vcpu *vcpu) |
| 1260 | { | 1262 | { |
| 1261 | if (vcpu->irq_summary) | 1263 | if (vcpu->irq_summary || |
| 1264 | (irqchip_in_kernel(vcpu->kvm) && kvm_cpu_has_interrupt(vcpu))) | ||
| 1262 | return 1; | 1265 | return 1; |
| 1263 | 1266 | ||
| 1264 | vcpu->run->exit_reason = KVM_EXIT_HLT; | 1267 | vcpu->run->exit_reason = KVM_EXIT_HLT; |
| @@ -2715,6 +2718,30 @@ static long kvm_vm_ioctl(struct file *filp, | |||
| 2715 | goto out; | 2718 | goto out; |
| 2716 | break; | 2719 | break; |
| 2717 | } | 2720 | } |
| 2721 | case KVM_CREATE_IRQCHIP: | ||
| 2722 | r = -ENOMEM; | ||
| 2723 | kvm->vpic = kvm_create_pic(kvm); | ||
| 2724 | if (kvm->vpic) | ||
| 2725 | r = 0; | ||
| 2726 | else | ||
| 2727 | goto out; | ||
| 2728 | break; | ||
| 2729 | case KVM_IRQ_LINE: { | ||
| 2730 | struct kvm_irq_level irq_event; | ||
| 2731 | |||
| 2732 | r = -EFAULT; | ||
| 2733 | if (copy_from_user(&irq_event, argp, sizeof irq_event)) | ||
| 2734 | goto out; | ||
| 2735 | if (irqchip_in_kernel(kvm)) { | ||
| 2736 | if (irq_event.irq < 16) | ||
| 2737 | kvm_pic_set_irq(pic_irqchip(kvm), | ||
| 2738 | irq_event.irq, | ||
| 2739 | irq_event.level); | ||
| 2740 | /* TODO: IOAPIC */ | ||
| 2741 | r = 0; | ||
| 2742 | } | ||
| 2743 | break; | ||
| 2744 | } | ||
| 2718 | default: | 2745 | default: |
| 2719 | ; | 2746 | ; |
| 2720 | } | 2747 | } |
| @@ -2825,12 +2852,19 @@ static long kvm_dev_ioctl(struct file *filp, | |||
| 2825 | r = 0; | 2852 | r = 0; |
| 2826 | break; | 2853 | break; |
| 2827 | } | 2854 | } |
| 2828 | case KVM_CHECK_EXTENSION: | 2855 | case KVM_CHECK_EXTENSION: { |
| 2829 | /* | 2856 | int ext = (long)argp; |
| 2830 | * No extensions defined at present. | 2857 | |
| 2831 | */ | 2858 | switch (ext) { |
| 2832 | r = 0; | 2859 | case KVM_CAP_IRQCHIP: |
| 2860 | r = 1; | ||
| 2861 | break; | ||
| 2862 | default: | ||
| 2863 | r = 0; | ||
| 2864 | break; | ||
| 2865 | } | ||
| 2833 | break; | 2866 | break; |
| 2867 | } | ||
| 2834 | case KVM_GET_VCPU_MMAP_SIZE: | 2868 | case KVM_GET_VCPU_MMAP_SIZE: |
| 2835 | r = -EINVAL; | 2869 | r = -EINVAL; |
| 2836 | if (arg) | 2870 | if (arg) |
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index cc674bfd31d9..2237a594a8ef 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include "kvm_svm.h" | 17 | #include "kvm_svm.h" |
| 18 | #include "x86_emulate.h" | 18 | #include "x86_emulate.h" |
| 19 | #include "irq.h" | ||
| 19 | 20 | ||
| 20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 21 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| @@ -921,7 +922,8 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
| 921 | enum emulation_result er; | 922 | enum emulation_result er; |
| 922 | int r; | 923 | int r; |
| 923 | 924 | ||
| 924 | if (is_external_interrupt(exit_int_info)) | 925 | if (!irqchip_in_kernel(kvm) && |
| 926 | is_external_interrupt(exit_int_info)) | ||
| 925 | push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); | 927 | push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); |
| 926 | 928 | ||
| 927 | mutex_lock(&kvm->lock); | 929 | mutex_lock(&kvm->lock); |
| @@ -1185,6 +1187,8 @@ static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
| 1185 | static int interrupt_window_interception(struct vcpu_svm *svm, | 1187 | static int interrupt_window_interception(struct vcpu_svm *svm, |
| 1186 | struct kvm_run *kvm_run) | 1188 | struct kvm_run *kvm_run) |
| 1187 | { | 1189 | { |
| 1190 | svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); | ||
| 1191 | svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; | ||
| 1188 | /* | 1192 | /* |
| 1189 | * If the user space waits to inject interrupts, exit as soon as | 1193 | * If the user space waits to inject interrupts, exit as soon as |
| 1190 | * possible | 1194 | * possible |
| @@ -1289,22 +1293,56 @@ static void pre_svm_run(struct vcpu_svm *svm) | |||
| 1289 | } | 1293 | } |
| 1290 | 1294 | ||
| 1291 | 1295 | ||
| 1292 | static inline void inject_irq(struct vcpu_svm *svm) | 1296 | static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) |
| 1293 | { | 1297 | { |
| 1294 | struct vmcb_control_area *control; | 1298 | struct vmcb_control_area *control; |
| 1295 | 1299 | ||
| 1296 | control = &svm->vmcb->control; | 1300 | control = &svm->vmcb->control; |
| 1297 | control->int_vector = pop_irq(&svm->vcpu); | 1301 | control->int_vector = irq; |
| 1298 | control->int_ctl &= ~V_INTR_PRIO_MASK; | 1302 | control->int_ctl &= ~V_INTR_PRIO_MASK; |
| 1299 | control->int_ctl |= V_IRQ_MASK | | 1303 | control->int_ctl |= V_IRQ_MASK | |
| 1300 | ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); | 1304 | ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); |
| 1301 | } | 1305 | } |
| 1302 | 1306 | ||
| 1303 | static void reput_irq(struct vcpu_svm *svm) | 1307 | static void svm_intr_assist(struct vcpu_svm *svm) |
| 1304 | { | 1308 | { |
| 1309 | struct vmcb *vmcb = svm->vmcb; | ||
| 1310 | int intr_vector = -1; | ||
| 1311 | |||
| 1312 | if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && | ||
| 1313 | ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { | ||
| 1314 | intr_vector = vmcb->control.exit_int_info & | ||
| 1315 | SVM_EVTINJ_VEC_MASK; | ||
| 1316 | vmcb->control.exit_int_info = 0; | ||
| 1317 | svm_inject_irq(svm, intr_vector); | ||
| 1318 | return; | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | if (vmcb->control.int_ctl & V_IRQ_MASK) | ||
| 1322 | return; | ||
| 1323 | |||
| 1324 | if (!kvm_cpu_has_interrupt(&svm->vcpu)) | ||
| 1325 | return; | ||
| 1326 | |||
| 1327 | if (!(vmcb->save.rflags & X86_EFLAGS_IF) || | ||
| 1328 | (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || | ||
| 1329 | (vmcb->control.event_inj & SVM_EVTINJ_VALID)) { | ||
| 1330 | /* unable to deliver irq, set pending irq */ | ||
| 1331 | vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); | ||
| 1332 | svm_inject_irq(svm, 0x0); | ||
| 1333 | return; | ||
| 1334 | } | ||
| 1335 | /* Okay, we can deliver the interrupt: grab it and update PIC state. */ | ||
| 1336 | intr_vector = kvm_cpu_get_interrupt(&svm->vcpu); | ||
| 1337 | svm_inject_irq(svm, intr_vector); | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | static void kvm_reput_irq(struct vcpu_svm *svm) | ||
| 1341 | { | ||
| 1342 | struct kvm_vcpu *vcpu = &svm->vcpu; | ||
| 1305 | struct vmcb_control_area *control = &svm->vmcb->control; | 1343 | struct vmcb_control_area *control = &svm->vmcb->control; |
| 1306 | 1344 | ||
| 1307 | if (control->int_ctl & V_IRQ_MASK) { | 1345 | if ((control->int_ctl & V_IRQ_MASK) && !irqchip_in_kernel(vcpu->kvm)) { |
| 1308 | control->int_ctl &= ~V_IRQ_MASK; | 1346 | control->int_ctl &= ~V_IRQ_MASK; |
| 1309 | push_irq(&svm->vcpu, control->int_vector); | 1347 | push_irq(&svm->vcpu, control->int_vector); |
| 1310 | } | 1348 | } |
| @@ -1313,6 +1351,19 @@ static void reput_irq(struct vcpu_svm *svm) | |||
| 1313 | !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); | 1351 | !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); |
| 1314 | } | 1352 | } |
| 1315 | 1353 | ||
| 1354 | static void svm_do_inject_vector(struct vcpu_svm *svm) | ||
| 1355 | { | ||
| 1356 | struct kvm_vcpu *vcpu = &svm->vcpu; | ||
| 1357 | int word_index = __ffs(vcpu->irq_summary); | ||
| 1358 | int bit_index = __ffs(vcpu->irq_pending[word_index]); | ||
| 1359 | int irq = word_index * BITS_PER_LONG + bit_index; | ||
| 1360 | |||
| 1361 | clear_bit(bit_index, &vcpu->irq_pending[word_index]); | ||
| 1362 | if (!vcpu->irq_pending[word_index]) | ||
| 1363 | clear_bit(word_index, &vcpu->irq_summary); | ||
| 1364 | svm_inject_irq(svm, irq); | ||
| 1365 | } | ||
| 1366 | |||
| 1316 | static void do_interrupt_requests(struct vcpu_svm *svm, | 1367 | static void do_interrupt_requests(struct vcpu_svm *svm, |
| 1317 | struct kvm_run *kvm_run) | 1368 | struct kvm_run *kvm_run) |
| 1318 | { | 1369 | { |
| @@ -1326,7 +1377,7 @@ static void do_interrupt_requests(struct vcpu_svm *svm, | |||
| 1326 | /* | 1377 | /* |
| 1327 | * If interrupts enabled, and not blocked by sti or mov ss. Good. | 1378 | * If interrupts enabled, and not blocked by sti or mov ss. Good. |
| 1328 | */ | 1379 | */ |
| 1329 | inject_irq(svm); | 1380 | svm_do_inject_vector(svm); |
| 1330 | 1381 | ||
| 1331 | /* | 1382 | /* |
| 1332 | * Interrupts blocked. Wait for unblock. | 1383 | * Interrupts blocked. Wait for unblock. |
| @@ -1408,7 +1459,9 @@ again: | |||
| 1408 | return -EINTR; | 1459 | return -EINTR; |
| 1409 | } | 1460 | } |
| 1410 | 1461 | ||
| 1411 | if (!vcpu->mmio_read_completed) | 1462 | if (irqchip_in_kernel(vcpu->kvm)) |
| 1463 | svm_intr_assist(svm); | ||
| 1464 | else if (!vcpu->mmio_read_completed) | ||
| 1412 | do_interrupt_requests(svm, kvm_run); | 1465 | do_interrupt_requests(svm, kvm_run); |
| 1413 | 1466 | ||
| 1414 | vcpu->guest_mode = 1; | 1467 | vcpu->guest_mode = 1; |
| @@ -1576,7 +1629,7 @@ again: | |||
| 1576 | 1629 | ||
| 1577 | stgi(); | 1630 | stgi(); |
| 1578 | 1631 | ||
| 1579 | reput_irq(svm); | 1632 | kvm_reput_irq(svm); |
| 1580 | 1633 | ||
| 1581 | svm->next_rip = 0; | 1634 | svm->next_rip = 0; |
| 1582 | 1635 | ||
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index d63e82e5dbf8..f1e80a95b69d 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include "kvm.h" | 18 | #include "kvm.h" |
| 19 | #include "x86_emulate.h" | 19 | #include "x86_emulate.h" |
| 20 | #include "irq.h" | ||
| 20 | #include "vmx.h" | 21 | #include "vmx.h" |
| 21 | #include "segment_descriptor.h" | 22 | #include "segment_descriptor.h" |
| 22 | 23 | ||
| @@ -1582,6 +1583,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) | |||
| 1582 | vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6)); | 1583 | vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6)); |
| 1583 | } | 1584 | } |
| 1584 | 1585 | ||
| 1586 | static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) | ||
| 1587 | { | ||
| 1588 | if (vcpu->rmode.active) { | ||
| 1589 | inject_rmode_irq(vcpu, irq); | ||
| 1590 | return; | ||
| 1591 | } | ||
| 1592 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, | ||
| 1593 | irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); | ||
| 1594 | } | ||
| 1595 | |||
| 1585 | static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) | 1596 | static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) |
| 1586 | { | 1597 | { |
| 1587 | int word_index = __ffs(vcpu->irq_summary); | 1598 | int word_index = __ffs(vcpu->irq_summary); |
| @@ -1591,13 +1602,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) | |||
| 1591 | clear_bit(bit_index, &vcpu->irq_pending[word_index]); | 1602 | clear_bit(bit_index, &vcpu->irq_pending[word_index]); |
| 1592 | if (!vcpu->irq_pending[word_index]) | 1603 | if (!vcpu->irq_pending[word_index]) |
| 1593 | clear_bit(word_index, &vcpu->irq_summary); | 1604 | clear_bit(word_index, &vcpu->irq_summary); |
| 1594 | 1605 | vmx_inject_irq(vcpu, irq); | |
| 1595 | if (vcpu->rmode.active) { | ||
| 1596 | inject_rmode_irq(vcpu, irq); | ||
| 1597 | return; | ||
| 1598 | } | ||
| 1599 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, | ||
| 1600 | irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); | ||
| 1601 | } | 1606 | } |
| 1602 | 1607 | ||
| 1603 | 1608 | ||
| @@ -1681,7 +1686,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
| 1681 | "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); | 1686 | "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); |
| 1682 | } | 1687 | } |
| 1683 | 1688 | ||
| 1684 | if (is_external_interrupt(vect_info)) { | 1689 | if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { |
| 1685 | int irq = vect_info & VECTORING_INFO_VECTOR_MASK; | 1690 | int irq = vect_info & VECTORING_INFO_VECTOR_MASK; |
| 1686 | set_bit(irq, vcpu->irq_pending); | 1691 | set_bit(irq, vcpu->irq_pending); |
| 1687 | set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); | 1692 | set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); |
| @@ -1961,6 +1966,12 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu, | |||
| 1961 | static int handle_interrupt_window(struct kvm_vcpu *vcpu, | 1966 | static int handle_interrupt_window(struct kvm_vcpu *vcpu, |
| 1962 | struct kvm_run *kvm_run) | 1967 | struct kvm_run *kvm_run) |
| 1963 | { | 1968 | { |
| 1969 | u32 cpu_based_vm_exec_control; | ||
| 1970 | |||
| 1971 | /* clear pending irq */ | ||
| 1972 | cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); | ||
| 1973 | cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; | ||
| 1974 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); | ||
| 1964 | /* | 1975 | /* |
| 1965 | * If the user space waits to inject interrupts, exit as soon as | 1976 | * If the user space waits to inject interrupts, exit as soon as |
| 1966 | * possible | 1977 | * possible |
| @@ -2052,6 +2063,55 @@ static void vmx_flush_tlb(struct kvm_vcpu *vcpu) | |||
| 2052 | { | 2063 | { |
| 2053 | } | 2064 | } |
| 2054 | 2065 | ||
| 2066 | static void enable_irq_window(struct kvm_vcpu *vcpu) | ||
| 2067 | { | ||
| 2068 | u32 cpu_based_vm_exec_control; | ||
| 2069 | |||
| 2070 | cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); | ||
| 2071 | cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; | ||
| 2072 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); | ||
| 2073 | } | ||
| 2074 | |||
| 2075 | static void vmx_intr_assist(struct kvm_vcpu *vcpu) | ||
| 2076 | { | ||
| 2077 | u32 idtv_info_field, intr_info_field; | ||
| 2078 | int has_ext_irq, interrupt_window_open; | ||
| 2079 | |||
| 2080 | has_ext_irq = kvm_cpu_has_interrupt(vcpu); | ||
| 2081 | intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); | ||
| 2082 | idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); | ||
| 2083 | if (intr_info_field & INTR_INFO_VALID_MASK) { | ||
| 2084 | if (idtv_info_field & INTR_INFO_VALID_MASK) { | ||
| 2085 | /* TODO: fault when IDT_Vectoring */ | ||
| 2086 | printk(KERN_ERR "Fault when IDT_Vectoring\n"); | ||
| 2087 | } | ||
| 2088 | if (has_ext_irq) | ||
| 2089 | enable_irq_window(vcpu); | ||
| 2090 | return; | ||
| 2091 | } | ||
| 2092 | if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { | ||
| 2093 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); | ||
| 2094 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, | ||
| 2095 | vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); | ||
| 2096 | |||
| 2097 | if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK)) | ||
| 2098 | vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, | ||
| 2099 | vmcs_read32(IDT_VECTORING_ERROR_CODE)); | ||
| 2100 | if (unlikely(has_ext_irq)) | ||
| 2101 | enable_irq_window(vcpu); | ||
| 2102 | return; | ||
| 2103 | } | ||
| 2104 | if (!has_ext_irq) | ||
| 2105 | return; | ||
| 2106 | interrupt_window_open = | ||
| 2107 | ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && | ||
| 2108 | (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); | ||
| 2109 | if (interrupt_window_open) | ||
| 2110 | vmx_inject_irq(vcpu, kvm_cpu_get_interrupt(vcpu)); | ||
| 2111 | else | ||
| 2112 | enable_irq_window(vcpu); | ||
| 2113 | } | ||
| 2114 | |||
| 2055 | static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 2115 | static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
| 2056 | { | 2116 | { |
| 2057 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 2117 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
| @@ -2088,7 +2148,9 @@ again: | |||
| 2088 | goto out; | 2148 | goto out; |
| 2089 | } | 2149 | } |
| 2090 | 2150 | ||
| 2091 | if (!vcpu->mmio_read_completed) | 2151 | if (irqchip_in_kernel(vcpu->kvm)) |
| 2152 | vmx_intr_assist(vcpu); | ||
| 2153 | else if (!vcpu->mmio_read_completed) | ||
| 2092 | do_interrupt_requests(vcpu, kvm_run); | 2154 | do_interrupt_requests(vcpu, kvm_run); |
| 2093 | 2155 | ||
| 2094 | vcpu->guest_mode = 1; | 2156 | vcpu->guest_mode = 1; |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 1d5a49cdda3b..bfe742b771f6 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
| @@ -34,6 +34,17 @@ struct kvm_memory_alias { | |||
| 34 | __u64 target_phys_addr; | 34 | __u64 target_phys_addr; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | /* for KVM_SET_IRQ_LEVEL */ | ||
| 38 | struct kvm_irq_level { | ||
| 39 | /* | ||
| 40 | * ACPI gsi notion of irq. | ||
| 41 | * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. | ||
| 42 | * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23.. | ||
| 43 | */ | ||
| 44 | __u32 irq; | ||
| 45 | __u32 level; | ||
| 46 | }; | ||
| 47 | |||
| 37 | enum kvm_exit_reason { | 48 | enum kvm_exit_reason { |
| 38 | KVM_EXIT_UNKNOWN = 0, | 49 | KVM_EXIT_UNKNOWN = 0, |
| 39 | KVM_EXIT_EXCEPTION = 1, | 50 | KVM_EXIT_EXCEPTION = 1, |
| @@ -269,6 +280,11 @@ struct kvm_signal_mask { | |||
| 269 | #define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */ | 280 | #define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */ |
| 270 | 281 | ||
| 271 | /* | 282 | /* |
| 283 | * Extension capability list. | ||
| 284 | */ | ||
| 285 | #define KVM_CAP_IRQCHIP 0 | ||
| 286 | |||
| 287 | /* | ||
| 272 | * ioctls for VM fds | 288 | * ioctls for VM fds |
| 273 | */ | 289 | */ |
| 274 | #define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region) | 290 | #define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region) |
| @@ -279,6 +295,9 @@ struct kvm_signal_mask { | |||
| 279 | #define KVM_CREATE_VCPU _IO(KVMIO, 0x41) | 295 | #define KVM_CREATE_VCPU _IO(KVMIO, 0x41) |
| 280 | #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log) | 296 | #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log) |
| 281 | #define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias) | 297 | #define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias) |
| 298 | /* Device model IOC */ | ||
| 299 | #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) | ||
| 300 | #define KVM_IRQ_LINE _IO(KVMIO, 0x61) | ||
| 282 | 301 | ||
| 283 | /* | 302 | /* |
| 284 | * ioctls for vcpu fds | 303 | * ioctls for vcpu fds |
