parlib: have 2LS libraries #include parlib/stdio.h
[akaros.git] / user / vmm / ioapic.c
1 /*
2  * IOAPIC emulation
3  *
4  * Copyright 2015 Google Inc.
5  *
6  * See LICENSE for details.
7  */
8
9 #include <parlib/stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <parlib/arch/arch.h>
14 #include <parlib/ros_debug.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/uio.h>
20 #include <stdint.h>
21 #include <err.h>
22 #include <sys/mman.h>
23 #include <vmm/vmm.h>
24 #include <vmm/virtio.h>
25 #include <vmm/virtio_mmio.h>
26 #include <vmm/virtio_ids.h>
27 #include <vmm/virtio_config.h>
28 #include <vmm/sched.h>
29
30 #define IOAPIC_CONFIG 0x100
31 #define IOAPIC_NUM_PINS 24
32
33 int debug_ioapic;
34 int apic_id_mask = 0xf0;
35
36 #define DPRINTF(fmt, ...) \
37         if (debug_ioapic) { fprintf(stderr, "ioapic: " fmt , ## __VA_ARGS__); }
38
39
40 struct ioapic {
41         int id;
42         int reg;
43         uint32_t arbid;
44         uint32_t value[256];
45 };
46
47 static struct ioapic ioapic[1];
48
49 static uint32_t ioapic_read(struct guest_thread *vm_thread, int ix,
50                             uint64_t offset)
51 {
52         uint32_t ret = (uint32_t)-1;
53         uint32_t reg = ioapic[ix].reg;
54
55         if (offset == 0) {
56                 DPRINTF("ioapic_read ix %x return 0x%x\n", ix, reg);
57                 return reg;
58         }
59
60         DPRINTF("ioapic_read %x 0x%x\n", ix, (int)reg);
61         switch (reg) {
62         case 0:
63                 return ioapic[ix].id;
64         case 1:
65                 return 0x170011;
66         case 2:
67                 return ioapic[ix].arbid;
68         default:
69                 if (reg >= 0 && reg < (IOAPIC_NUM_PINS*2 + 0x10)) {
70                         //bx_io_redirect_entry_t *entry = ioredtbl + index;
71                         //data = (ioregsel&1) ? entry->get_hi_part()
72                         //                    : entry->get_lo_part();
73                         ret = ioapic[ix].value[reg];
74                         DPRINTF("IOAPIC_READ %x: %x return %08x\n", ix, reg,
75                                 ret);
76                         return ret;
77                 } else {
78                         DPRINTF("IOAPIC READ: %x BAD INDEX 0x%x\n", ix, reg);
79                 }
80                 return ret;
81         }
82         return 0;
83 }
84
85 static void ioapic_write(struct guest_thread *vm_thread, int ix,
86                          uint64_t offset, uint32_t value)
87 {
88         uint32_t ret;
89         uint32_t reg = ioapic[ix].reg;
90         struct virtual_machine *vm = gth_to_vm(vm_thread);
91         uint32_t irqreg;
92
93         if (offset == 0) {
94                 DPRINTF("ioapic_write ix %x set reg 0x%x\n", ix, value);
95                 ioapic[ix].reg = value;
96                 return;
97         }
98
99         for (int i = 0; i < VIRTIO_MMIO_MAX_NUM_DEV; i++) {
100                 if (vm->virtio_mmio_devices[i] == NULL)
101                         continue;
102
103                 /* The first IRQ register starts at 0x10, and there are two
104                  * 32-bit registers for each IRQ. The first 8 bits of the value
105                  * assigned to 'reg' is the interrupt vector. */
106                 irqreg = (vm->virtio_mmio_devices[i]->irq) * 2 + 0x10;
107                 if (reg == irqreg && (value & 0xff) != 0) {
108                         vm->virtio_mmio_devices[i]->vec = value & 0xff;
109                         DPRINTF("irq vector for irq number %d is: %lx\n",
110                                  vm->virtio_mmio_devices[i]->irq, value & 0xff);
111                 } else if (reg == irqreg + 1) {
112                         vm->virtio_mmio_devices[i]->dest = value >> 24;
113                         if (value >> 24 == 0xff)
114                                 vm->virtio_mmio_devices[i]->dest = 0xffffffff;
115
116                         DPRINTF("high value for irq number %d is: %lx\n",
117                                  vm->virtio_mmio_devices[i]->irq, value);
118                         DPRINTF("irq destination for irq number %d is: %lx\n",
119                                  vm->virtio_mmio_devices[i]->irq, value >> 24);
120                 }
121         }
122
123         switch (reg) {
124         case 0:
125                 DPRINTF("IOAPIC_WRITE: Set %d ID to %d\n", ix, value);
126                 ioapic[ix].id = value;
127                 break;
128         case 1:
129         case 2:
130                 DPRINTF("IOAPIC_WRITE: Can't write %d\n", reg);
131         default:
132                 if (reg >= 0 && reg < (IOAPIC_NUM_PINS*2 + 0x10)) {
133                         ioapic[ix].value[reg] = value;
134                         DPRINTF("IOAPIC %x: set %08x to %016x\n", ix, reg,
135                                 value);
136                 } else {
137                         DPRINTF("IOAPIC WRITE: %x BAD INDEX 0x%x\n", ix, reg);
138                 }
139                 break;
140         }
141
142 }
143
144 int do_ioapic(struct guest_thread *vm_thread, uint64_t gpa, int destreg,
145               uint64_t *regp, int store)
146 {
147         /* TODO(ganshun): compute an index for the ioapic array. */
148         int ix = 0;
149         uint32_t offset = gpa & 0xfffff;
150         /* basic sanity tests. */
151         DPRINTF("%s: %p 0x%x %p %s\n", __func__, (void *)gpa, destreg, regp,
152                 store ? "write" : "read");
153
154         if ((offset != 0) && (offset != 0x10)) {
155                 DPRINTF("Bad register offset: 0x%x and has to be 0x0 or 0x10\n",
156                         offset);
157                 return -1;
158         }
159
160         if (store) {
161                 ioapic_write(vm_thread, ix, offset, *regp);
162         } else {
163                 *regp = ioapic_read(vm_thread, ix, offset);
164         }
165         return 0;
166 }