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
27 #include "qemu-char.h"
31 #include "hypercall.h"
34 #define HYPERCALL_IOPORT_SIZE 0x100
36 static int use_hypercall_dev
= 0;
38 typedef struct VmChannelCharDriverState
{
39 CharDriverState
*vmchannel_hd
;
41 } VmChannelCharDriverState
;
43 static VmChannelCharDriverState vmchannel_hds
[MAX_VMCHANNEL_DEVICES
];
45 typedef struct HypercallState
{
51 uint8_t RxBuff
[HP_MEM_SIZE
];
52 uint8_t txbufferaccu
[HP_MEM_SIZE
];
53 int txbufferaccu_offset
;
59 static HypercallState
*pHypercallStates
[MAX_VMCHANNEL_DEVICES
] = {NULL
};
61 //#define HYPERCALL_DEBUG 1
63 static void hp_reset(HypercallState
*s
)
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
);
91 hypercall_update_irq(s
);
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");
108 s
->txbufferaccu_offset
= 0;
114 if (s
->txsize
== 0) {
115 printf("error with txbuff!!!\n");
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;
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
;
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
);
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
);
173 #ifdef HYPERCALL_DEBUG
174 printf(" val=%x\n", ret
);
179 /***********************************************************/
180 /* PCI Hypercall definitions */
182 typedef struct 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
)
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
;
232 ret
= pci_device_load(s
->pci_dev
, f
);
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
);
250 static void pci_hypercall_single_init(PCIBus
*bus
, uint32_t deviceid
, uint32_t index
)
252 PCIHypercallState
*d
;
255 char name
[sizeof("HypercallX")];
257 sprintf(name
, "Hypercall%d", index
);
259 #ifdef HYPERCALL_DEBUG
260 printf("%s, devicename:%s\n", __FUNCTION__
, name
);
263 // If the vmchannel wasn't initialized, we don't want the Hypercall device in the guest
264 if (use_hypercall_dev
== 0) {
268 d
= (PCIHypercallState
*)pci_register_device(bus
,
269 name
, sizeof(PCIHypercallState
),
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
);
289 pHypercallStates
[index
] = s
;
291 s
->irq
= 16; /* PCI interrupt */
292 s
->pci_dev
= (PCIDevice
*)d
;
295 register_savevm(name
, index
, 1, hc_save
, hc_load
, s
);
298 void pci_hypercall_init(PCIBus
*bus
)
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
)
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
);
327 // input from vmchannel outside caller
328 static void vmchannel_read(void *opaque
, const uint8_t *buf
, int size
)
331 long index
= (long)opaque
;
333 #ifdef HYPERCALL_DEBUG
334 printf("vmchannel_read buf size:%d\n", size
);
337 // if the hypercall device is in interrupts disabled state, don't accept the data
338 if (pHypercallStates
[index
]->hcr
& HCR_DI
) {
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
);
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
);