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 #define HYPERCALL_IOPORT_SIZE 0x100
31 static int use_hypercall_dev
= 0;
33 typedef struct VmChannelCharDriverState
{
34 CharDriverState
*vmchannel_hd
;
36 } VmChannelCharDriverState
;
38 static VmChannelCharDriverState vmchannel_hds
[MAX_VMCHANNEL_DEVICES
];
40 typedef struct HypercallState
{
46 uint8_t RxBuff
[HP_MEM_SIZE
];
47 uint8_t txbufferaccu
[HP_MEM_SIZE
];
48 int txbufferaccu_offset
;
54 static HypercallState
*pHypercallStates
[MAX_VMCHANNEL_DEVICES
] = {NULL
};
56 //#define HYPERCALL_DEBUG 1
58 static void hp_reset(HypercallState
*s
)
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
);
86 hypercall_update_irq(s
);
95 // handle the case when the we are being called when txsize is not 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");
103 s
->txbufferaccu_offset
= 0;
109 if (s
->txsize
== 0) {
110 printf("error with txbuff!!!\n");
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;
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
;
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
);
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
);
168 #ifdef HYPERCALL_DEBUG
169 printf(" val=%x\n", ret
);
174 /***********************************************************/
175 /* PCI Hypercall definitions */
177 typedef struct 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
)
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
;
227 ret
= pci_device_load(s
->pci_dev
, f
);
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
);
245 static void pci_hypercall_single_init(PCIBus
*bus
, uint32_t deviceid
, uint32_t index
)
247 PCIHypercallState
*d
;
250 char name
[sizeof("HypercallX")];
252 sprintf(name
, "Hypercall%d", index
);
254 #ifdef HYPERCALL_DEBUG
255 printf("%s, devicename:%s\n", __FUNCTION__
, name
);
258 // If the vmchannel wasn't initialized, we don't want the Hypercall device in the guest
259 if (use_hypercall_dev
== 0) {
263 d
= (PCIHypercallState
*)pci_register_device(bus
,
264 name
, sizeof(PCIHypercallState
),
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
);
284 pHypercallStates
[index
] = s
;
286 s
->irq
= 16; /* PCI interrupt */
287 s
->pci_dev
= (PCIDevice
*)d
;
290 register_savevm(name
, index
, 1, hc_save
, hc_load
, s
);
293 void pci_hypercall_init(PCIBus
*bus
)
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
)
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
);
322 // input from vmchannel outside caller
323 static void vmchannel_read(void *opaque
, const uint8_t *buf
, int size
)
326 long index
= (long)opaque
;
328 #ifdef HYPERCALL_DEBUG
329 printf("vmchannel_read buf size:%d\n", size
);
332 // if the hypercall device is in interrupts disabled state, don't accept the data
333 if (pHypercallStates
[index
]->hcr
& HCR_DI
) {
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
);
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
);