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.


cfe3c056e0eca463fbd2000f9bc4102694dbc3bb
[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             dest_apic->ops->raise_intr(dest_apic->core, 
100                                        icr->del_mode!=7 ? icr->vec : extirq,
101                                        dest_apic->priv_data); 
102             if (src_apic!=state->ioapic_id && dest_apic->core->cpu_id != src_apic) { 
103                 // Assume core # is same as logical processor for now
104                 // TODO FIX THIS FIX THIS
105                 // THERE SHOULD BE:  guestapicid->virtualapicid map,
106                 //                   cpu_id->logical processor map
107                 //     host maitains logical proc->phsysical proc
108                 PrintDebug("icc_bus: non-local core, forcing it to exit\n"); 
109                 V3_Call_On_CPU(dest_apic->core->cpu_id,v3_force_exit,(void*)(dest_apic->core));
110                 // TODO: do what the print says
111             }                                                   
112             break;                                                      
113             
114         case 2:   //SMI                 
115             PrintError("icc_bus: SMI delivery is unsupported\n");       
116             return -1;                                          
117             break;                                                      
118             
119         case 3:  //reserved                                             
120             PrintError("icc_bus: Reserved delivery mode 3 is unsupported\n"); 
121             return -1;                                          
122             break;                                                      
123
124         case 4:  //NMI                                  
125             PrintError("icc_bus: NMI delivery is unsupported\n"); 
126             return -1;                                          
127             break;                                                      
128
129         case 5: { //INIT
130             struct guest_info *core = dest_apic->core;
131
132             PrintDebug("icc_bus: INIT delivery to core %u\n",core->cpu_id);
133
134             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
135
136             // Sanity check
137             if (core->cpu_mode != INIT) { 
138                 PrintError("icc_bus: Warning: core %u is not in INIT state, ignored\n",core->cpu_id);
139                 // Only a warning, since INIT INIT SIPI is common
140                 break;
141             }
142
143             // We transition the target core to SIPI state
144             core->cpu_mode = SIPI;  // note: locking should not be needed here
145
146             // That should be it since the target core should be
147             // waiting in host on this transition
148             // either it's on another core or on a different preemptive thread
149             // in both cases, it will quickly notice this transition 
150             // in particular, we should not need to force an exit here
151
152             PrintDebug("icc_bus: INIT delivery done\n");
153
154         }
155             break;                                                      
156
157         case 6: { //SIPI
158             struct guest_info *core = dest_apic->core;
159
160             // Sanity check
161             if (core->cpu_mode!=SIPI) { 
162                 PrintError("icc_bus: core %u is not in SIPI state, ignored!\n",core->cpu_id);
163                 break;
164             }
165
166             // Write the RIP, CS, and descriptor
167             // assume the rest is already good to go
168             //
169             // vector VV -> rip at 0
170             //              CS = VV00
171             //  This means we start executing at linear address VV000
172             //
173             // So the selector needs to be VV00
174             // and the base needs to be VV000
175             //
176             core->rip = 0;
177             core->segments.cs.selector = icr->vec << 8;
178             core->segments.cs.limit = 0xffff;
179             core->segments.cs.base = icr->vec << 12;
180
181             PrintDebug("icc_bus: SIPI delivery (0x%x -> 0x%x:0x0) to core %u\n",
182                        icr->vec, core->segments.cs.selector, core->cpu_id);
183             // Maybe need to adjust the APIC?
184             
185             // We transition the target core to SIPI state
186             core->cpu_mode = REAL;  // note: locking should not be needed here
187
188             // As with INIT, we should not need to do anything else
189
190             PrintDebug("icc_bus: SIPI delivery done\n");
191
192         }
193             break;                                                      
194     }
195
196     return 0;
197
198
199
200 //
201 // icr_data contains interrupt vector *except* for ext_int
202 // in which case it is given via irq
203 //
204
205 int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data, 
206                     uint32_t dfr_data, uint32_t extirq) {
207
208     PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx, extirq=%u\n",icc_bus,src_apic,icr_data,extirq);
209
210     struct int_cmd_reg *icr = (struct int_cmd_reg *)&icr_data;
211     struct dst_fmt_reg *dfr = (struct dst_fmt_reg*)&dfr_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, dfr=0x%x) (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, dfr->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                 uint8_t mda = icr->dst; // message destination address, not physical address
266                 
267                 if (dfr->model==0xf) { 
268                     // flat model
269                     // this means we deliver the IPI each destination APIC where
270                     // mda of sender & ldr of receiver is nonzero
271                     // mda=0xff means broadcast to all
272                     //
273                     int i;
274                     for (i=0;i<MAX_APICS;i++) { 
275                         struct apic_data *dest_apic=&(state->apics[i]);
276                         if (dest_apic->present &&
277                             dest_apic->ops->should_deliver_flat(dest_apic->core,
278                                                                 mda,
279                                                                 dest_apic->priv_data)) {
280                             if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
281                                 return -1;
282                             }
283                         }
284                     }
285                 } else if (dfr->model==0x0) {
286                     // cluster model
287                     //
288                     // there are two variants of this
289                     //
290                     // 1. (ancient P5/P6) All apics are on one bus
291                     //    mda[31:28] is the target cluster, 
292                     //    mda[27:24] has one bit for each apic in the cluster
293                     //    mda[31:28] of sending apic == ldr[31:28] of dest apic means
294                     //      the dest apic is part of the cluster
295                     //      then mda[27:24] & ldr[27:24] nonzero means to deliver
296                     //    also, mda=0xff still means broadcast 
297                     //    So, basically, you have 15 clusters of 4 apics each + broadcast
298                     //
299                     // 2. (current) hierarchical cluster model
300                     //    This is some hwat unclearly documented in volume 3, 9-32
301                     //    basically, you have a hierarchy of clusters that where
302                     //    each cluster has 4 agents (APICs?) and a cluster manager.
303                     //    The cluster manager is not an apic, though, and outside of
304                     //    scope of documents.  Again, you have 15 clusters of 4 apics
305                     //    each + broadcast.   My impression is that this is identical 
306                     //    to variant 1 for our purposes. 
307                     //
308                     //
309                     // if we are in lowest priorty mode, we should just pick one
310                     // according to the arbitrarion prioty register
311                     int i;
312                     for (i=0;i<MAX_APICS;i++) { 
313                         struct apic_data *dest_apic=&(state->apics[i]);
314                         if (dest_apic->present &&
315                             dest_apic->ops->should_deliver_cluster(dest_apic->core,
316                                                                    mda,
317                                                                    dest_apic->priv_data)) {
318                             if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
319                                 return -1;
320                             }
321                         }
322                     }
323                 } else {
324                     PrintError("icc_bus: unknown logical delivery model 0x%x\n", dfr->model);
325                     return -1;
326                 }
327
328             }
329             
330             break;
331             
332         case 1:  // self
333
334             if (icr->dst_mode==0) { 
335                 // physical delivery
336                 if (icr->dst==state->ioapic_id) { 
337                     PrintError("icc_bus: ioapic attempting to send to itself\n");
338                     return -1;
339                 }
340                 struct apic_data *dest_apic=&(state->apics[src_apic]);
341                 if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
342                     return -1;
343                 }
344             } else {
345                 // logical delivery
346                 PrintError("icc_bus: use of logical delivery in self is not yet supported.\n");
347
348                 return -1;
349             }
350             break;
351             
352         case 2: 
353
354         case 3: { // all and all-but-me
355             if (icr->dst_mode==0) { 
356                 // physical
357                 int i;
358                 for (i=0;i<MAX_APICS;i++) { 
359                     struct apic_data *dest_apic=&(state->apics[i]);
360                     if (dest_apic->present && (i!=src_apic || icr->dst_shorthand==2)) { 
361                         if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
362                             return -1;
363                         }
364
365                     }
366                 }
367             } else {
368                 // logical delivery
369                 PrintError("icc_bus: use of logical delivery in %s is not yet supported\n",
370                            icr->dst_shorthand==2 ? "all" : "all-but-me" );
371                 return -1;
372             }
373             break;
374         }
375         default:
376             return -1;
377     }
378     
379
380     return 0;
381 }
382
383
384
385 /* THIS IS A BIG ASSUMPTION: APIC PHYSID == LOGID == CORENUM */
386
387 int v3_icc_register_apic(struct guest_info  * core, struct vm_device * icc_bus, 
388                          uint8_t apic_num, struct v3_icc_ops * ops, void * priv_data) {
389     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
390     struct apic_data * apic = &(icc->apics[apic_num]);
391
392     if (apic->present == 1) {
393         PrintError("icc_bus: Attempt to re-register apic %u\n", apic_num);
394         return -1;
395     }
396     
397     apic->present = 1;
398     apic->priv_data = priv_data;
399     apic->core = core;
400     apic->ops = ops;
401    
402     PrintDebug("icc_bus: Registered apic %u\n", apic_num);
403
404     return 0;
405 }
406
407
408 int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, uint8_t apic_num)
409 {
410     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
411
412     if (icc->ioapic_id) { 
413         PrintError("icc_bus: Attempt to register a second ioapic!\n");
414         return -1;
415     }
416
417     icc->ioapic_id=apic_num;
418
419     PrintDebug("icc_bus: Registered ioapic %u\n", apic_num);
420     
421
422     return 0;
423 }
424
425
426 static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
427     PrintDebug("icc_bus: Creating ICC_BUS\n");
428
429     char * dev_id = v3_cfg_val(cfg, "ID");
430
431     struct icc_bus_state * icc_bus = (struct icc_bus_state *)V3_Malloc(sizeof(struct icc_bus_state));
432     memset(icc_bus, 0, sizeof(struct icc_bus_state));
433
434     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, icc_bus);
435
436     if (v3_attach_device(vm, dev) == -1) {
437         PrintError("icc_bus: Could not attach device %s\n", dev_id);
438         return -1;
439     }
440
441     return 0;
442 }
443
444
445
446 device_register("ICC_BUS", icc_bus_init)