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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
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>
29 #ifndef CONFIG_DEBUG_ICC_BUS
31 #define PrintDebug(fmt, args...)
35 void v3_force_exit() {
38 struct ipi_thunk_data {
39 struct vm_device * target;
46 struct guest_info * core;
47 struct v3_icc_ops * ops;
54 struct icc_bus_state {
55 struct apic_data apics[MAX_APICS];
60 static struct v3_device_ops dev_ops = {
68 static char *shorthand_str[] = {
75 static char *deliverymode_str[] = {
88 static int deliver(uint32_t src_apic, struct apic_data *dest_apic, struct int_cmd_reg *icr, struct icc_bus_state * state) {
90 switch (icr->del_mode) {
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
103 PrintError("icc_bus: SMI delivery is unsupported\n");
109 PrintError("icc_bus: Reserved delivery mode 3 is unsupported\n");
114 PrintError("icc_bus: NMI delivery is unsupported\n");
119 PrintError("icc_bus: INIT delivery is unsupported\n");
124 PrintError("icc_bus: Startup Delivery is unsupported\n");
134 int v3_icc_send_ipi(struct vm_device * icc_bus, uint32_t src_apic, uint64_t icr_data) {
136 PrintDebug("icc_bus: icc_bus=%p, src_apic=%u, icr_data=%llx\n",icc_bus,src_apic,icr_data);
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;
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);
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);
151 struct apic_data * dest_apic = &(state->apics[icr->dst]);
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);
161 switch (icr->dst_shorthand) {
163 case 0: // no shorthand
164 if (deliver(src_apic,dest_apic,icr,state)) {
170 if (icr->dst==state->ioapic_id) {
171 PrintError("icc_bus: ioapic attempting to send to itself\n");
174 if (deliver(src_apic,dest_apic,icr,state)) {
180 case 3: { // all and all-but-me
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)) {
199 /* THIS IS A BIG ASSUMPTION: APIC PHYSID == LOGID == CORENUM */
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]);
206 if (apic->present == 1) {
207 PrintError("icc_bus: Attempt to re-register apic %u\n", apic_num);
212 apic->priv_data = priv_data;
216 PrintDebug("icc_bus: Registered apic %u\n", apic_num);
222 int v3_icc_register_ioapic(struct v3_vm_info *vm, struct vm_device * icc_bus, uint8_t apic_num)
224 struct icc_bus_state * icc = (struct icc_bus_state *)icc_bus->private_data;
226 if (icc->ioapic_id) {
227 PrintError("icc_bus: Attempt to register a second ioapic!\n");
231 icc->ioapic_id=apic_num;
233 PrintDebug("icc_bus: Registered ioapic %u\n", apic_num);
241 static int icc_bus_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
242 PrintDebug("icc_bus: Creating ICC_BUS\n");
244 char * name = v3_cfg_val(cfg, "name");
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));
249 struct vm_device * dev = v3_allocate_device(name, &dev_ops, icc_bus);
251 if (v3_attach_device(vm, dev) == -1) {
252 PrintError("icc_bus: Could not attach device %s\n", name);
261 device_register("ICC_BUS", icc_bus_init)