Branch data Line data Source code
1 : : #include <linux/init.h>
2 : : #include <linux/module.h>
3 : : #include <linux/kernel.h>
4 : : #include <linux/fs.h>
5 : : #include <linux/ioport.h>
6 : : #include <linux/pci.h>
7 : : #include <linux/delay.h>
8 : :
9 : : MODULE_LICENSE("GPL");
10 : : MODULE_AUTHOR("Zekun Shen");
11 : : MODULE_DESCRIPTION("A command channel between linux guest and qemu host");
12 : : MODULE_VERSION("0.01");
13 : :
14 : : #define qemu_driver_name "Qemu driver"
15 : :
16 : : static int device_open_count = 0;
17 : : static int major_num;
18 : : #define CMD_ADDR 0x8
19 : : #define CMD_ARG1 0x10
20 : : #define CMD_ARG2 0x18
21 : : #define CMD_ARG3 0x20
22 : : #define ACT 0x1
23 : : #define READY_ADDR 0x30
24 : :
25 : : #define INFO_START 0x40
26 : :
27 : : /* shared */
28 : : enum ACTIONS {
29 : : CONST_DMA_INIT = 1,
30 : : CONST_DMA_EXIT,
31 : : STREAM_DMA_INIT,
32 : : STREAM_DMA_EXIT,
33 : : EXEC_INIT,
34 : : EXEC_EXIT,
35 : : SUBMIT_STAGE,
36 : : SUBMIT_KCOV_TRACE,
37 : : KASAN,
38 : : REQ_RESET,
39 : : EXEC_TIMEOUT,
40 : : PROBE_FAIL,
41 : : };
42 : :
43 : : struct qemu_adapter {
44 : : void* hw_addr;
45 : : struct pci_dev *pdev;
46 : : };
47 : :
48 : : static struct qemu_adapter *adapter = NULL;
49 : :
50 : : /* Handler */
51 : 222 : void handle_const_dma_init(uint64_t dma_addr, uint64_t addr, uint64_t size) {
52 [ + + ]: 222 : if (adapter) {
53 : : //printk(KERN_INFO "Get dma_init\n");
54 : 66 : writeq(CONST_DMA_INIT, adapter->hw_addr + CMD_ADDR);
55 : 66 : writeq(dma_addr, adapter->hw_addr + CMD_ARG1);
56 : 66 : writeq(addr, adapter->hw_addr + CMD_ARG2);
57 : 66 : writeq(size, adapter->hw_addr + CMD_ARG3);
58 : 66 : writeq(ACT, adapter->hw_addr);
59 : : }
60 : : else {
61 : : //printk(KERN_INFO "Get dma_init: adapter not ready\n");
62 : 222 : }
63 : 222 : }
64 : : EXPORT_SYMBOL(handle_const_dma_init);
65 : :
66 : 0 : void handle_const_dma_exit(uint64_t dma_addr) {
67 [ # # ]: 0 : if (adapter) {
68 : : // printk(KERN_INFO "Get dma_exit\n");
69 : 0 : writeq(CONST_DMA_EXIT, adapter->hw_addr + CMD_ADDR);
70 : 0 : writeq(dma_addr, adapter->hw_addr + CMD_ARG1);
71 : 0 : writeq(ACT, adapter->hw_addr);
72 : : }
73 : 0 : }
74 : : EXPORT_SYMBOL(handle_const_dma_exit);
75 : 0 : void handle_stream_dma_init(uint64_t dma_addr, uint64_t addr, uint64_t size) {
76 [ # # ]: 0 : if (adapter) {
77 : : //printk(KERN_INFO "Get dma_init\n");
78 : 0 : writeq(STREAM_DMA_INIT, adapter->hw_addr + CMD_ADDR);
79 : 0 : writeq(dma_addr, adapter->hw_addr + CMD_ARG1);
80 : 0 : writeq(addr, adapter->hw_addr + CMD_ARG2);
81 : 0 : writeq(size, adapter->hw_addr + CMD_ARG3);
82 : 0 : writeq(ACT, adapter->hw_addr);
83 : : }
84 : : else {
85 : : //printk(KERN_INFO "Get dma_init: adapter not ready\n");
86 : 0 : }
87 : 0 : }
88 : : EXPORT_SYMBOL(handle_stream_dma_init);
89 : :
90 : 0 : void handle_stream_dma_exit(uint64_t dma_addr) {
91 [ # # ]: 0 : if (adapter) {
92 : : // printk(KERN_INFO "Get dma_exit\n");
93 : 0 : writeq(STREAM_DMA_EXIT, adapter->hw_addr + CMD_ADDR);
94 : 0 : writeq(dma_addr, adapter->hw_addr + CMD_ARG1);
95 : 0 : writeq(ACT, adapter->hw_addr);
96 : : }
97 : 0 : }
98 : : EXPORT_SYMBOL(handle_stream_dma_exit);
99 : :
100 : 78 : static void handle_exec_init(void) {
101 : 78 : printk(KERN_INFO "[GUEST_KERNEL] handle_exec_init\n");
102 [ + - ]: 78 : if (adapter) {
103 : 78 : writeq(EXEC_INIT, adapter->hw_addr + CMD_ADDR);
104 : 78 : writeq(ACT, adapter->hw_addr);
105 : 78 : writeq(ACT, adapter->hw_addr + READY_ADDR);
106 : : }
107 : 78 : }
108 : 0 : static void handle_exec_exit(void) {
109 : 0 : if (adapter) {
110 : 0 : writeq(EXEC_EXIT, adapter->hw_addr + CMD_ADDR);
111 : 0 : writeq(ACT, adapter->hw_addr);
112 : : }
113 : : }
114 : 0 : static void handle_exec_timeout(void) {
115 : 0 : if (adapter) {
116 : 0 : writeq(EXEC_TIMEOUT, adapter->hw_addr + CMD_ADDR);
117 : 0 : writeq(ACT, adapter->hw_addr);
118 : : }
119 : : }
120 : 0 : static void handle_submit_stage(uint64_t stage) {
121 : 0 : if (adapter) {
122 : 0 : writeq(SUBMIT_STAGE, adapter->hw_addr + CMD_ADDR);
123 : 0 : writeq(stage, adapter->hw_addr + CMD_ARG1);
124 : 0 : writeq(ACT, adapter->hw_addr);
125 : : }
126 : : }
127 : 1248 : void handle_submit_kcov_trace(uint64_t address, uint64_t size) {
128 [ + - ]: 1248 : if (adapter) {
129 : 1248 : writeq(SUBMIT_KCOV_TRACE, adapter->hw_addr + CMD_ADDR);
130 [ + - ]: 1248 : writeq(virt_to_phys(address), adapter->hw_addr + CMD_ARG1);
131 : 1248 : writeq(size, adapter->hw_addr + CMD_ARG2);
132 : 1248 : writeq(ACT, adapter->hw_addr);
133 : : }
134 : 1248 : }
135 : : EXPORT_SYMBOL(handle_submit_kcov_trace);
136 : :
137 : 0 : void handle_kasan(void) {
138 : 0 : printk(KERN_INFO "handle_kasan\n");
139 [ # # ]: 0 : if (adapter) {
140 : 0 : writeq(KASAN, adapter->hw_addr + CMD_ADDR);
141 : 0 : writeq(ACT, adapter->hw_addr);
142 : : }
143 : 0 : }
144 : : EXPORT_SYMBOL(handle_kasan);
145 : :
146 : 0 : void handle_req_reset(void) {
147 : 0 : printk(KERN_INFO "handle_reset\n");
148 [ # # ]: 0 : if (adapter) {
149 : 0 : writeq(REQ_RESET, adapter->hw_addr + CMD_ADDR);
150 : 0 : writeq(ACT, adapter->hw_addr);
151 : : }
152 : 0 : }
153 : :
154 : 201 : void probe_fail(void) {
155 : 201 : printk(KERN_INFO "probe_fail\n");
156 [ + + ]: 201 : if (adapter) {
157 : 45 : writeq(PROBE_FAIL, adapter->hw_addr + CMD_ADDR);
158 : 45 : writeq(ACT, adapter->hw_addr);
159 : : }
160 : 201 : }
161 : : EXPORT_SYMBOL(probe_fail);
162 : :
163 : 78 : static int handle_command(void* buffer, size_t len) {
164 : 78 : uint64_t *pbuffer;
165 : 78 : uint64_t cmd;
166 : 78 : uint64_t *argv;
167 : 78 : int argc;
168 : 78 : size_t nread = 0;
169 : 78 : pbuffer = (uint64_t *)buffer;
170 [ + - + - ]: 78 : if (len == 0 || len % 8) {
171 : : return -EINVAL;
172 : : }
173 : :
174 : 78 : cmd = *pbuffer;
175 : 78 : nread += 8;
176 : 78 : argv = pbuffer + 1;
177 : 78 : argc = (len - 8) / 8;
178 [ - - - - : 78 : switch (cmd)
+ - - - -
- - ]
179 : : {
180 : 0 : case CONST_DMA_INIT:
181 [ # # ]: 0 : WARN_ON(len != 0x20);
182 : 0 : handle_const_dma_init(argv[0], argv[1], argv[2]);
183 : 0 : return 0x20;
184 : 0 : case CONST_DMA_EXIT:
185 [ # # ]: 0 : WARN_ON(len != 0x10);
186 [ # # ]: 0 : handle_const_dma_exit(argv[0]);
187 : : return 0x10;
188 : 0 : case STREAM_DMA_INIT:
189 [ # # ]: 0 : WARN_ON(len != 0x20);
190 : 0 : handle_stream_dma_init(argv[0], argv[1], argv[2]);
191 : 0 : return 0x20;
192 : 0 : case STREAM_DMA_EXIT:
193 [ # # ]: 0 : WARN_ON(len != 0x10);
194 [ # # ]: 0 : handle_stream_dma_exit(argv[0]);
195 : : return 0x10;
196 : 78 : case EXEC_INIT:
197 [ - + ]: 78 : WARN_ON(len!= 0x8);
198 : 78 : handle_exec_init();
199 : 78 : return 0x8;
200 : 0 : case EXEC_EXIT:
201 [ # # ]: 0 : WARN_ON(len!= 0x8);
202 [ # # ]: 0 : handle_exec_exit();
203 : : return 0x8;
204 : 0 : case SUBMIT_STAGE:
205 [ # # ]: 0 : WARN_ON(len!= 0x10);
206 [ # # ]: 0 : handle_submit_stage(argv[0]);
207 : : return 0x10;
208 : 0 : case SUBMIT_KCOV_TRACE:
209 [ # # ]: 0 : WARN_ON(len!= 0x18);
210 : 0 : handle_submit_kcov_trace(argv[0], argv[1]);
211 : 0 : return 0x18;
212 : 0 : case REQ_RESET:
213 [ # # ]: 0 : WARN_ON(len != 0x8);
214 : 0 : handle_req_reset();
215 : 0 : return 0x8;
216 : 0 : case EXEC_TIMEOUT:
217 [ # # ]: 0 : WARN_ON(len != 0x8);
218 [ # # ]: 0 : handle_exec_timeout();
219 : : return 0x8;
220 : 0 : default:
221 : 0 : printk(KERN_INFO "Unknow action\n");
222 : 0 : return 0x4;
223 : : }
224 : : return 0;
225 : : }
226 : :
227 : : /* File ops */
228 : 78 : static ssize_t device_write(struct file *flip, const char *buffer, size_t len,
229 : : loff_t *offset) {
230 : : //uint64_t *p = (uint64_t*) buffer;
231 : 78 : *offset = 0;
232 : 78 : int num = 0;
233 [ - + ]: 78 : void *kbuf = kmalloc(len, GFP_KERNEL);
234 [ - + + - ]: 156 : if (copy_from_user(kbuf, buffer, len)) {
235 : : return -EIO;
236 : : }
237 [ + - ]: 78 : if ((num = handle_command(kbuf, len)) == 0) {
238 : : return -EINVAL;
239 : : }
240 : 78 : return num;
241 : :
242 : : }
243 : :
244 : 312 : static ssize_t device_read(struct file *flip, char *buffer, size_t len,
245 : : loff_t *offset) {
246 : 312 : size_t off;
247 [ - + ]: 312 : void *kbuf = kmalloc(len, GFP_KERNEL);
248 [ + - ]: 312 : if (!adapter)
249 : : return -EINVAL;
250 [ + + ]: 2496 : for (off = 0; off < len; off++) {
251 : 2184 : *(char*)(kbuf + off) = readb(adapter->hw_addr + INFO_START + *offset + off);
252 : : }
253 [ - + + - ]: 624 : if (copy_to_user(buffer, kbuf, len)) {
254 : : return -EIO;
255 : : }
256 : 312 : *offset += len;
257 : 312 : return len;
258 : : }
259 : :
260 : 156 : static int device_open(struct inode *inode, struct file *file) {
261 [ + - ]: 156 : if (device_open_count) {
262 : : return -EBUSY;
263 : : }
264 : 156 : device_open_count++;
265 : 156 : try_module_get(THIS_MODULE);
266 : 156 : return 0;
267 : : }
268 : :
269 : 156 : static int device_release(struct inode *inode, struct file *file) {
270 : 156 : device_open_count--;
271 : 156 : module_put(THIS_MODULE);
272 : 156 : return 0;
273 : : }
274 : :
275 : : static struct file_operations file_ops = {
276 : : .read = device_read,
277 : : .write = device_write,
278 : : .open = device_open,
279 : : .release = device_release
280 : : };
281 : :
282 : : /* File ops end */
283 : :
284 : : /* PCI */
285 : 78 : static int qemu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) {
286 : 78 : printk(KERN_INFO "Qemu probe\n Hello!\n");
287 : 78 : int err;
288 : : // int bars;
289 : : //bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
290 [ + - ]: 78 : if ((err = pci_enable_device(pdev)))
291 : : return err;
292 : :
293 : : // if ((err = pci_request_selected_regions(pdev, bars, qemu_driver_name)))
294 : : // goto somewhere1;
295 : :
296 : : // pci_set_master(pdev);
297 : : // if ((err = pci_save_state(pdev))) {
298 : : // goto somewhere2;
299 : : // }
300 : 78 : adapter = kmalloc(sizeof(struct qemu_adapter), GFP_KERNEL);
301 : 78 : adapter->pdev = pdev;
302 : 78 : adapter->hw_addr = pci_ioremap_bar(pdev, 0);
303 : 78 : pci_set_drvdata(pdev, adapter);
304 : :
305 : : // Test code for dma
306 : : /*
307 : : dma_addr_t dma_handle;
308 : : void *const_dma_region;
309 : : void *stream_dma_region;
310 : : const_dma_region =
311 : : dma_alloc_coherent(&pdev->dev, 0x1000, &dma_handle, GFP_KERNEL);
312 : :
313 : : *(char*)const_dma_region = 'A';
314 : : *((char*)const_dma_region + 0x111) = 'A';
315 : : dma_free_coherent(&pdev->dev, 0x1000, const_dma_region, dma_handle);
316 : :
317 : :
318 : : stream_dma_region = kmalloc(0x101, GFP_KERNEL);
319 : : *((char*)stream_dma_region + 0x100) = '\x00';
320 : : dma_handle = dma_map_single(&pdev->dev, stream_dma_region, 0x100, DMA_FROM_DEVICE);
321 : :
322 : : if (dma_mapping_error(&pdev->dev, dma_handle)) {
323 : : pr_info("dma_map_single() failed\n");
324 : : } else {
325 : : pr_info("dma_map_single() succeeded");
326 : : }
327 : : dma_unmap_single(&pdev->dev, dma_handle, 0x100, DMA_FROM_DEVICE);
328 : : // udelay(100);
329 : : printk(KERN_INFO "stream dma data: %s\n", (char*)stream_dma_region);
330 : : kfree(stream_dma_region);
331 : : */
332 : 78 : return 0;
333 : : }
334 : :
335 : 0 : static void qemu_remove(struct pci_dev *pdev) {
336 : : //pci_release_selected_regions(pdev, bars);
337 : 0 : kfree(pci_get_drvdata(pdev));
338 : 0 : pci_disable_device(pdev);
339 : 0 : }
340 : :
341 : : static const struct pci_device_id qemu_pci_tbl[] = {
342 : : {PCI_DEVICE(0x7777, 0x7777)},
343 : : {}
344 : : };
345 : : static struct pci_driver qemu_driver = {
346 : : .name = qemu_driver_name,
347 : : .id_table = qemu_pci_tbl,
348 : : .probe = qemu_probe,
349 : : .remove = qemu_remove,
350 : : };
351 : :
352 : : /* PCI ends */
353 : :
354 : : /* Module */
355 : 78 : int __init qemu_init_module(void) {
356 : 78 : int ret;
357 : 78 : printk(KERN_INFO "Qemu init\n Hello!\n");
358 [ - + ]: 78 : if ((ret = pci_register_driver(&qemu_driver)) != 0) {
359 : 0 : printk(KERN_ALERT "Could not register pci: %d\b", ret);
360 : 0 : return ret;
361 : : }
362 : 78 : major_num = register_chrdev(0, qemu_driver_name, &file_ops);
363 [ - + ]: 78 : if (major_num < 0) {
364 : 0 : printk(KERN_ALERT "Could not register device: %d\n", major_num);
365 : 0 : return major_num;
366 : : } else {
367 : 78 : printk(KERN_INFO "Qemu module loaded with major %d\n", major_num);
368 : 78 : return 0;
369 : : }
370 : : }
371 : : module_init(qemu_init_module);
372 : :
373 : 0 : void __exit qemu_exit_module(void) {
374 : 0 : unregister_chrdev(major_num, qemu_driver_name);
375 : 0 : printk(KERN_INFO "Qemu exit\n Goodbye!\n");
376 : 0 : }
377 : :
378 : : module_exit(qemu_exit_module);
379 : : /* Module ends */
|