kvm: external module: define CONFIG_HAS_IOMEM
[qemu-kvm/amd-iommu.git] / hw / hypercall.c
blob7210f3299653a90b747d83775701a2698ae9f233
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 "vl.h"
26 #include "hypercall.h"
27 #include <stddef.h>
29 #define HYPERCALL_IOPORT_SIZE 0x100
31 static int use_hypercall_dev = 0;
33 typedef struct VmChannelCharDriverState {
34 CharDriverState *vmchannel_hd;
35 uint32_t deviceid;
36 } VmChannelCharDriverState;
38 static VmChannelCharDriverState vmchannel_hds[MAX_VMCHANNEL_DEVICES];
40 typedef struct HypercallState {
41 uint32_t hcr;
42 uint32_t hsr;
43 uint32_t txsize;
44 uint32_t txbuff;
45 uint32_t rxsize;
46 uint8_t RxBuff[HP_MEM_SIZE];
47 uint8_t txbufferaccu[HP_MEM_SIZE];
48 int txbufferaccu_offset;
49 int irq;
50 PCIDevice *pci_dev;
51 uint32_t index;
52 } HypercallState;
54 static HypercallState *pHypercallStates[MAX_VMCHANNEL_DEVICES] = {NULL};
56 //#define HYPERCALL_DEBUG 1
58 static void hp_reset(HypercallState *s)
60 s->hcr = HCR_DI;
61 s->hsr = 0;
62 s->txsize = 0;
63 s->txbuff = 0;
64 s->rxsize= 0;
65 s->txbufferaccu_offset = 0;
68 static void hypercall_update_irq(HypercallState *s);
71 static void hp_ioport_write(void *opaque, uint32_t addr, uint32_t val)
73 HypercallState *s = opaque;
75 #ifdef HYPERCALL_DEBUG
76 printf("%s: addr=0x%x, val=0x%x\n", __FUNCTION__, addr, val);
77 #endif
78 addr &= 0xff;
80 switch(addr)
82 case HCR_REGISTER:
84 s->hcr = val;
85 if (s->hcr & HCR_DI)
86 hypercall_update_irq(s);
87 if (val & HCR_GRS){
88 hp_reset(s);
90 break;
93 case HP_TXSIZE:
95 // handle the case when the we are being called when txsize is not 0
96 if (s->txsize != 0) {
97 printf("txsize is being set, but txsize is not 0!!!\n");
99 if (val > HP_MEM_SIZE) {
100 printf("txsize is larger than allowed by hw!!!\n");
102 s->txsize = val;
103 s->txbufferaccu_offset = 0;
104 break;
107 case HP_TXBUFF:
109 if (s->txsize == 0) {
110 printf("error with txbuff!!!\n");
111 break;
114 s->txbufferaccu[s->txbufferaccu_offset] = val;
115 s->txbufferaccu_offset++;
116 if (s->txbufferaccu_offset >= s->txsize) {
117 qemu_chr_write(vmchannel_hds[s->index].vmchannel_hd, s->txbufferaccu, s->txsize);
118 s->txbufferaccu_offset = 0;
119 s->txsize = 0;
121 break;
123 default:
125 printf("hp_ioport_write to unhandled address!!!\n");
130 static uint32_t hp_ioport_read(void *opaque, uint32_t addr)
132 HypercallState *s = opaque;
133 int ret;
135 addr &= 0xff;
136 #ifdef HYPERCALL_DEBUG
137 // Since HSR_REGISTER is being repeatedly read in the guest ISR we don't print it
138 if (addr != HSR_REGISTER)
139 printf("%s: addr=0x%x", __FUNCTION__, addr);
140 #endif
142 if (addr >= offsetof(HypercallState, RxBuff) )
144 int RxBuffOffset = addr - (offsetof(HypercallState, RxBuff));
145 ret = s->RxBuff[RxBuffOffset];
146 #ifdef HYPERCALL_DEBUG
147 printf(" val=%x\n", ret);
148 #endif
149 return ret;
152 switch (addr)
154 case HSR_REGISTER:
155 ret = s->hsr;
156 if (ret & HSR_VDR) {
157 s->hsr &= ~HSR_VDR;
159 break;
160 case HP_RXSIZE:
161 ret = s->rxsize;
162 break;
164 default:
165 ret = 0x00;
166 break;
168 #ifdef HYPERCALL_DEBUG
169 printf(" val=%x\n", ret);
170 #endif
171 return ret;
174 /***********************************************************/
175 /* PCI Hypercall definitions */
177 typedef struct PCIHypercallState {
178 PCIDevice dev;
179 HypercallState hp;
180 } PCIHypercallState;
182 static void hp_map(PCIDevice *pci_dev, int region_num,
183 uint32_t addr, uint32_t size, int type)
185 PCIHypercallState *d = (PCIHypercallState *)pci_dev;
186 HypercallState *s = &d->hp;
188 register_ioport_write(addr, HYPERCALL_IOPORT_SIZE, 1, hp_ioport_write, s);
189 register_ioport_read(addr, HYPERCALL_IOPORT_SIZE, 1, hp_ioport_read, s);
194 static void hypercall_update_irq(HypercallState *s)
196 /* PCI irq */
197 qemu_set_irq(s->pci_dev->irq[0], !(s->hcr & HCR_DI));
200 static void hc_save(QEMUFile* f,void* opaque)
202 HypercallState* s=(HypercallState*)opaque;
204 pci_device_save(s->pci_dev, f);
206 qemu_put_be32s(f, &s->hcr);
207 qemu_put_be32s(f, &s->hsr);
208 qemu_put_be32s(f, &s->txsize);
209 qemu_put_be32s(f, &s->txbuff);
210 qemu_put_be32s(f, &s->rxsize);
211 qemu_put_buffer(f, s->RxBuff, HP_MEM_SIZE);
212 qemu_put_buffer(f, s->txbufferaccu, HP_MEM_SIZE);
213 qemu_put_be32s(f, &s->txbufferaccu_offset);
214 qemu_put_be32s(f, &s->irq);
215 qemu_put_be32s(f, &s->index);
219 static int hc_load(QEMUFile* f,void* opaque,int version_id)
221 HypercallState* s=(HypercallState*)opaque;
222 int ret;
224 if (version_id != 1)
225 return -EINVAL;
227 ret = pci_device_load(s->pci_dev, f);
228 if (ret < 0)
229 return ret;
231 qemu_get_be32s(f, &s->hcr);
232 qemu_get_be32s(f, &s->hsr);
233 qemu_get_be32s(f, &s->txsize);
234 qemu_get_be32s(f, &s->txbuff);
235 qemu_get_be32s(f, &s->rxsize);
236 qemu_get_buffer(f, s->RxBuff, HP_MEM_SIZE);
237 qemu_get_buffer(f, s->txbufferaccu, HP_MEM_SIZE);
238 qemu_get_be32s(f, &s->txbufferaccu_offset);
239 qemu_get_be32s(f, &s->irq);
240 qemu_get_be32s(f, &s->index);
242 return 0;
245 static void pci_hypercall_single_init(PCIBus *bus, uint32_t deviceid, uint32_t index)
247 PCIHypercallState *d;
248 HypercallState *s;
249 uint8_t *pci_conf;
250 char name[sizeof("HypercallX")];
252 sprintf(name, "Hypercall%d", index);
254 #ifdef HYPERCALL_DEBUG
255 printf("%s, devicename:%s\n", __FUNCTION__, name);
256 #endif
258 // If the vmchannel wasn't initialized, we don't want the Hypercall device in the guest
259 if (use_hypercall_dev == 0) {
260 return;
263 d = (PCIHypercallState *)pci_register_device(bus,
264 name, sizeof(PCIHypercallState),
266 NULL, NULL);
268 pci_conf = d->dev.config;
269 pci_conf[0x00] = 0x02; // Qumranet vendor ID 0x5002
270 pci_conf[0x01] = 0x50;
271 pci_conf[0x02] = deviceid & 0x00ff;
272 pci_conf[0x03] = (deviceid & 0xff00) >> 8;
274 pci_conf[0x09] = 0x00; // ProgIf
275 pci_conf[0x0a] = 0x00; // SubClass
276 pci_conf[0x0b] = 0x05; // BaseClass
278 pci_conf[0x0e] = 0x00; // header_type
279 pci_conf[0x3d] = 1; // interrupt pin 0
281 pci_register_io_region(&d->dev, 0, HYPERCALL_IOPORT_SIZE,
282 PCI_ADDRESS_SPACE_IO, hp_map);
283 s = &d->hp;
284 pHypercallStates[index] = s;
285 s->index = index;
286 s->irq = 16; /* PCI interrupt */
287 s->pci_dev = (PCIDevice *)d;
289 hp_reset(s);
290 register_savevm(name, index, 1, hc_save, hc_load, s);
293 void pci_hypercall_init(PCIBus *bus)
295 int i;
297 // loop devices & call pci_hypercall_single_init with device id's
298 for(i = 0; i < MAX_VMCHANNEL_DEVICES; i++){
299 if (vmchannel_hds[i].vmchannel_hd) {
300 pci_hypercall_single_init(bus, vmchannel_hds[i].deviceid, i);
305 static int vmchannel_can_read(void *opaque)
307 return 128;
310 static void vmchannel_event(void *opaque, int event)
313 #ifdef HYPERCALL_DEBUG
314 // if index is to be used outside the printf, take it out of the #ifdef block!
315 long index = (long)opaque;
316 printf("%s index:%ld, got event %i\n", __FUNCTION__, index, event);
317 #endif
319 return;
322 // input from vmchannel outside caller
323 static void vmchannel_read(void *opaque, const uint8_t *buf, int size)
325 int i;
326 long index = (long)opaque;
328 #ifdef HYPERCALL_DEBUG
329 printf("vmchannel_read buf size:%d\n", size);
330 #endif
332 // if the hypercall device is in interrupts disabled state, don't accept the data
333 if (pHypercallStates[index]->hcr & HCR_DI) {
334 return;
337 for(i = 0; i < size; i++) {
338 pHypercallStates[index]->RxBuff[i] = buf[i];
340 pHypercallStates[index]->rxsize = size;
341 pHypercallStates[index]->hsr = HSR_VDR;
342 hypercall_update_irq(pHypercallStates[index]);
345 void vmchannel_init(CharDriverState *hd, uint32_t deviceid, uint32_t index)
347 #ifdef HYPERCALL_DEBUG
348 printf("vmchannel_init, index=%d, deviceid=0x%x\n", index, deviceid);
349 #endif
351 vmchannel_hds[index].deviceid = deviceid;
352 vmchannel_hds[index].vmchannel_hd = hd;
354 use_hypercall_dev = 1;
355 qemu_chr_add_handlers(vmchannel_hds[index].vmchannel_hd, vmchannel_can_read, vmchannel_read,
356 vmchannel_event, (void *)(long)index);