169e1daaf36c49664281bac9ff647d3f90ff3a3d
[akaros.git] / user / vmm / apic.c
1 /*
2  * APIC emulation
3  *
4  * Copyright 2015 Google Inc.
5  *
6  * See LICENSE for details.
7  */
8
9 #include <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
31 #define APIC_CONFIG 0x100
32
33 int debug_apic = 1;
34 #define DPRINTF(fmt, ...) \
35         if (debug_apic) { fprintf(stderr, "apic: " fmt , ## __VA_ARGS__); }
36
37
38 static struct apicinfo apicinfo;
39
40 enum {
41         reserved,
42         readonly = 1,
43         readwrite = 3,
44         writeonly = 2
45 };
46
47 struct {
48         char *name;
49         int mode;
50         uint32_t value;
51 } apicregs[256] = {
52 [0x00] {.name = "Reserved", .mode =  reserved},
53 [0x01] {.name = "Reserved", .mode =  reserved},
54 [0x02] {.name = "Local APIC ID Register Read/Write.", .mode = readwrite},
55 [0x03] {.name = "Local APIC Version Register Read Only.", .mode = readonly},
56 [0x04] {.name = "Reserved", .mode =  reserved},
57 [0x05] {.name = "Reserved", .mode =  reserved},
58 [0x06] {.name = "Reserved", .mode =  reserved},
59 [0x07] {.name = "Reserved", .mode =  reserved},
60 [0x08] {.name = "Task Priority Register (TPR) Read/Write.", .mode = readwrite},
61 [0x09] {.name = "Arbitration Priority Register1 (APR) Read Only.", .mode = readonly},
62 [0x0A] {.name = "Processor Priority Register (PPR) Read Only.", .mode = readonly},
63 [0x0B] {.name = "EOI Register Write Only.", .mode = writeonly},
64 [0x0C] {.name = "Remote Read Register1 (RRD) Read Only", .mode = readonly},
65 [0x0D] {.name = "Logical Destination Register Read/Write.", .mode = readwrite},
66 [0x0E] {.name = "Destination Format Register Read/Write (see Section", .mode = readwrite},
67 [0x0F] {.name = "Spurious Interrupt Vector Register Read/Write (see Section 10.9.", .mode = readwrite},
68 [0x10] {.name = "In-Service Register (ISR); bits 31:0 Read Only.", .mode = readonly},
69 [0x11] {.name = "In-Service Register (ISR); bits 63:32 Read Only.", .mode = readonly},
70 [0x12] {.name = "In-Service Register (ISR); bits 95:64 Read Only.", .mode = readonly},
71 [0x13] {.name = "In-Service Register (ISR); bits 127:96 Read Only.", .mode = readonly},
72 [0x14] {.name = "In-Service Register (ISR); bits 159:128 Read Only.", .mode = readonly},
73 [0x15] {.name = "In-Service Register (ISR); bits 191:160 Read Only.", .mode = readonly},
74 [0x16] {.name = "In-Service Register (ISR); bits 223:192 Read Only.", .mode = readonly},
75 [0x17] {.name = "In-Service Register (ISR); bits 255:224 Read Only.", .mode = readonly},
76 [0x18] {.name = "Trigger Mode Register (TMR); bits 31:0 Read Only.", .mode = readonly},
77 [0x19] {.name = "Trigger Mode Register (TMR); bits 63:32 Read Only.", .mode = readonly},
78 [0x1A] {.name = "Trigger Mode Register (TMR); bits 95:64 Read Only.", .mode = readonly},
79 [0x1B] {.name = "Trigger Mode Register (TMR); bits 127:96 Read Only.", .mode = readonly},
80 [0x1C] {.name = "Trigger Mode Register (TMR); bits 159:128 Read Only.", .mode = readonly},
81 [0x1D] {.name = "Trigger Mode Register (TMR); bits 191:160 Read Only.", .mode = readonly},
82 [0x1E] {.name = "Trigger Mode Register (TMR); bits 223:192 Read Only.", .mode = readonly},
83 [0x1F] {.name = "Trigger Mode Register (TMR); bits 255:224 Read Only.", .mode = readonly},
84 [0x20] {.name = "Interrupt Request Register (IRR); bits 31:0 Read Only.", .mode = readonly},
85 [0x21] {.name = "Interrupt Request Register (IRR); bits 63:32 Read Only.", .mode = readonly},
86 [0x22] {.name = "Interrupt Request Register (IRR); bits 95:64 Read Only.", .mode = readonly},
87 [0x23] {.name = "Interrupt Request Register (IRR); bits 127:96 Read Only.", .mode = readonly},
88 [0x24] {.name = "Interrupt Request Register (IRR); bits 159:128 Read Only.", .mode = readonly},
89 [0x25] {.name = "Interrupt Request Register (IRR); bits 191:160 Read Only.", .mode = readonly},
90 [0x26] {.name = "Interrupt Request Register (IRR); bits 223:192 Read Only.", .mode = readonly},
91 [0x27] {.name = "Interrupt Request Register (IRR); bits 255:224 Read Only.", .mode = readonly},
92 [0x28] {.name = "Error Status Register Read Only.", .mode = readonly},
93 [0x29 ] {.name = "Reserved", .mode =  reserved},
94 [0x2a] {.name = "Reserved", .mode =  reserved},
95 [0x2b] {.name = "Reserved", .mode =  reserved},
96 [0x2c] {.name = "Reserved", .mode =  reserved},
97 [0x2d] {.name = "Reserved", .mode =  reserved},
98 [0x2E] {.name = "Reserved", .mode =  reserved},
99 [0x2F] {.name = "LVT CMCI Register Read/Write.", .mode = readwrite},
100 [0x30] {.name = "Interrupt Command Register (ICR); bits 0-31 Read/Write.", .mode = readwrite},
101 [0x31] {.name = "Interrupt Command Register (ICR); bits 32-63 Read/Write.", .mode = readwrite},
102 [0x32] {.name = "LVT Timer Register Read/Write.", .mode = readwrite},
103 [0x33] {.name = "LVT Thermal Sensor Register2 Read/Write.", .mode = readwrite},
104 [0x34] {.name = "LVT Performance Monitoring Counters Register3 Read/Write.", .mode = readwrite},
105 [0x35] {.name = "LVT LINT0 Register Read/Write.", .mode = readwrite},
106 [0x36] {.name = "LVT LINT1 Register Read/Write.", .mode = readwrite},
107 [0x37] {.name = "LVT Error Register Read/Write.", .mode = readwrite},
108 [0x38] {.name = "Initial Count Register (for Timer) Read/Write.", .mode = readwrite},
109 [0x39] {.name = "Current Count Register (for Timer) Read Only.", .mode = readonly},
110 [0x3A] {.name = "Reserved", .mode =  reserved},
111 [0x3a]{.name = "Reserved", .mode =  reserved},
112 [0x3b]{.name = "Reserved", .mode =  reserved},
113 [0x3c]{.name = "Reserved", .mode =  reserved},
114 [0x3D]{.name = "Reserved", .mode =  reserved},
115 [0x3E] {.name = "Divide Configuration Register (for Timer) Read/Write.", .mode = readwrite},
116 [0x3F] {.name = "Reserved", .mode =  reserved},
117 };
118
119 static uint32_t apic_read(uint64_t offset)
120 {
121
122         uint32_t low;
123
124         DPRINTF("apic_read offset %s 0x%x\n", apicregs[offset].name,
125                 (int)offset);
126
127         if (! apicregs[offset].mode & 1) {
128                 fprintf(stderr, "Attempt to read %s, which is %s\n",
129                         apicregs[offset].name,
130                         apicregs[offset].mode == 0 ?  "reserved" : "writeonly");
131                 // panic? what to do?
132                 return (uint32_t) -1;
133         }
134
135         // no special cases yet.
136         switch (offset) {
137         default:
138                 DPRINTF("%s: return %08x\n", apicregs[offset].name,
139                         apicregs[offset].value);
140                 return apicregs[offset].value;
141                 break;
142         }
143         return 0;
144 }
145
146 static void apic_write(uint64_t offset, uint32_t value)
147 {
148         uint64_t val64;
149         uint32_t low, high;
150
151         DPRINTF("apic_write offset %s 0x%x value 0x%x\n", apicregs[offset].name,
152                 (int)offset, value);
153
154         if (! apicregs[offset].mode & 2) {
155                 fprintf(stderr, "Attempt to write %s, which is %s\n",
156                         apicregs[offset].name,
157                         apicregs[offset].mode == 0 ?  "reserved" : "readonly");
158                 // panic? what to do?
159                 return;
160         }
161
162         switch (offset) {
163         default:
164                 DPRINTF("%s: Set to %08x\n", apicregs[offset].name, value);
165                 apicregs[offset].value = value;
166                 break;
167         }
168
169 }
170
171 int __apic_access(struct guest_thread *vm_thread, uint64_t gpa, int destreg,
172                   uint64_t *regp, int store)
173 {
174         uint32_t offset = gpa & 0xfffff;
175         /* basic sanity tests. */
176         // TODO: Should be minus the base but FIXME
177
178         //fprintf(stderr, "WE SHOULD NEVER BE HERE: user/vmm/apic.c");
179         //exit(1);
180
181         offset = gpa & 0xfffff;
182         if (offset & 0xf) {
183                 DPRINTF("bad register offset; low nibl is non-zero\n");
184                 return -1;
185         }
186         offset >>= 4;
187         if (offset > APIC_CONFIG) {
188                 DPRINTF("Bad register offset: 0x%x and max is 0x%x\n", gpa, gpa
189                         + APIC_CONFIG);
190                 return -1;
191         }
192
193         if (store) {
194                 apic_write(offset, *regp);
195                 DPRINTF("Write: mov %s to %s @%p val %p\n", regname(destreg),
196                         apicregs[offset].name, gpa, *regp);
197         } else {
198                 *regp = apic_read(offset);
199                 DPRINTF("Read: Set %s from %s @%p to %p\n", regname(destreg),
200                         apicregs[offset].name, gpa, *regp);
201         }
202         return 0;
203 }
204
205 void vapic_status_dump(FILE *f, void *vapic)
206 {
207         uint32_t *p = (uint32_t *)vapic;
208         int i;
209
210         fprintf(f, "-- BEGIN APIC STATUS DUMP --\n");
211         for (i = 0x100/sizeof(*p); i < 0x180/sizeof(*p); i+=4) {
212                 fprintf(f, "VISR : 0x%x: 0x%08x\n", i, p[i]);
213         }
214         for (i = 0x200/sizeof(*p); i < 0x280/sizeof(*p); i+=4) {
215                 fprintf(f, "VIRR : 0x%x: 0x%08x\n", i, p[i]);
216         }
217         i = 0x0B0/sizeof(*p);
218         fprintf(f, "EOI FIELD : 0x%x, 0x%08x\n", i, p[i]);
219
220         fprintf(f, "-- END APIC STATUS DUMP --\n");
221 }