kvm: external module: adjust for new host kernels install location
[qemu-kvm/fedora.git] / hw / hypercall.c
blob73f6bb159362c344903836cd8d5d7d03c84d4f1e
1 /*
2 * QEMU-KVM Hypercall emulation
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 * Copyright (c) 2006 Qumranet
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
25 #include "hw/hw.h"
26 #include "sysemu.h"
27 #include "qemu-char.h"
28 #include "hw/isa.h"
29 #include "hw/irq.h"
30 #include "hw/pci.h"
31 #include "hypercall.h"
32 #include <stddef.h>
34 #define HYPERCALL_IOPORT_SIZE 0x100
36 static int use_hypercall_dev = 0;
38 typedef struct VmChannelCharDriverState {
39 CharDriverState *vmchannel_hd;
40 uint32_t deviceid;
41 } VmChannelCharDriverState;
43 static VmChannelCharDriverState vmchannel_hds[MAX_VMCHANNEL_DEVICES];
45 typedef struct HypercallState {
46 uint32_t hcr;
47 uint32_t hsr;
48 uint32_t txsize;
49 uint32_t txbuff;
50 uint32_t rxsize;
51 uint8_t RxBuff[HP_MEM_SIZE];
52 uint8_t txbufferaccu[HP_MEM_SIZE];
53 int txbufferaccu_offset;
54 int irq;
55 PCIDevice *pci_dev;
56 uint32_t index;
57 } HypercallState;
59 static HypercallState *pHypercallStates[MAX_VMCHANNEL_DEVICES] = {NULL};
61 //#define HYPERCALL_DEBUG 1
63 static void hp_reset(HypercallState *s)
65 s->hcr = HCR_DI;
66 s->hsr = 0;
67 s->txsize = 0;
68 s->txbuff = 0;
69 s->rxsize= 0;
70 s->txbufferaccu_offset = 0;
73 static void hypercall_update_irq(HypercallState *s);
76 static void hp_ioport_write(void *opaque, uint32_t addr, uint32_t val)
78 HypercallState *s = opaque;
80 #ifdef HYPERCALL_DEBUG
81 printf("%s: addr=0x%x, val=0x%x\n", __FUNCTION__, addr, val);
82 #endif
83 addr &= 0xff;
85 switch(addr)
87 case HCR_REGISTER:
89 s->hcr = val;
90 if (s->hcr & HCR_DI)
91 hypercall_update_irq(s);
92 if (val & HCR_GRS){
93 hp_reset(s);
95 break;
98 case HP_TXSIZE:
100 // handle the case when the we are being called when txsize is not 0
101 if (s->txsize != 0) {
102 printf("txsize is being set, but txsize is not 0!!!\n");
104 if (val > HP_MEM_SIZE) {
105 printf("txsize is larger than allowed by hw!!!\n");
107 s->txsize = val;
108 s->txbufferaccu_offset = 0;
109 break;
112 case HP_TXBUFF:
114 if (s->txsize == 0) {
115 printf("error with txbuff!!!\n");
116 break;
119 s->txbufferaccu[s->txbufferaccu_offset] = val;
120 s->txbufferaccu_offset++;
121 if (s->txbufferaccu_offset >= s->txsize) {
122 qemu_chr_write(vmchannel_hds[s->index].vmchannel_hd, s->txbufferaccu, s->txsize);
123 s->txbufferaccu_offset = 0;
124 s->txsize = 0;
126 break;
128 default:
130 printf("hp_ioport_write to unhandled address!!!\n");
135 static uint32_t hp_ioport_read(void *opaque, uint32_t addr)
137 HypercallState *s = opaque;
138 int ret;
140 addr &= 0xff;
141 #ifdef HYPERCALL_DEBUG
142 // Since HSR_REGISTER is being repeatedly read in the guest ISR we don't print it
143 if (addr != HSR_REGISTER)
144 printf("%s: addr=0x%x", __FUNCTION__, addr);
145 #endif
147 if (addr >= offsetof(HypercallState, RxBuff) )
149 int RxBuffOffset = addr - (offsetof(HypercallState, RxBuff));
150 ret = s->RxBuff[RxBuffOffset];
151 #ifdef HYPERCALL_DEBUG
152 printf(" val=%x\n", ret);
153 #endif
154 return ret;
157 switch (addr)
159 case HSR_REGISTER:
160 ret = s->hsr;
161 if (ret & HSR_VDR) {
162 s->hsr &= ~HSR_VDR;
164 break;
165 case HP_RXSIZE:
166 ret = s->rxsize;
167 break;
169 default:
170 ret = 0x00;
171 break;
173 #ifdef HYPERCALL_DEBUG
174 printf(" val=%x\n", ret);
175 #endif
176 return ret;
179 /***********************************************************/
180 /* PCI Hypercall definitions */
182 typedef struct PCIHypercallState {
183 PCIDevice dev;
184 HypercallState hp;
185 } PCIHypercallState;
187 static void hp_map(PCIDevice *pci_dev, int region_num,
188 uint32_t addr, uint32_t size, int type)
190 PCIHypercallState *d = (PCIHypercallState *)pci_dev;
191 HypercallState *s = &d->hp;
193 register_ioport_write(addr, HYPERCALL_IOPORT_SIZE, 1, hp_ioport_write, s);
194 register_ioport_read(addr, HYPERCALL_IOPORT_SIZE, 1, hp_ioport_read, s);
199 static void hypercall_update_irq(HypercallState *s)
201 /* PCI irq */
202 qemu_set_irq(s->pci_dev->irq[0], !(s->hcr & HCR_DI));
205 static void hc_save(QEMUFile* f,void* opaque)
207 HypercallState* s=(HypercallState*)opaque;
209 pci_device_save(s->pci_dev, f);
211 qemu_put_be32s(f, &s->hcr);
212 qemu_put_be32s(f, &s->hsr);
213 qemu_put_be32s(f, &s->txsize);
214 qemu_put_be32s(f, &s->txbuff);
215 qemu_put_be32s(f, &s->rxsize);
216 qemu_put_buffer(f, s->RxBuff, HP_MEM_SIZE);
217 qemu_put_buffer(f, s->txbufferaccu, HP_MEM_SIZE);
218 qemu_put_be32s(f, &s->txbufferaccu_offset);
219 qemu_put_be32s(f, &s->irq);
220 qemu_put_be32s(f, &s->index);
224 static int hc_load(QEMUFile* f,void* opaque,int version_id)
226 HypercallState* s=(HypercallState*)opaque;
227 int ret;
229 if (version_id != 1)
230 return -EINVAL;
232 ret = pci_device_load(s->pci_dev, f);
233 if (ret < 0)
234 return ret;
236 qemu_get_be32s(f, &s->hcr);
237 qemu_get_be32s(f, &s->hsr);
238 qemu_get_be32s(f, &s->txsize);
239 qemu_get_be32s(f, &s->txbuff);
240 qemu_get_be32s(f, &s->rxsize);
241 qemu_get_buffer(f, s->RxBuff, HP_MEM_SIZE);
242 qemu_get_buffer(f, s->txbufferaccu, HP_MEM_SIZE);
243 qemu_get_be32s(f, &s->txbufferaccu_offset);
244 qemu_get_be32s(f, &s->irq);
245 qemu_get_be32s(f, &s->index);
247 return 0;
250 static void pci_hypercall_single_init(PCIBus *bus, uint32_t deviceid, uint32_t index)
252 PCIHypercallState *d;
253 HypercallState *s;
254 uint8_t *pci_conf;
255 char name[sizeof("HypercallX")];
257 sprintf(name, "Hypercall%d", index);
259 #ifdef HYPERCALL_DEBUG
260 printf("%s, devicename:%s\n", __FUNCTION__, name);
261 #endif
263 // If the vmchannel wasn't initialized, we don't want the Hypercall device in the guest
264 if (use_hypercall_dev == 0) {
265 return;
268 d = (PCIHypercallState *)pci_register_device(bus,
269 name, sizeof(PCIHypercallState),
271 NULL, NULL);
273 pci_conf = d->dev.config;
274 pci_conf[0x00] = 0x02; // Qumranet vendor ID 0x5002
275 pci_conf[0x01] = 0x50;
276 pci_conf[0x02] = deviceid & 0x00ff;
277 pci_conf[0x03] = (deviceid & 0xff00) >> 8;
279 pci_conf[0x09] = 0x00; // ProgIf
280 pci_conf[0x0a] = 0x00; // SubClass
281 pci_conf[0x0b] = 0x05; // BaseClass
283 pci_conf[0x0e] = 0x00; // header_type
284 pci_conf[0x3d] = 1; // interrupt pin 0
286 pci_register_io_region(&d->dev, 0, HYPERCALL_IOPORT_SIZE,
287 PCI_ADDRESS_SPACE_IO, hp_map);
288 s = &d->hp;
289 pHypercallStates[index] = s;
290 s->index = index;
291 s->irq = 16; /* PCI interrupt */
292 s->pci_dev = (PCIDevice *)d;
294 hp_reset(s);
295 register_savevm(name, index, 1, hc_save, hc_load, s);
298 void pci_hypercall_init(PCIBus *bus)
300 int i;
302 // loop devices & call pci_hypercall_single_init with device id's
303 for(i = 0; i < MAX_VMCHANNEL_DEVICES; i++){
304 if (vmchannel_hds[i].vmchannel_hd) {
305 pci_hypercall_single_init(bus, vmchannel_hds[i].deviceid, i);
310 static int vmchannel_can_read(void *opaque)
312 return 128;
315 static void vmchannel_event(void *opaque, int event)
318 #ifdef HYPERCALL_DEBUG
319 // if index is to be used outside the printf, take it out of the #ifdef block!
320 long index = (long)opaque;
321 printf("%s index:%ld, got event %i\n", __FUNCTION__, index, event);
322 #endif
324 return;
327 // input from vmchannel outside caller
328 static void vmchannel_read(void *opaque, const uint8_t *buf, int size)
330 int i;
331 long index = (long)opaque;
333 #ifdef HYPERCALL_DEBUG
334 printf("vmchannel_read buf size:%d\n", size);
335 #endif
337 // if the hypercall device is in interrupts disabled state, don't accept the data
338 if (pHypercallStates[index]->hcr & HCR_DI) {
339 return;
342 for(i = 0; i < size; i++) {
343 pHypercallStates[index]->RxBuff[i] = buf[i];
345 pHypercallStates[index]->rxsize = size;
346 pHypercallStates[index]->hsr = HSR_VDR;
347 hypercall_update_irq(pHypercallStates[index]);
350 void vmchannel_init(CharDriverState *hd, uint32_t deviceid, uint32_t index)
352 #ifdef HYPERCALL_DEBUG
353 printf("vmchannel_init, index=%d, deviceid=0x%x\n", index, deviceid);
354 #endif
356 vmchannel_hds[index].deviceid = deviceid;
357 vmchannel_hds[index].vmchannel_hd = hd;
359 use_hypercall_dev = 1;
360 qemu_chr_add_handlers(vmchannel_hds[index].vmchannel_hd, vmchannel_can_read, vmchannel_read,
361 vmchannel_event, (void *)(long)index);