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.


Resolved Patrick's debug patches and the external irq work
[palacios-OLD.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
27 #define MAX_APICS 256
28
29 #ifndef CONFIG_DEBUG_ICC_BUS
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35 void v3_force_exit(void *p) {
36 #ifdef CONFIG_DEBUG_ICC_BUS
37     struct guest_info *core=(struct guest_info *)p;
38 #endif
39     PrintDebug("core %u: Forced to exit!\n",core->cpu_id);
40 }
41
42 struct ipi_thunk_data {
43     struct vm_device * target;
44     uint64_t val;
45 };
46
47
48
49 struct apic_data {
50     struct guest_info * core;
51     struct v3_icc_ops * ops;
52     
53     void * priv_data;
54     int present;
55 };
56
57
58 struct icc_bus_state {
59     struct apic_data apics[MAX_APICS];
60     
61     uint32_t         ioapic_id;
62 };
63
64 static struct v3_device_ops dev_ops = {
65     .free = NULL,
66     .reset = NULL,
67     .start = NULL,
68     .stop = NULL,
69 };
70
71 #ifdef CONFIG_DEBUG_ICC_BUS
72 static char *shorthand_str[] = { 
73     "(no shorthand)",
74     "(self)",
75     "(all)",
76     "(all-but-me)",
77  };
78
79 static char *deliverymode_str[] = { 
80     "(fixed)",
81     "(lowest priority)",
82     "(SMI)",
83     "(reserved)",
84     "(NMI)",
85     "(INIT)",
86     "(Start Up)",
87     "(ExtInt)",
88 };
89 #endif
90
91
92 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) {
93
94     switch (icr->del_mode) {                                            
95
96         case 0:  //fixed
97         case 1: // lowest priority
98         case 7: // ExtInt
99             PrintDebug("icc_bus: delivering IRQ to core %u\n",dest_apic->core->cpu_id); 
100             dest_apic->ops->raise_intr(dest_apic->core, 
101                                        icr->del_mode!=7 ? icr->vec : extirq,
102                                        dest_apic->priv_data); 
103             if (src_apic!=state->ioapic_id && dest_apic->core->cpu_id != src_apic) { 
104                 // Assume core # is same as logical processor for now
105                 // TODO FIX THIS FIX THIS
106                 // THERE SHOULD BE:  guestapicid->virtualapicid map,
107                 //                   cpu_id->logical processor map
108                 //     host maitains logical proc->phsysical proc
109                 PrintDebug("icc_bus: non-local core, forcing it to exit\n"); 
110                 V3_Call_On_CPU(dest_apic->core->cpu_id,v3_force_exit,(void*)(dest_apic->core));
111                 // TODO: do what the print says
112             }                                                   
113             break;                                                      
114             
115         case 2:   //SMI                 
116             PrintError("icc_bus: SMI delivery is unsupported\n");       
117             return -1;                                          
118             break;                                                      
119             
120         case 3:  //reserved                                             
121             PrintError("icc_bus: Reserved delivery mode 3 is unsupported\n"); 
122             return -1;                                          
123             break;                                                      
124
125         case 4:  //NMI                                  
126             PrintError("icc_bus: NMI delivery is unsupported\n"); 
127             return -1;                                          
128             break;                                                      
129
130         case 5: { //INIT
131             struct guest_info *core = dest_apic->core;
132
133             PrintDebug("icc_bus: INIT delivery to core %u\n",core->cpu_id);
134
135             // TODO: any APIC reset on dest core (shouldn't be needed, but not sure...)
136
137             // Sanity check
138             if (core->cpu_mode!=INIT) { 
139                 PrintError("icc_bus: Warning: core %u is not in INIT state, ignored\n",core->cpu_id);
140                 // Only a warning, since INIT INIT SIPI is common
141                 break;
142             }
143
144             // We transition the target core to SIPI state
145             core->cpu_mode=SIPI;  // note: locking should not be needed here
146
147             // That should be it since the target core should be
148             // waiting in host on this transition
149             // either it's on another core or on a different preemptive thread
150             // in both cases, it will quickly notice this transition 
151             // in particular, we should not need to force an exit here
152
153             PrintDebug("icc_bus: INIT delivery done\n");
154
155         }
156             break;                                                      
157
158         case 6: { //SIPI
159             struct guest_info *core = dest_apic->core;
160             uint64_t rip = icr->vec << 12;  // vector encodes target address;
161
162             PrintDebug("icc_bus: SIPI delivery (0x%x -> rip=0x%p) to core %u\n",
163                        icr->vec, (void*)rip, core->cpu_id);
164
165             // Sanity check
166             if (core->cpu_mode!=SIPI) { 
167                 PrintError("icc_bus: core %u is not in SIPI state, ignored!\n",core->cpu_id);
168                 break;
169             }
170
171             // Write the RIP, CS, and descriptor
172             // assume the rest is already good to go
173             core->rip=rip & 0xffff;
174             core->segments.cs.selector = (rip >> 4) & 0xf000;
175             core->segments.cs.limit= 0xffff;
176             core->segments.cs.base = rip & 0xf0000;
177
178             // Maybe need to adjust the APIC?
179             
180             // We transition the target core to SIPI state
181             core->cpu_mode=REAL;  // note: locking should not be needed here
182
183             // As with INIT, we should not need to do anything else
184
185             PrintDebug("icc_bus: SIPI delivery done\n");
186
187         }
188             break;                                                      
189     }
190
191     return 0;
192
193
194
195 //
196 // icr_data contains interrupt vector *except* for ext_int
197 // in which case it is given via irq
198 //
199 int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data, uint32_t extirq) {
200
201     PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx, extirq=%u\n",icc_bus,src_apic,icr_data,extirq);
202
203     struct int_cmd_reg *icr = (struct int_cmd_reg *)&icr_data;
204     struct icc_bus_state * state = (struct icc_bus_state *)icc_bus->private_data;
205
206     // initial sanity checks
207     if (src_apic>=MAX_APICS || (!state->apics[src_apic].present && src_apic!=state->ioapic_id)) { 
208         PrintError("icc_bus: Apparently sending from unregistered apic id=%u\n",src_apic);
209         return -1;
210     }
211     if (icr->dst_mode==0  && !state->apics[icr->dst].present) { 
212         PrintError("icc_bus: Attempted send to unregistered apic id=%u\n",icr->dst);
213         return -1;
214     }
215     
216     struct apic_data * dest_apic =  &(state->apics[icr->dst]);
217
218     PrintDebug("icc_bus: IPI %s %u from %s %u to %s %u (icr=0x%llx) (extirq=%u)\n",
219                deliverymode_str[icr->del_mode], icr->vec, src_apic==state->ioapic_id ? "ioapic" : "apic",
220                src_apic, shorthand_str[icr->dst_shorthand], icr->dst,icr->val,
221                extirq);
222
223
224
225
226     switch (icr->dst_shorthand) {
227
228         case 0:  // no shorthand
229             if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
230                 return -1;
231             }
232             break;
233
234         case 1:  // self
235             if (icr->dst==state->ioapic_id) { 
236                 PrintError("icc_bus: ioapic attempting to send to itself\n");
237                 return -1;
238             }
239             if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
240                 return -1;
241             }
242             break;
243
244         case 2: 
245         case 3: { // all and all-but-me
246             int i;
247             for (i=0;i<MAX_APICS;i++) { 
248                 dest_apic=&(state->apics[i]);
249                 if (dest_apic->present && (i!=src_apic || icr->dst_shorthand==2)) { 
250                     if (deliver(src_apic,dest_apic,icr,state,extirq)) { 
251                         return -1;
252                     }
253                 }
254             }
255         }
256             break;
257     }
258
259     return 0;
260 }
261
262
263
264 /* THIS IS A BIG ASSUMPTION: APIC PHYSID == LOGID == CORENUM */
265
266 int v3_icc_register_apic(struct guest_info  * core, struct vm_device * icc_bus, 
267                          uint8_t apic_num, struct v3_icc_ops * ops, void * priv_data) {
268     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
269     struct apic_data * apic = &(icc->apics[apic_num]);
270
271     if (apic->present == 1) {
272         PrintError("icc_bus: Attempt to re-register apic %u\n", apic_num);
273         return -1;
274     }
275     
276     apic->present = 1;
277     apic->priv_data = priv_data;
278     apic->core = core;
279     apic->ops = ops;
280    
281     PrintDebug("icc_bus: Registered apic %u\n", apic_num);
282
283     return 0;
284 }
285
286
287 int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, uint8_t apic_num)
288 {
289     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
290
291     if (icc->ioapic_id) { 
292         PrintError("icc_bus: Attempt to register a second ioapic!\n");
293         return -1;
294     }
295
296     icc->ioapic_id=apic_num;
297
298     PrintDebug("icc_bus: Registered ioapic %u\n", apic_num);
299     
300
301     return 0;
302 }
303
304
305
306 static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
307     PrintDebug("icc_bus: Creating ICC_BUS\n");
308
309     char * name = v3_cfg_val(cfg, "name");
310
311     struct icc_bus_state * icc_bus = (struct icc_bus_state *)V3_Malloc(sizeof(struct icc_bus_state));
312     memset(icc_bus, 0, sizeof(struct icc_bus_state));
313
314     struct vm_device * dev = v3_allocate_device(name, &dev_ops, icc_bus);
315
316     if (v3_attach_device(vm, dev) == -1) {
317         PrintError("icc_bus: Could not attach device %s\n", name);
318         return -1;
319     }
320
321     return 0;
322 }
323
324
325
326 device_register("ICC_BUS", icc_bus_init)