Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


f1cb982d185b45850119f9f29f822ee0d5db9fbd
[palacios.git] / palacios / src / devices / icc_bus.c
1 /*
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National
4  * Science Foundation and the Department of Energy.
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm_dev_mgr.h>
21 #include <palacios/vmm_sprintf.h>
22 #include <palacios/vm_guest.h>
23 #include <devices/icc_bus.h>
24 #include <devices/apic_regs.h>
25
26 #define MAX_APICS 256
27
28 #ifndef CONFIG_DEBUG_ICC_BUS
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34 void v3_force_exit(void *p) {
35 #ifdef CONFIG_DEBUG_ICC_BUS
36     struct guest_info *core=(struct guest_info *)p;
37 #endif
38     PrintDebug("core %u: Forced to exit!\n",core->cpu_id);
39 }
40
41 struct ipi_thunk_data {
42     struct vm_device * target;
43     uint64_t val;
44 };
45
46
47
48 struct apic_data {
49     struct guest_info * core;
50     struct v3_icc_ops * ops;
51     
52     void * priv_data;
53     int present;
54 };
55
56
57 struct icc_bus_state {
58     struct apic_data apics[MAX_APICS];
59     
60     uint32_t         ioapic_id;
61 };
62
63 static struct v3_device_ops dev_ops = {
64     .free = NULL,
65     .reset = NULL,
66     .start = NULL,
67     .stop = NULL,
68 };
69
70 #ifdef CONFIG_DEBUG_ICC_BUS
71 static char *shorthand_str[] = { 
72     "(no shorthand)",
73     "(self)",
74     "(all)",
75     "(all-but-me)",
76  };
77
78 static char *deliverymode_str[] = { 
79     "(fixed)",
80     "(lowest priority)",
81     "(SMI)",
82     "(reserved)",
83     "(NMI)",
84     "(INIT)",
85     "(Start Up)",
86     "(ExtInt)",
87 };
88 #endif
89
90
91 static int deliver(uint32_t src_apic, struct apic_data *dest_apic, struct int_cmd_reg *icr, struct icc_bus_state * state, uint32_t extirq) {
92
93     switch (icr->del_mode) {                                            
94
95         case 0:  //fixed
96         case 1: // lowest priority
97         case 7: // ExtInt
98             PrintDebug("icc_bus: delivering IRQ to core %u\n",dest_apic->core->cpu_id); 
99
100             dest_apic->ops->raise_intr(dest_apic->core, 
101                                        (icr->del_mode != 7) ? icr->vec : extirq,
102                                        dest_apic->priv_data); 
103
104             if ((src_apic != state->ioapic_id) && (dest_apic->core->cpu_id != src_apic)) { 
105                 // Assume core # is same as logical processor for now
106                 // TODO FIX THIS FIX THIS
107                 // THERE SHOULD BE:  guestapicid->virtualapicid map,
108                 //                   cpu_id->logical processor map
109                 //     host maitains logical proc->phsysical proc
110                 PrintDebug("icc_bus: non-local core, forcing it to exit\n"); 
111
112                 V3_Call_On_CPU(dest_apic->core->cpu_id, v3_force_exit, (void *)(dest_apic->core));
113                 // TODO: do what the print says
114             }                                                   
115             break;                                                      
116             
117         case 2:   //SMI                 
118             PrintError("icc_bus: SMI delivery is unsupported\n");       
119             return -1;                                          
120             break;                                                      
121             
122         case 3:  //reserved                                             
123             PrintError("icc_bus: Reserved delivery mode 3 is unsupported\n"); 
124             return -1;                                          
125             break;                                                      
126
127         case 4:  //NMI                                  
128             PrintError("icc_bus: NMI delivery is unsupported\n"); 
129             return -1;                                          
130             break;                                                      
131
132         case 5: { //INIT
133             struct guest_info *core = dest_apic->core;
134
135             PrintDebug("icc_bus: INIT delivery to core %u\n", core->cpu_id);
136
137             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
138
139             // Sanity check
140             if (dest_apic->ipi_state != INIT) { 
141                 PrintError("icc_bus: Warning: core %u is not in INIT state (mode = %d), ignored\n",
142                            core->cpu_id, core->cpu_mode);
143                 // Only a warning, since INIT INIT SIPI is common
144                 break;
145             }
146
147             // We transition the target core to SIPI state
148             dest_apic->ipi_state = SIPI;  // note: locking should not be needed here
149
150             // That should be it since the target core should be
151             // waiting in host on this transition
152             // either it's on another core or on a different preemptive thread
153             // in both cases, it will quickly notice this transition 
154             // in particular, we should not need to force an exit here
155
156             PrintDebug("icc_bus: INIT delivery done\n");
157
158         }
159             break;                                                      
160
161         case 6: { //SIPI
162             struct guest_info *core = dest_apic->core;
163
164             // Sanity check
165             if (dest_apic->ipi_state != SIPI) { 
166                 PrintError("icc_bus: core %u is not in SIPI state (mode = %d), ignored!\n",core->cpu_id, core->cpu_mode);
167                 break;
168             }
169
170             // Write the RIP, CS, and descriptor
171             // assume the rest is already good to go
172             //
173             // vector VV -> rip at 0
174             //              CS = VV00
175             //  This means we start executing at linear address VV000
176             //
177             // So the selector needs to be VV00
178             // and the base needs to be VV000
179             //
180             core->rip = 0;
181             core->segments.cs.selector = icr->vec << 8;
182             core->segments.cs.limit = 0xffff;
183             core->segments.cs.base = icr->vec << 12;
184
185             PrintDebug("icc_bus: SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
186                        icr->vec, core->segments.cs.selector, core->cpu_id);
187             // Maybe need to adjust the APIC?
188             
189             // We transition the target core to SIPI state
190             core->core_run_state = CORE_RUNNING;  // note: locking should not be needed here
191
192             // As with INIT, we should not need to do anything else
193
194             PrintDebug("icc_bus: SIPI delivery done\n");
195
196         }
197             break;                                                      
198     }
199
200     return 0;
201
202
203
204 //
205 // icr_data contains interrupt vector *except* for ext_int
206 // in which case it is given via irq
207 //
208
209 int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data, uint32_t extirq) {
210
211     struct int_cmd_reg *icr = (struct int_cmd_reg *)&icr_data;
212
213     struct icc_bus_state * state = (struct icc_bus_state *)icc_bus->private_data;
214     struct apic_data * dest_apic = NULL;
215     PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx, extirq=%u\n", 
216                icc_bus, src_apic, icr_data, extirq);
217
218     // initial sanity checks
219     if ((src_apic >= MAX_APICS) || 
220         ((state->apics[src_apic].present == 0) && 
221          (src_apic != state->ioapic_id))) { 
222         PrintError("icc_bus: Apparently sending from unregistered apic id=%u\n",src_apic);
223         return -1;
224     }
225
226
227     if ((icr->dst_mode == 0) && (state->apics[icr->dst].present == 0)) { 
228         PrintError("icc_bus: Attempted send to unregistered apic id=%u\n", icr->dst);
229         return -1;
230     }
231
232     dest_apic =  &(state->apics[icr->dst]);
233
234
235     PrintDebug("icc_bus: IPI %s %u from %s %u to %s %s %u (icr=0x%llx, extirq=%u)\n",
236                deliverymode_str[icr->del_mode], icr->vec, 
237                src_apic==state->ioapic_id ? "ioapic" : "apic",
238                src_apic,               
239                icr->dst_mode==0 ? "(physical)" : "(logical)", 
240                shorthand_str[icr->dst_shorthand], icr->dst,icr->val,
241                extirq);
242
243     /*
244
245     if (icr->dst==state->ioapic_id) { 
246         PrintError("icc_bus: Attempted send to ioapic ignored\n");
247         return -1;
248     }
249     */
250
251
252
253     switch (icr->dst_shorthand) {
254
255         case 0:  // no shorthand
256
257             if (icr->dst_mode==0) { 
258                 // physical delivery
259                 struct apic_data * dest_apic =  &(state->apics[icr->dst]);
260                 if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
261                     return -1;
262                 }
263             } else {
264                 // logical delivery
265                 int i;
266                 uint8_t mda = icr->dst;
267                 for (i=0;i<MAX_APICS;i++) { 
268                     struct apic_data *dest_apic=&(state->apics[i]);
269                     if (dest_apic->present &&
270                         dest_apic->ops->should_deliver(dest_apic->core,
271                                                        mda,
272                                                        dest_apic->priv_data)) {
273                         if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
274                             return -1;
275                         }
276                     }
277                 }
278             }
279             
280             break;
281             
282         case 1:  // self
283
284             if (icr->dst_mode==0) { 
285                 // physical delivery
286                 if (icr->dst==state->ioapic_id) { 
287                     PrintError("icc_bus: ioapic attempting to send to itself\n");
288                     return -1;
289                 }
290                 struct apic_data *dest_apic=&(state->apics[src_apic]);
291                 if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
292                     return -1;
293                 }
294             } else {
295                 // logical delivery
296                 PrintError("icc_bus: use of logical delivery in self is not yet supported.\n");
297
298                 return -1;
299             }
300             break;
301             
302         case 2: 
303
304         case 3: { // all and all-but-me
305             // assuming that logical verus physical doesn't matter
306             // although it is odd that both are used
307             int i;
308             for (i=0;i<MAX_APICS;i++) { 
309                 struct apic_data *dest_apic=&(state->apics[i]);
310                 if (dest_apic->present && (i!=src_apic || icr->dst_shorthand==2)) { 
311                     if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
312                         return -1;
313                     }
314                 }
315             }
316         }
317             break;
318
319         default:
320             return -1;
321     }
322     
323
324     return 0;
325 }
326
327
328
329 /* THIS IS A BIG ASSUMPTION: APIC PHYSID == LOGID == CORENUM */
330
331 int v3_icc_register_apic(struct guest_info  * core, struct vm_device * icc_bus, 
332                          uint8_t apic_num, struct v3_icc_ops * ops, void * priv_data) {
333     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
334     struct apic_data * apic = &(icc->apics[apic_num]);
335
336     if (apic->present == 1) {
337         PrintError("icc_bus: Attempt to re-register apic %u\n", apic_num);
338         return -1;
339     }
340     
341     apic->present = 1;
342     apic->priv_data = priv_data;
343     apic->core = core;
344     apic->ops = ops;
345    
346     PrintDebug("icc_bus: Registered apic %u\n", apic_num);
347
348     return 0;
349 }
350
351
352 int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, uint8_t apic_num)
353 {
354     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
355
356     if (icc->ioapic_id) { 
357         PrintError("icc_bus: Attempt to register a second ioapic!\n");
358         return -1;
359     }
360
361     icc->ioapic_id=apic_num;
362
363     PrintDebug("icc_bus: Registered ioapic %u\n", apic_num);
364     
365
366     return 0;
367 }
368
369
370 static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
371     PrintDebug("icc_bus: Creating ICC_BUS\n");
372
373     char * dev_id = v3_cfg_val(cfg, "ID");
374
375     struct icc_bus_state * icc_bus = (struct icc_bus_state *)V3_Malloc(sizeof(struct icc_bus_state));
376     memset(icc_bus, 0, sizeof(struct icc_bus_state));
377
378     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, icc_bus);
379
380     if (v3_attach_device(vm, dev) == -1) {
381         PrintError("icc_bus: Could not attach device %s\n", dev_id);
382         return -1;
383     }
384
385     return 0;
386 }
387
388
389
390 device_register("ICC_BUS", icc_bus_init)