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