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.


e75734df177029a03305b7f075e86f446c923215
[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
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() {
36 }
37
38 struct ipi_thunk_data {
39     struct vm_device * target;
40     uint64_t val;
41 };
42
43
44
45 struct apic_data {
46     struct guest_info * core;
47     struct v3_icc_ops * ops;
48     
49     void * priv_data;
50     int present;
51 };
52
53
54 struct icc_bus_state {
55     struct apic_data apics[MAX_APICS];
56     
57     uint32_t         ioapic_id;
58 };
59
60 static struct v3_device_ops dev_ops = {
61     .free = NULL,
62     .reset = NULL,
63     .start = NULL,
64     .stop = NULL,
65 };
66
67
68 static char *shorthand_str[] = { 
69     "(no shorthand)",
70     "(self)",
71     "(all)",
72     "(all-but-me)",
73  };
74
75 static char *deliverymode_str[] = { 
76     "(fixed)",
77     "(lowest priority)",
78     "(SMI)",
79     "(reserved)",
80     "(NMI)",
81     "(INIT)",
82     "(Start Up)",
83     "(reserved)",
84 };
85
86
87
88 static int deliver(uint32_t src_apic, struct apic_data *dest_apic, struct int_cmd_reg *icr, struct icc_bus_state * state) {
89
90     switch (icr->del_mode) {                                            
91
92         case 0:  //fixed
93         case 1: // lowest priority
94             PrintDebug("icc_bus: delivering to core %u\n",dest_apic->core->cpu_id); 
95             dest_apic->ops->raise_intr(dest_apic->core, icr->vec, dest_apic->priv_data); 
96             if (src_apic!=state->ioapic_id && dest_apic->core->cpu_id != src_apic) { 
97                 PrintDebug("icc_bus: non-local core, forcing it to exit\n"); 
98                 // TODO: do what the print says
99             }                                                   
100             break;                                                      
101             
102         case 2:   //SMI                 
103             PrintError("icc_bus: SMI delivery is unsupported\n");       
104             return -1;                                          
105             break;                                                      
106             
107         case 3:  //reserved                                             
108         case 7:
109             PrintError("icc_bus: Reserved delivery mode 3 is unsupported\n"); 
110             return -1;                                          
111             break;                                                      
112
113         case 4:  //NMI                                  
114             PrintError("icc_bus: NMI delivery is unsupported\n"); 
115             return -1;                                          
116             break;                                                      
117
118         case 5: //INIT
119             PrintError("icc_bus: INIT delivery is unsupported\n"); 
120             return -1;                                          
121             break;                                                      
122
123         case 6: //Start Up
124             PrintError("icc_bus: Startup Delivery is unsupported\n"); 
125             return -1;                                          
126             break;                                                      
127     }
128
129     return 0;
130
131
132
133
134 int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data) {
135
136     PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx\n",icc_bus,src_apic,icr_data);
137
138     struct int_cmd_reg *icr = (struct int_cmd_reg *)&icr_data;
139     struct icc_bus_state * state = (struct icc_bus_state *)icc_bus->private_data;
140
141     // initial sanity checks
142     if (src_apic>=MAX_APICS || (!state->apics[src_apic].present && src_apic!=state->ioapic_id)) { 
143         PrintError("icc_bus: Apparently sending from unregistered apic id=%u\n",src_apic);
144         return -1;
145     }
146     if (icr->dst_mode==0  && !state->apics[icr->dst].present) { 
147         PrintError("icc_bus: Attempted send to unregistered apic id=%u\n",icr->dst);
148         return -1;
149     }
150     
151     struct apic_data * dest_apic =  &(state->apics[icr->dst]);
152
153
154     PrintDebug("icc_bus: IPI %s %u from %s %u to %s %u (icr=0x%llx)\n",
155                deliverymode_str[icr->del_mode], icr->vec, src_apic==state->ioapic_id ? "ioapic" : "apic",
156                src_apic, shorthand_str[icr->dst_shorthand], icr->dst,icr->val);
157
158
159
160
161     switch (icr->dst_shorthand) {
162
163         case 0:  // no shorthand
164             if (deliver(src_apic,dest_apic,icr,state)) { 
165                 return -1;
166             }
167             break;
168
169         case 1:  // self
170             if (icr->dst==state->ioapic_id) { 
171                 PrintError("icc_bus: ioapic attempting to send to itself\n");
172                 return -1;
173             }
174             if (deliver(src_apic,dest_apic,icr,state)) { 
175                 return -1;
176             }
177             break;
178
179         case 2: 
180         case 3: { // all and all-but-me
181             int i;
182             for (i=0;i<MAX_APICS;i++) { 
183                 dest_apic=&(state->apics[i]);
184                 if (dest_apic->present && (i!=src_apic || icr->dst_shorthand==2)) { 
185                     if (deliver(src_apic,dest_apic,icr,state)) { 
186                         return -1;
187                     }
188                 }
189             }
190         }
191             break;
192     }
193
194     return 0;
195 }
196
197
198
199 /* THIS IS A BIG ASSUMPTION: APIC PHYSID == LOGID == CORENUM */
200
201 int v3_icc_register_apic(struct guest_info  * core, struct vm_device * icc_bus, 
202                          uint8_t apic_num, struct v3_icc_ops * ops, void * priv_data) {
203     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
204     struct apic_data * apic = &(icc->apics[apic_num]);
205
206     if (apic->present == 1) {
207         PrintError("icc_bus: Attempt to re-register apic %u\n", apic_num);
208         return -1;
209     }
210     
211     apic->present = 1;
212     apic->priv_data = priv_data;
213     apic->core = core;
214     apic->ops = ops;
215    
216     PrintDebug("icc_bus: Registered apic %u\n", apic_num);
217
218     return 0;
219 }
220
221
222 int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, uint8_t apic_num)
223 {
224     struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
225
226     if (icc->ioapic_id) { 
227         PrintError("icc_bus: Attempt to register a second ioapic!\n");
228         return -1;
229     }
230
231     icc->ioapic_id=apic_num;
232
233     PrintDebug("icc_bus: Registered ioapic %u\n", apic_num);
234     
235
236     return 0;
237 }
238
239
240
241 static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
242     PrintDebug("icc_bus: Creating ICC_BUS\n");
243
244     char * name = v3_cfg_val(cfg, "name");
245
246     struct icc_bus_state * icc_bus = (struct icc_bus_state *)V3_Malloc(sizeof(struct icc_bus_state));
247     memset(icc_bus, 0, sizeof(struct icc_bus_state));
248
249     struct vm_device * dev = v3_allocate_device(name, &dev_ops, icc_bus);
250
251     if (v3_attach_device(vm, dev) == -1) {
252         PrintError("icc_bus: Could not attach device %s\n", name);
253         return -1;
254     }
255
256     return 0;
257 }
258
259
260
261 device_register("ICC_BUS", icc_bus_init)