2 * QEMU-KVM Hypercall emulation
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 * Copyright (c) 2006 Qumranet
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
26 #include "hypercall.h"
29 int use_hypercall_dev
= 0;
30 static CharDriverState
*vmchannel_hd
;
32 typedef struct HypercallState
{
38 uint8_t RxBuff
[HP_MEM_SIZE
];
39 uint8_t txbufferaccu
[HP_MEM_SIZE
];
40 int txbufferaccu_offset
;
45 HypercallState
*pHypercallState
= NULL
;
48 //#define HYPERCALL_DEBUG 1
50 static void hp_reset(HypercallState
*s
)
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
);
78 hypercall_update_irq(s
);
87 // handle the case when the we are being called when txsize is not 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");
95 s
->txbufferaccu_offset
= 0;
101 if (s
->txsize
== 0) {
102 printf("error with txbuff!!!\n");
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;
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
;
127 #ifdef HYPERCALL_DEBUG
128 printf("%s: addr=0x%x\n", __FUNCTION__
, addr
);
132 if (addr
>= offsetof(HypercallState
, RxBuff
) )
134 int RxBuffOffset
= addr
- (offsetof(HypercallState
, RxBuff
));
135 ret
= s
->RxBuff
[RxBuffOffset
];
159 /***********************************************************/
160 /* PCI Hypercall definitions */
162 typedef struct 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
)
182 pci_set_irq(s
->pci_dev
, 0, !(s
->hcr
& HCR_DI
));
185 void pci_hypercall_init(PCIBus
*bus
)
187 PCIHypercallState
*d
;
191 // If the vmchannel wasn't initialized, we don't want the Hypercall device in the guest
192 if (use_hypercall_dev
== 0) {
196 d
= (PCIHypercallState
*)pci_register_device(bus
,
197 "Hypercall", sizeof(PCIHypercallState
),
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
);
218 s
->irq
= 16; /* PCI interrupt */
219 s
->pci_dev
= (PCIDevice
*)d
;
225 static int vmchannel_can_read(void *opaque
)
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
);
239 // input from vmchannel outside caller
240 static void vmchannel_read(void *opaque
, const uint8_t *buf
, int size
)
244 #ifdef HYPERCALL_DEBUG
245 printf("vmchannel_read buf:%s, size:%d\n", buf
, size
);
248 // if the hypercall device is in interrupts disabled state, don't accept the data
249 if (pHypercallState
->hcr
& HCR_DI
) {
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
)
265 #ifdef HYPERCALL_DEBUG
266 printf("vmchannel_init\n");
268 use_hypercall_dev
= 1;
269 qemu_chr_add_handlers(vmchannel_hd
, vmchannel_can_read
, vmchannel_read
,
270 vmchannel_event
, &pHypercallState
);