Adjust qemu_addr_chr call for the 0.9 qemu version.
[qemu-kvm/fedora.git] / hw / hypercall.c
blob946d99ff0935bbfb37aaa32bc4d881477c47b92c
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 int use_hypercall_dev = 0;
30 static CharDriverState *vmchannel_hd;
32 typedef struct HypercallState {
33 uint32_t hcr;
34 uint32_t hsr;
35 uint32_t txsize;
36 uint32_t txbuff;
37 uint32_t rxsize;
38 uint8_t RxBuff[HP_MEM_SIZE];
39 uint8_t txbufferaccu[HP_MEM_SIZE];
40 int txbufferaccu_offset;
41 int irq;
42 PCIDevice *pci_dev;
43 } HypercallState;
45 HypercallState *pHypercallState = NULL;
48 //#define HYPERCALL_DEBUG 1
50 static void hp_reset(HypercallState *s)
52 s->hcr = 0;
53 s->hsr = 0;
54 s->txsize = 0;
55 s->txbuff = 0;
56 s->rxsize= 0;
57 s->txbufferaccu_offset = 0;
60 static void hypercall_update_irq(HypercallState *s);
63 static void hp_ioport_write(void *opaque, uint32_t addr, uint32_t val)
65 HypercallState *s = opaque;
67 #ifdef HYPERCALL_DEBUG
68 printf("%s: addr=0x%x, val=0x%x\n", __FUNCTION__, addr, val);
69 #endif
70 addr &= 0xff;
72 switch(addr)
74 case HCR_REGISTER:
76 s->hcr = val;
77 if (s->hcr & HCR_DI)
78 hypercall_update_irq(s);
79 if (val & HCR_GRS){
80 hp_reset(s);
82 break;
85 case HP_TXSIZE:
87 // handle the case when the we are being called when txsize is not 0
88 if (s->txsize != 0) {
89 printf("txsize is being set, but txsize is not 0!!!\n");
91 if (val > HP_MEM_SIZE) {
92 printf("txsize is larger than allowed by hw!!!\n");
94 s->txsize = val;
95 s->txbufferaccu_offset = 0;
96 break;
99 case HP_TXBUFF:
101 if (s->txsize == 0) {
102 printf("error with txbuff!!!\n");
103 break;
106 s->txbufferaccu[s->txbufferaccu_offset] = val;
107 s->txbufferaccu_offset++;
108 if (s->txbufferaccu_offset >= s->txsize) {
109 qemu_chr_write(vmchannel_hd, s->txbufferaccu, s->txsize);
110 s->txbufferaccu_offset = 0;
111 s->txsize = 0;
113 break;
115 default:
117 printf("hp_ioport_write to unhandled address!!!\n");
122 static uint32_t hp_ioport_read(void *opaque, uint32_t addr)
124 HypercallState *s = opaque;
125 int ret;
127 #ifdef HYPERCALL_DEBUG
128 printf("%s: addr=0x%x\n", __FUNCTION__, addr);
129 #endif
130 addr &= 0xff;
132 if (addr >= offsetof(HypercallState, RxBuff) )
134 int RxBuffOffset = addr - (offsetof(HypercallState, RxBuff));
135 ret = s->RxBuff[RxBuffOffset];
136 return ret;
139 switch (addr)
141 case HSR_REGISTER:
142 ret = s->hsr;
143 if (ret & HSR_VDR) {
144 s->hsr &= ~HSR_VDR;
146 break;
147 case HP_RXSIZE:
148 ret = s->rxsize;
149 break;
151 default:
152 ret = 0x00;
153 break;
156 return ret;
159 /***********************************************************/
160 /* PCI Hypercall definitions */
162 typedef struct PCIHypercallState {
163 PCIDevice dev;
164 HypercallState hp;
165 } PCIHypercallState;
167 static void hp_map(PCIDevice *pci_dev, int region_num,
168 uint32_t addr, uint32_t size, int type)
170 PCIHypercallState *d = (PCIHypercallState *)pci_dev;
171 HypercallState *s = &d->hp;
173 register_ioport_write(addr, 0x100, 1, hp_ioport_write, s);
174 register_ioport_read(addr, 0x100, 1, hp_ioport_read, s);
179 static void hypercall_update_irq(HypercallState *s)
181 /* PCI irq */
182 pci_set_irq(s->pci_dev, 0, !(s->hcr & HCR_DI));
185 void pci_hypercall_init(PCIBus *bus)
187 PCIHypercallState *d;
188 HypercallState *s;
189 uint8_t *pci_conf;
191 // If the vmchannel wasn't initialized, we don't want the Hypercall device in the guest
192 if (use_hypercall_dev == 0) {
193 return;
196 d = (PCIHypercallState *)pci_register_device(bus,
197 "Hypercall", sizeof(PCIHypercallState),
199 NULL, NULL);
201 pci_conf = d->dev.config;
202 pci_conf[0x00] = 0x02; // Qumranet vendor ID 0x5002
203 pci_conf[0x01] = 0x50;
204 pci_conf[0x02] = 0x58; // Qumranet DeviceID 0x2258
205 pci_conf[0x03] = 0x22;
207 pci_conf[0x09] = 0x00; // ProgIf
208 pci_conf[0x0a] = 0x00; // SubClass
209 pci_conf[0x0b] = 0x05; // BaseClass
211 pci_conf[0x0e] = 0x00; // header_type
212 pci_conf[0x3d] = 1; // interrupt pin 0
214 pci_register_io_region(&d->dev, 0, 0x100,
215 PCI_ADDRESS_SPACE_IO, hp_map);
216 s = &d->hp;
217 pHypercallState = s;
218 s->irq = 16; /* PCI interrupt */
219 s->pci_dev = (PCIDevice *)d;
221 hp_reset(s);
225 static int vmchannel_can_read(void *opaque)
227 return 128;
230 static void vmchannel_event(void *opaque, int event)
232 PCIHypercallState *s = opaque;
233 #ifdef HYPERCALL_DEBUG
234 printf("%s got event %d\n", __FUNCTION__, event);
235 #endif
236 return;
239 // input from vmchannel outside caller
240 static void vmchannel_read(void *opaque, const uint8_t *buf, int size)
242 int i;
244 #ifdef HYPERCALL_DEBUG
245 printf("vmchannel_read buf:%s, size:%d\n", buf, size);
246 #endif
248 // if the hypercall device is in interrupts disabled state, don't accept the data
249 if (pHypercallState->hcr & HCR_DI) {
250 return;
253 for(i = 0; i < size; i++) {
254 pHypercallState->RxBuff[i] = buf[i];
256 pHypercallState->rxsize = size;
257 pHypercallState->hsr = HSR_VDR;
258 hypercall_update_irq(pHypercallState);
261 void vmchannel_init(CharDriverState *hd)
263 vmchannel_hd = hd;
265 #ifdef HYPERCALL_DEBUG
266 printf("vmchannel_init\n");
267 #endif
268 use_hypercall_dev = 1;
269 qemu_chr_add_handlers(vmchannel_hd, vmchannel_can_read, vmchannel_read,
270 vmchannel_event, &pHypercallState);