1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7/* Intel 8259 Programmable Interrupt Controller (PIC) emulator on x86. 8 * 9 * The functions related to machine state manipulations were taken 10 * from Linux kernel 3.8.8 arch/x86/kvm/i8259.c 11 * 12 */ 13 14#include <autoconf.h> 15#include <assert.h> 16#include <stdio.h> 17#include <stdbool.h> 18#include <sel4/sel4.h> 19#include <stdio.h> 20#include <utils/util.h> 21 22#include <sel4vm/guest_vm.h> 23#include <sel4vm/boot.h> 24#include <sel4vm/guest_irq_controller.h> 25#include <sel4vm/arch/ioports.h> 26#include "i8259.h" 27 28#define I8259_MASTER 0 29#define I8259_SLAVE 1 30 31#define PIC_NUM_PINS 16 32 33/*first programmable interrupt controller, master*/ 34#define X86_IO_PIC_1_START 0x20 35#define X86_IO_PIC_1_END 0x21 36 37/*second programmable interrupt controller, slave*/ 38#define X86_IO_PIC_2_START 0xa0 39#define X86_IO_PIC_2_END 0xa1 40 41/*ELCR (edge/level control register) for IRQ line*/ 42#define X86_IO_ELCR_START 0x4d0 43#define X86_IO_ELCR_END 0x4d1 44 45typedef struct i8259_irq_ack { 46 irq_ack_fn_t callback; 47 void *cookie; 48} i8259_irq_ack_t; 49 50static i8259_irq_ack_t irq_ack_fns[PIC_NUM_PINS]; 51 52/* PIC Machine state. */ 53struct i8259_state { 54 unsigned char last_irr; /* Edge detection */ 55 unsigned char irr; /* Interrupt request register */ 56 unsigned char imr; /* Interrupt mask register */ 57 unsigned char isr; /* Interrupt service register */ 58 unsigned char priority_add; /* Highest irq priority */ 59 unsigned char irq_base; 60 unsigned char read_reg_select; 61 unsigned char poll; 62 unsigned char special_mask; 63 unsigned char init_state; 64 unsigned char auto_eoi; 65 unsigned char rotate_on_auto_eoi; 66 unsigned char special_fully_nested_mode; 67 unsigned char init4; /* True if 4 byte init */ 68 unsigned char elcr; /* PIIX edge/trigger selection */ 69 unsigned char elcr_mask; 70 unsigned char isr_ack; /* Interrupt ack detection */ 71 struct i8259 *pics_state; 72}; 73 74/* Struct containig PIC state for a Guest OS instance. */ 75struct i8259 { 76 unsigned int wakeup_needed; 77 unsigned int pending_acks; 78 struct i8259_state pics[2]; /* 0 is master pic, 1 is slave pic */ 79 int output; /* Intr from master PIC */ 80 int emitagain; 81}; 82 83static inline int select_pic(unsigned int irq) 84{ 85 assert(irq < 16); 86 if (irq < 8) { 87 return I8259_MASTER; 88 } else { 89 return I8259_SLAVE; 90 } 91} 92 93static inline int __vm_irq_line_state(unsigned long *irq_state, 94 int irq_source_id, int level) 95{ 96 /* Logical OR for level trig interrupt. */ 97 if (level) { 98 (*irq_state) |= BIT(irq_source_id); 99 } else { 100 (*irq_state) &= ~BIT(irq_source_id); 101 } 102 103 return !!(*irq_state); 104} 105 106/* Return the highest priority found in mask (highest = smallest number). Return 8 if no irq */ 107static inline int get_priority(struct i8259_state *s, int mask) 108{ 109 int priority = 0; 110 111 if (!mask) { 112 return 8; 113 } 114 115 while (!(mask & (1 << ((priority + s->priority_add) & 7)))) { 116 priority++; 117 } 118 return priority; 119} 120 121/* Check if given IO address is valid. */ 122static int i8259_in_range(unsigned int addr) 123{ 124 switch (addr) { 125 case 0x20: 126 case 0x21: 127 case 0xa0: 128 case 0xa1: 129 case 0x4d0: 130 case 0x4d1: 131 return 1; 132 default: 133 return 0; 134 } 135} 136 137 138/* Compare ISR with the highest priority IRQ in IRR. 139 * Returns -1 if no interrupts, 140 * Otherwise returns the PIC interrupt generated. 141 */ 142static int pic_get_irq(struct i8259_state *s) 143{ 144 int mask, cur_priority, priority; 145 146 mask = s->irr & ~s->imr; 147 priority = get_priority(s, mask); 148 if (priority == 8) { 149 return -1; 150 } 151 /* Compute current priority. If special fully nested mode on the 152 * master, the IRQ coming from the slave is not taken into account 153 * for the priority computation. 154 */ 155 mask = s->isr; 156 if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) { 157 mask &= ~(1 << 2); 158 } 159 cur_priority = get_priority(s, mask); 160 if (priority < cur_priority) { 161 /* Higher priority found: an irq should be generated. */ 162 return (priority + s->priority_add) & 7; 163 } else { 164 return -1; 165 } 166} 167 168/* Clear the IRQ from ISR, the IRQ has been served. */ 169static void pic_clear_isr(vm_t *vm, struct i8259_state *s, int irq) 170{ 171 /* Clear the ISR, notify the ack handler. */ 172 s->isr &= ~(1 << irq); 173 if (s != &s->pics_state->pics[0]) { 174 irq += 8; 175 } 176 177 if (irq != 2) { 178 if (irq_ack_fns[irq].callback) { 179 irq_ack_fns[irq].callback(vm->vcpus[BOOT_VCPU], irq, irq_ack_fns[irq].cookie); 180 } 181 } 182} 183 184/* Set irq level. If an edge is detected, then the IRR is set to 1. */ 185static inline int pic_set_irq1(struct i8259_state *s, int irq, int level) 186{ 187 int mask, ret = 1; 188 mask = 1 << irq; 189 190 if (s->elcr & mask) { 191 /* Level triggered. */ 192 if (level) { 193 ret = !(s->irr & mask); 194 s->irr |= mask; 195 s->last_irr |= mask; 196 } else { 197 s->irr &= ~mask; 198 s->last_irr &= ~mask; 199 } 200 } else { 201 /* Edge triggered. */ 202 if (level) { 203 if ((s->last_irr & mask) == 0) { 204 ret = !(s->irr & mask); 205 s->irr |= mask; 206 } 207 s->last_irr |= mask; 208 } else { 209 s->last_irr &= ~mask; 210 } 211 } 212 213 return (s->imr & mask) ? -1 : ret; 214} 215 216 217/* Raise IRQ on CPU if necessary. Must be called every time the active IRQ may change. 218 Update the master pic and trigger interrupt injection according to the IRR and ISR. */ 219static void pic_update_irq(struct i8259 *s) 220{ 221 int irq2, irq; 222 223 irq2 = pic_get_irq(&s->pics[1]); 224 if (irq2 >= 0) { 225 /* If IRQ request by slave PIC, signal master PIC and set the IRR in master PIC. */ 226 pic_set_irq1(&s->pics[0], 2, 1); 227 pic_set_irq1(&s->pics[0], 2, 0); 228 } 229 irq = pic_get_irq(&s->pics[0]); 230 231 /* PIC status changed injection flag. */ 232 if (!s->output) { 233 s->wakeup_needed = true; 234 } 235 236 if (irq >= 0) { 237 s->output = 1; 238 } else { 239 s->output = 0; 240 } 241 242 if (s->emitagain && s->output) { 243// haveint_emit(); 244 s->emitagain = 0; 245 } 246} 247 248/* Reset the PIC state for a guest OS. */ 249static void pic_reset(vm_t *vm, struct i8259_state *s) 250{ 251 int irq; 252 unsigned char edge_irr = s->irr & ~s->elcr; 253 254 s->last_irr = 0; 255 s->irr &= s->elcr; 256 s->imr = 0; 257 s->priority_add = 0; 258 s->special_mask = 0; 259 s->read_reg_select = 0; 260 if (!s->init4) { 261 s->special_fully_nested_mode = 0; 262 s->auto_eoi = 0; 263 } 264 s->init_state = 1; 265 266#if 0 267 /* FIXME: CONNECT pic with APIC */ 268 kvm_for_each_vcpu(i, vcpu, s->piics_state->kvm) 269 if (kvm_apic_accept_pic_intr(vcpu)) { 270 found = true; 271 break; 272 } 273 274 275 if (!found) { 276 return; 277 } 278#endif 279 280 for (irq = 0; irq < PIC_NUM_PINS / 2; irq++) { 281 if (edge_irr & (1 << irq)) { 282 pic_clear_isr(vm, s, irq); 283 } 284 } 285} 286 287/* Write into the state owned by the guest OS. */ 288static void pic_ioport_write(vm_vcpu_t *vcpu, struct i8259_state *s, unsigned int addr, unsigned int val) 289{ 290 int priority, cmd, irq; 291 292 addr &= 1; 293 294 if (addr == 0) { 295 if (val & 0x10) { 296 /* ICW1 */ 297 s->init4 = val & 1; 298 if (val & 0x02) { 299 printf("PIC: single mode not supported\n"); 300 } 301 if (val & 0x08) { 302 printf("PIC: level sensitive irq not supported\n"); 303 } 304 /* Reset the machine state and pending IRQS. */ 305 pic_reset(vcpu->vm, s); 306 307 } else if (val & 0x08) { 308 /* OCW 3 */ 309 if (val & 0x04) { 310 s->poll = 1; 311 } 312 if (val & 0x02) { 313 s->read_reg_select = val & 1; 314 } 315 if (val & 0x40) { 316 s->special_mask = (val >> 5) & 1; 317 } 318 } else { 319 /* OCW 2 */ 320 cmd = val >> 5; 321 switch (cmd) { 322 case 0: 323 case 4: 324 s->rotate_on_auto_eoi = cmd >> 2; 325 break; 326 case 1: 327 /* End of interrupt. */ 328 case 5: 329 /* Clear ISR and update IRQ*/ 330 priority = get_priority(s, s->isr); 331 if (priority != 8) { 332 irq = (priority + s->priority_add) & 7; 333 if (cmd == 5) { 334 s->priority_add = (irq + 1) & 7; 335 } 336 pic_clear_isr(vcpu->vm, s, irq); 337 pic_update_irq(s->pics_state); 338 } 339 break; 340 case 3: 341 /* Specific EOI command. */ 342 irq = val & 7; 343 pic_clear_isr(vcpu->vm, s, irq); 344 pic_update_irq(s->pics_state); 345 break; 346 case 6: 347 /* Set priority command. */ 348 s->priority_add = (val + 1) & 7; 349 pic_update_irq(s->pics_state); 350 break; 351 case 7: 352 /* Rotate on specific eoi command. */ 353 irq = val & 7; 354 s->priority_add = (irq + 1) & 7; 355 pic_clear_isr(vcpu->vm, s, irq); 356 pic_update_irq(s->pics_state); 357 break; 358 default: 359 /* No operation. */ 360 break; 361 } 362 } 363 } else 364 switch (s->init_state) { 365 case 0: { /* Normal mode OCW 1. */ 366 unsigned char imr_diff = s->imr ^ val; 367 (void) imr_diff; 368 //off = (s == &s->pics_state->pics[0]) ? 0 : 8; 369 s->imr = val; 370#if 0 371 for (irq = 0; irq < PIC_NUM_PINS / 2; irq++) 372 if (imr_diff & (1 << irq)) 373 /*FIXME: notify the status changes for IMR*/ 374 kvm_fire_mask_notifiers( 375 s->pics_state->kvm, 376 select_pic(irq + off), 377 irq + off, 378 !!(s->imr & (1 << irq))); 379#endif 380 pic_update_irq(s->pics_state); 381 break; 382 } 383 case 1: 384 /* ICW 2 */ 385 s->irq_base = val & 0xf8; 386 s->init_state = 2; 387 break; 388 case 2: 389 if (s->init4) { 390 s->init_state = 3; 391 } else { 392 s->init_state = 0; 393 } 394 break; 395 case 3: 396 /* ICW 4 */ 397 s->special_fully_nested_mode = (val >> 4) & 1; 398 s->auto_eoi = (val >> 1) & 1; 399 s->init_state = 0; 400 break; 401 } 402} 403 404/* Poll the pending IRQS for the highest priority IRQ, ack the IRQ: clear the ISR and IRR, and 405 * update PIC state. Returns -1 if no pending IRQ. */ 406static unsigned int pic_poll_read(vm_t *vm, struct i8259_state *s, unsigned int addr1) 407{ 408 unsigned int ret; 409 410 ret = pic_get_irq(s); 411 412 if (ret >= 0) { 413 if (addr1 >> 7) { 414 s->pics_state->pics[0].isr &= ~(1 << 2); 415 s->pics_state->pics[0].irr &= ~(1 << 2); 416 } 417 s->irr &= ~(1 << ret); 418 pic_clear_isr(vm, s, ret); 419 if (addr1 >> 7 || ret != 2) { 420 pic_update_irq(s->pics_state); 421 } 422 } else { 423 ret = 0x07; 424 pic_update_irq(s->pics_state); 425 } 426 427 return ret; 428} 429 430 431/* Read and write functions for PIC (master and slave). */ 432static unsigned int pic_ioport_read(vm_vcpu_t *vcpu, struct i8259_state *s, unsigned int addr) 433{ 434 unsigned int ret; 435 436 /* Poll for the highest priority IRQ. */ 437 if (s->poll) { 438 ret = pic_poll_read(vcpu->vm, s, addr); 439 s->poll = 0; 440 441 } else { 442 if (!(addr & 1)) { 443 if (s->read_reg_select) { 444 ret = s->isr; 445 } else { 446 ret = s->irr; 447 } 448 } else { 449 ret = s->imr; 450 } 451 452 } 453 return ret; 454} 455 456/*read and write functions for ELCR (edge/level control registers) 457IO: 0x4d0 0x4d1 each bit corresponsing to an IRQ from 8259 458bit set: level triggered mode 459bit clear: edge triggered mode*/ 460static void elcr_ioport_write(struct i8259_state *s, unsigned int addr, unsigned int val) 461{ 462 s->elcr = val & s->elcr_mask; 463} 464 465static unsigned int elcr_ioport_read(struct i8259_state *s, unsigned int addr) 466{ 467 return s->elcr; 468} 469 470 471ioport_fault_result_t i8259_port_out(vm_vcpu_t *vcpu, void *cookie, unsigned int port_no, unsigned int size, 472 unsigned int value) 473{ 474 /* Sender thread is the VMM main thread, calculate guest ID according to the badge. */ 475 struct i8259 *s = vcpu->vm->arch.i8259_gs; 476 477 if (!i8259_in_range(port_no)) { 478 return IO_FAULT_ERROR; 479 } 480 if (size != 1) { 481 return IO_FAULT_ERROR; 482 } 483 484 /* 0x20, 0x21, master pic, 0xa0, 0xa1 slave PIC. */ 485 switch (port_no) { 486 case 0x20: 487 case 0x21: 488 case 0xa0: 489 case 0xa1: 490 pic_ioport_write(vcpu, &s->pics[port_no >> 7], port_no, value); 491 break; 492 case 0x4d0: 493 case 0x4d1: 494 elcr_ioport_write(&s->pics[port_no & 1], port_no, value); 495 break; 496 } 497 498 return IO_FAULT_HANDLED; 499 500} 501 502ioport_fault_result_t i8259_port_in(vm_vcpu_t *vcpu, void *cookie, unsigned int port_no, unsigned int size, 503 unsigned int *result) 504{ 505 /* Sender thread is the VMM main thread, calculate guest ID according to the badge. */ 506 struct i8259 *s = vcpu->vm->arch.i8259_gs; 507 508 if (!i8259_in_range(port_no)) { 509 return IO_FAULT_ERROR; 510 } 511 if (size != 1) { 512 return IO_FAULT_ERROR; 513 } 514 515 /* 0x20, 0x21, master pic, 0xa0, 0xa1 slave PIC. */ 516 switch (port_no) { 517 case 0x20: 518 case 0x21: 519 case 0xa0: 520 case 0xa1: 521 *result = pic_ioport_read(vcpu, &s->pics[port_no >> 7], port_no); 522 break; 523 case 0x4d0: 524 case 0x4d1: 525 *result = elcr_ioport_read(&s->pics[port_no & 1], port_no); 526 break; 527 } 528 return IO_FAULT_HANDLED; 529} 530 531/* Init internal status for PIC driver. */ 532static void i8259_init_state(struct i8259 *s) 533{ 534 /* Init pic machine state for guest OS. */ 535// s->pics[0].elcr = seL4_IA32_IOPort_In8(LIB_VMM_IO_PCI_CAP, 0x4d0).result; 536// s->pics[1].elcr = seL4_IA32_IOPort_In8(LIB_VMM_IO_PCI_CAP, 0x4d1).result; 537 s->pics[0].elcr = 0; 538 s->pics[1].elcr = 0; 539 s->pics[0].elcr_mask = 0xf8; 540 s->pics[1].elcr_mask = 0xde; 541 s->pics[0].pics_state = s; 542 s->pics[1].pics_state = s; 543} 544 545 546/* Acknowledge interrupt IRQ. */ 547static inline void pic_intack(vm_t *vm, struct i8259_state *s, int irq) 548{ 549 /* Ack the IRQ, set the ISR. */ 550 s->isr |= 1 << irq; 551 552 /* We don't clear a level sensitive interrupt here. */ 553 if (!(s->elcr & (1 << irq))) { 554 s->irr &= ~(1 << irq); 555 } 556 557 /* Clear the ISR for auto EOI mode. */ 558 if (s->auto_eoi) { 559 if (s->rotate_on_auto_eoi) { 560 s->priority_add = (irq + 1) & 7; 561 } 562 pic_clear_isr(vm, s, irq); 563 } 564} 565 566/* Use output as a flag for pending IRQ. */ 567static int i8259_has_irq(vm_t *vm) 568{ 569 struct i8259 *s = vm->arch.i8259_gs; 570 return s->output; 571} 572 573#if 0 574static int i8259_poll_irq() 575{ 576 struct i8259 *s = &i8259_gs; 577 578 int irq, irq2, intno; 579 580 /* Search for the highest priority IRQ. */ 581 irq = pic_get_irq(&s->pics[0]); 582 583 if (irq >= 0) { 584 if (irq == 2) { 585 irq2 = pic_get_irq(&s->pics[1]); 586 if (irq2 >= 0) { 587 } else { 588 /* Spurious IRQ on slave controller. */ 589 irq2 = 7; 590 } 591 intno = s->pics[1].irq_base + irq2; 592 irq = irq2 + 8; 593 } else { 594 intno = s->pics[0].irq_base + irq; 595 } 596 } else { 597 /* Spurious IRQ on host 8259 controller. */ 598 irq = 7; 599 intno = s->pics[0].irq_base + irq; 600 } 601 602 return intno; 603} 604#endif 605 606/* Return the highest pending IRQ. Ack the IRQ by updating the ISR before entering guest, using this 607 * function to get the pending IRQ. */ 608static int i8259_read_irq(vm_t *vm) 609{ 610 struct i8259 *s = vm->arch.i8259_gs; 611 612 int irq, irq2, intno; 613 614 /* Search for the highest priority IRQ. */ 615 irq = pic_get_irq(&s->pics[0]); 616 617 if (irq >= 0) { 618 /* Ack the IRQ. */ 619 pic_intack(vm, &s->pics[0], irq); 620 621 /* Ack the slave 8259 controller. */ 622 if (irq == 2) { 623 irq2 = pic_get_irq(&s->pics[1]); 624 if (irq2 >= 0) { 625 pic_intack(vm, &s->pics[1], irq2); 626 } else 627 /* Spurious IRQ on slave controller. */ 628 { 629 irq2 = 7; 630 } 631 intno = s->pics[1].irq_base + irq2; 632 irq = irq2 + 8; 633 } else { 634 intno = s->pics[0].irq_base + irq; 635 } 636 } else { 637 /* Spurious IRQ on host 8259 controller. */ 638 irq = 7; 639 intno = s->pics[0].irq_base + irq; 640 } 641 pic_update_irq(s); 642 643 return intno; 644} 645 646int i8259_get_interrupt(vm_t *vm) 647{ 648 int ret; 649 if (i8259_has_irq(vm)) { 650 ret = i8259_read_irq(vm); 651 } else { 652 ret = -1; 653 } 654 if (!i8259_has_irq(vm)) { 655 vm->arch.i8259_gs->emitagain = 1; 656 } 657 return ret; 658} 659 660int i8259_has_interrupt(vm_t *vm) 661{ 662 int ret = i8259_has_irq(vm); 663 return ret; 664} 665 666vm_ioport_entry_t pic_ioports[] = { 667 {{X86_IO_PIC_1_START, X86_IO_PIC_1_END}, {NULL, i8259_port_in, i8259_port_out, "8259 Programmable Interrupt Controller (1st, Master)"}}, 668 {{X86_IO_PIC_2_START, X86_IO_PIC_2_END}, {NULL, i8259_port_in, i8259_port_out, "8259 Programmable Interrupt Controller (2nd, Slave)"}}, 669 {{X86_IO_ELCR_START, X86_IO_ELCR_END}, {NULL, i8259_port_in, i8259_port_out, "ELCR (edge/level control register) for IRQ line"}} 670}; 671 672int i8259_pre_init(vm_t *vm) 673{ 674 int err; 675 /* First initialize the emulated pic state */ 676 vm->arch.i8259_gs = calloc(1, sizeof(struct i8259)); 677 if (!vm->arch.i8259_gs) { 678 return -1; 679 } 680 i8259_init_state(vm->arch.i8259_gs); 681 vm->arch.i8259_gs->emitagain = 1; 682 for (int i = 0; i < ARRAY_SIZE(pic_ioports); i++) { 683 vm_ioport_range_t pic_range = pic_ioports[i].range; 684 vm_ioport_interface_t pic_interface = pic_ioports[i].interface; 685 err = vm_io_port_add_handler(vm, pic_range, pic_interface); 686 if (err) { 687 return err; 688 } 689 } 690 return 0; 691} 692 693/* This is the actual function that will get called for all interrupt events 694 * Furthermore this implements the guest irq controller interface */ 695 696/* To inject an IRQ: First set the level as 1, then set the level as 0, toggling the level for 697 * triggering the IRQ. 698 * IRQ source ID is used for mapping multiple IRQ source into a IRQ pin. 699 * Sets irq request into the state machine for PIC. 700 */ 701int vm_set_irq_level(vm_vcpu_t *vcpu, int irq, int irq_level) 702{ 703 int ret; 704 705 struct i8259 *s = vcpu->vm->arch.i8259_gs; 706 707 /* Set IRR. */ 708 ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, irq_level); 709 pic_update_irq(s); 710 711 if (ret == -1) { 712 return -1; 713 } 714 return 0; 715} 716 717int vm_inject_irq(vm_vcpu_t *vcpu, int irq) 718{ 719 vm_set_irq_level(vcpu, irq, 1); 720 vm_set_irq_level(vcpu, irq, 0); 721 return 0; 722} 723 724int vm_register_irq(vm_vcpu_t *vcpu, int irq, irq_ack_fn_t fn, void *cookie) 725{ 726 if (irq < 0 || irq >= PIC_NUM_PINS) { 727 ZF_LOGE("irq %d is invalid", irq); 728 return -1; 729 } 730 i8259_irq_ack_t *ack = &irq_ack_fns[irq]; 731 ack->callback = fn; 732 ack->cookie = cookie; 733 return 0; 734} 735