Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Cleanup and sanity-checking of use of strncpy/strcpy (Coverity static analysis)
[palacios.releases.git] / palacios / src / devices / generic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Peter Dinda <pdinda@northwestern.edu>
15  * Contributor: 2008, Jack Lange <jarusl@cs.northwestern.edu>
16  *        
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22 #include <palacios/vmm.h>
23 #include <palacios/vmm_types.h>
24 #include <palacios/vmm_list.h>
25 #include <palacios/vmm_io.h>
26 #include <palacios/vmm_dev_mgr.h>
27 #include <palacios/vm_guest_mem.h>
28
29 #ifdef V3_CONFIG_HOST_DEVICE
30 #include <interfaces/vmm_host_dev.h>
31 #endif
32
33 #ifndef V3_CONFIG_DEBUG_GENERIC
34 #undef PrintDebug
35 #define PrintDebug(fmt, args...)
36 #endif
37
38 #define MAX_NAME      32
39 #define MAX_MEM_HOOKS 16
40
41 typedef enum {GENERIC_IGNORE, 
42               GENERIC_PASSTHROUGH, 
43               GENERIC_PRINT_AND_PASSTHROUGH, 
44               GENERIC_PRINT_AND_IGNORE} generic_mode_t;
45
46 struct generic_internal {
47     enum {GENERIC_PHYSICAL, GENERIC_HOST} forward_type;
48 #ifdef V3_CONFIG_HOST_DEVICE
49     v3_host_dev_t                         host_dev;
50 #endif
51     struct vm_device                      *dev; // me
52
53     char                                  name[MAX_NAME];
54     
55     uint32_t                              num_mem_hooks;
56     addr_t                                mem_hook[MAX_MEM_HOOKS];
57 };
58
59
60
61
62 static int generic_write_port_passthrough(struct guest_info * core, 
63                                           uint16_t port, 
64                                           void * src, 
65                                           uint_t length, 
66                                           void * priv_data) 
67 {
68     struct generic_internal *state = (struct generic_internal *) priv_data;
69     uint_t i;
70
71     switch (state->forward_type) { 
72         case GENERIC_PHYSICAL:
73             switch (length) {
74                 case 1:
75                     v3_outb(port, ((uint8_t *)src)[0]);
76                     break;
77                 case 2:
78                     v3_outw(port, ((uint16_t *)src)[0]);
79                     break;
80                 case 4:
81                     v3_outdw(port, ((uint32_t *)src)[0]);
82                     break;
83                 default:
84                     for (i = 0; i < length; i++) { 
85                         v3_outb(port, ((uint8_t *)src)[i]);
86                     }
87                     break;
88             }
89             return length;
90             break;
91 #ifdef V3_CONFIG_HOST_DEVICE
92         case GENERIC_HOST:
93             if (state->host_dev) { 
94                 return v3_host_dev_write_io(state->host_dev,port,src,length);
95             } else {
96                 return -1;
97             }
98             break;
99 #endif
100         default:
101             PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
102             return -1;
103             break;
104     }
105 }
106
107 static int generic_write_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
108                                                     uint_t length, void * priv_data) {
109     uint_t i;
110     int rc;
111
112 #ifdef V3_CONFIG_DEBUG_GENERIC
113     struct generic_internal *state = (struct generic_internal *) priv_data;
114 #endif
115
116     PrintDebug(core->vm_info, core, "generic (%s): writing 0x%x bytes to port 0x%x using %s ...", state->name,
117                length, port,
118                state->forward_type == GENERIC_PHYSICAL ? "physical" :
119                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
120
121     PrintDebug(core->vm_info, core, "generic (%s): writing 0x", state->name);
122
123     for (i = 0; i < length; i++) { 
124         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
125     }
126   
127     PrintDebug(core->vm_info, core, " to port 0x%x ... ", port);
128
129     rc=generic_write_port_passthrough(core,port,src,length,priv_data);
130
131     PrintDebug(core->vm_info, core, " done\n");
132   
133     return rc;
134 }
135
136 static int generic_read_port_passthrough(struct guest_info * core, 
137                                          uint16_t port, 
138                                          void * dst, 
139                                          uint_t length, 
140                                          void * priv_data) 
141 {
142     struct generic_internal *state = (struct generic_internal *) priv_data;
143
144     uint_t i;
145
146     switch (state->forward_type) { 
147         case GENERIC_PHYSICAL:
148             switch (length) {
149                 case 1:
150                     ((uint8_t *)dst)[0] = v3_inb(port);
151                     break;
152                 case 2:
153                     ((uint16_t *)dst)[0] = v3_inw(port);
154                     break;
155                 case 4:
156                     ((uint32_t *)dst)[0] = v3_indw(port);
157                     break;
158                 default:
159                     for (i = 0; i < length; i++) { 
160                         ((uint8_t *)dst)[i] = v3_inb(port);
161                     }
162             }
163             return length;
164             break;
165 #ifdef V3_CONFIG_HOST_DEVICE
166         case GENERIC_HOST:
167             if (state->host_dev) { 
168                 return v3_host_dev_read_io(state->host_dev,port,dst,length);
169             }
170             break;
171 #endif
172         default:
173             PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
174             return -1;
175             break;
176     }
177
178     return -1;
179 }
180
181 static int generic_read_port_print_and_passthrough(struct guest_info * core, uint16_t port, void * src, 
182                                                    uint_t length, void * priv_data) {
183     uint_t i;
184     int rc;
185
186 #ifdef V3_CONFIG_DEBUG_GENERIC
187     struct generic_internal *state = (struct generic_internal *) priv_data;
188 #endif
189
190     PrintDebug(core->vm_info, core, "generic (%s): reading 0x%x bytes from port 0x%x using %s ...", state->name, length, port,
191                state->forward_type == GENERIC_PHYSICAL ? "physical" :
192                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
193
194
195     rc=generic_read_port_passthrough(core,port,src,length,priv_data);
196
197     PrintDebug(core->vm_info, core, " done ... read 0x");
198
199     for (i = 0; i < rc; i++) { 
200         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
201     }
202
203     PrintDebug(core->vm_info, core, "\n");
204
205     return rc;
206 }
207
208
209 static int generic_read_port_ignore(struct guest_info * core, uint16_t port, void * src, 
210                                     uint_t length, void * priv_data) {
211
212     memset((uint8_t *)src, 0, length);
213
214     return length;
215 }
216
217 static int generic_read_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src, 
218                                               uint_t length, void * priv_data) {
219    
220 #ifdef V3_CONFIG_DEBUG_GENERIC
221     struct generic_internal *state = (struct generic_internal *) priv_data;
222 #endif
223
224     PrintDebug(core->vm_info, core, "generic (%s): reading 0x%x bytes from port 0x%x using %s ...", state->name, length, port,
225                state->forward_type == GENERIC_PHYSICAL ? "physical" :
226                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
227
228
229     memset((uint8_t *)src, 0, length);
230     PrintDebug(core->vm_info, core, " ignored (return zeroed buffer)\n");
231
232     return length;
233 }
234
235 static int generic_write_port_ignore(struct guest_info * core, uint16_t port, void * src, 
236                                      uint_t length, void * priv_data) {
237
238     return length;
239 }
240
241 static int generic_write_port_print_and_ignore(struct guest_info * core, uint16_t port, void * src, 
242                                               uint_t length, void * priv_data) {
243     int i;
244
245 #ifdef V3_CONFIG_DEBUG_GENERIC
246     struct generic_internal *state = (struct generic_internal *) priv_data;
247 #endif
248
249     PrintDebug(core->vm_info, core, "generic (%s): writing 0x%x bytes to port 0x%x using %s ", state->name, length, port,
250                state->forward_type == GENERIC_PHYSICAL ? "physical" :
251                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
252     
253     memset((uint8_t *)src, 0, length);
254     PrintDebug(core->vm_info, core, " ignored - data was: 0x");
255
256     for (i = 0; i < length; i++) { 
257         PrintDebug(core->vm_info, core, "%x", ((uint8_t *)src)[i]);
258     }
259     
260     PrintDebug(core->vm_info, core, "\n");
261
262     return length;
263 }
264
265
266
267 static int generic_write_mem_passthrough(struct guest_info * core, 
268                                          addr_t              gpa,
269                                          void              * src,
270                                          uint_t              len,
271                                          void              * priv)
272 {
273     struct vm_device *dev = (struct vm_device *) priv;
274     struct generic_internal *state = (struct generic_internal *) dev->private_data;
275     
276     switch (state->forward_type) { 
277         case GENERIC_PHYSICAL:
278             memcpy(V3_VAddr((void*)gpa),src,len);
279             return len;
280             break;
281 #ifdef V3_CONFIG_HOST_DEVICE
282         case GENERIC_HOST:
283             if (state->host_dev) { 
284                 return v3_host_dev_write_mem(state->host_dev,gpa,src,len);
285             } else {
286                 return -1;
287             }
288             break;
289 #endif
290         default:
291             PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
292             return -1;
293             break;
294     }
295 }
296
297 static int generic_write_mem_print_and_passthrough(struct guest_info * core, 
298                                                    addr_t              gpa,
299                                                    void              * src,
300                                                    uint_t              len,
301                                                    void              * priv)
302 {
303 #ifdef V3_CONFIG_DEBUG_GENERIC
304     struct vm_device *dev = (struct vm_device *) priv;
305     struct generic_internal *state = (struct generic_internal *) dev->private_data;
306 #endif
307
308     PrintDebug(core->vm_info, core, "generic (%s): writing %u bytes to GPA 0x%p via %s ... ", state->name,
309                len,(void*)gpa,
310                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
311                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
312     
313     int rc = generic_write_mem_passthrough(core,gpa,src,len,priv);
314
315     PrintDebug(core->vm_info, core, "done\n");
316     
317     return rc;
318 }
319
320 static int generic_write_mem_ignore(struct guest_info * core, 
321                                     addr_t              gpa,
322                                     void              * src,
323                                     uint_t              len,
324                                     void              * priv)
325 {
326     return len;
327 }
328
329 static int generic_write_mem_print_and_ignore(struct guest_info * core, 
330                                               addr_t              gpa,
331                                               void              * src,
332                                               uint_t              len,
333                                               void              * priv)
334 {
335 #ifdef V3_CONFIG_DEBUG_GENERIC
336     struct vm_device *dev = (struct vm_device *) priv;
337     struct generic_internal *state = (struct generic_internal *) dev->private_data;
338 #endif
339
340     PrintDebug(core->vm_info, core, "generic (%s): ignoring write of %u bytes to GPA 0x%p via %s", state->name,
341                len,(void*)gpa,
342                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
343                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
344     
345     return len;
346 }
347
348 static int generic_read_mem_passthrough(struct guest_info * core, 
349                                         addr_t              gpa,
350                                         void              * dst,
351                                         uint_t              len,
352                                         void              * priv)
353 {
354     struct vm_device *dev = (struct vm_device *) priv;
355     struct generic_internal *state = (struct generic_internal *) dev->private_data;
356     
357     switch (state->forward_type) { 
358         case GENERIC_PHYSICAL:
359             memcpy(dst,V3_VAddr((void*)gpa),len);
360             return len;
361             break;
362 #ifdef V3_CONFIG_HOST_DEVICE
363         case GENERIC_HOST:
364             if (state->host_dev) { 
365                 return v3_host_dev_read_mem(state->host_dev,gpa,dst,len);
366             } else {
367                 return -1;
368             }
369             break;
370 #endif
371         default:
372             PrintError(core->vm_info, core, "generic (%s): unknown forwarding type\n", state->name);
373             break;
374     }
375     
376     return -1;
377 }
378
379 static int generic_read_mem_print_and_passthrough(struct guest_info * core, 
380                                                   addr_t              gpa,
381                                                   void              * dst,
382                                                   uint_t              len,
383                                                   void              * priv)
384 {
385 #ifdef V3_CONFIG_DEBUG_GENERIC
386     struct vm_device *dev = (struct vm_device *) priv;
387     struct generic_internal *state = (struct generic_internal *) dev->private_data;
388 #endif
389
390     PrintDebug(core->vm_info, core, "generic (%s): attempting to read %u bytes from GPA 0x%p via %s ... ", state->name,
391                len,(void*)gpa,
392                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
393                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
394     
395     int rc = generic_read_mem_passthrough(core,gpa,dst,len,priv);
396
397     PrintDebug(core->vm_info, core, "done - read %d bytes\n", rc);
398     
399     return rc;
400 }
401
402 static int generic_read_mem_ignore(struct guest_info * core, 
403                                    addr_t              gpa,
404                                    void              * dst,
405                                    uint_t              len,
406                                    void              * priv)
407 {
408 #ifdef V3_CONFIG_DEBUG_GENERIC
409     struct vm_device *dev = (struct vm_device *) priv;
410     struct generic_internal *state = (struct generic_internal *) dev->private_data;
411 #endif
412
413     PrintDebug(core->vm_info, core, "generic (%s): ignoring attempt to read %u bytes from GPA 0x%p via %s ... ", state->name,
414                len,(void*)gpa,
415                state->forward_type == GENERIC_PHYSICAL ? "physical" : 
416                state->forward_type == GENERIC_HOST ? "host" : "UNKNOWN");
417
418     memset((uint8_t *)dst, 0, len);
419
420     PrintDebug(core->vm_info, core, "returning zeros\n");
421
422     return len;
423 }
424
425
426 static int generic_read_mem_print_and_ignore(struct guest_info * core, 
427                                              addr_t              gpa,
428                                              void              * dst,
429                                              uint_t              len,
430                                              void              * priv)
431 {
432     memset((uint8_t *)dst, 0, len);
433     return len;
434 }
435
436
437 static int generic_free(struct generic_internal * state) {
438     int i;
439     
440     PrintDebug(VM_NONE,VCORE_NONE, "generic (%s): deinit_device\n", state->name);
441     
442 #ifdef V3_CONFIG_HOST_DEVICE
443     if (state->host_dev) { 
444         v3_host_dev_close(state->host_dev);
445         state->host_dev=0;
446     }
447 #endif
448     
449     // Note that the device manager handles unhooking the I/O ports
450     // We need to handle unhooking memory regions    
451     for (i=0;i<state->num_mem_hooks;i++) {
452         if (v3_unhook_mem(state->dev->vm,V3_MEM_CORE_ANY,state->mem_hook[i])<0) { 
453             PrintError(VM_NONE,VCORE_NONE , "generic (%s): unable to unhook memory starting at 0x%p\n", state->name,(void*)(state->mem_hook[i]));
454             return -1;
455         }
456     }
457              
458     V3_Free(state);
459     return 0;
460 }
461
462
463
464
465
466 static struct v3_device_ops dev_ops = { 
467     .free = (int (*)(void *))generic_free, 
468 };
469
470
471
472
473 static int add_port_range(struct vm_device * dev, uint_t start, uint_t end, generic_mode_t mode) {
474     uint_t i = 0;
475
476     struct generic_internal *state = (struct generic_internal *) dev->private_data;
477
478     PrintDebug(VM_NONE, VCORE_NONE, "generic (%s): adding port range 0x%x to 0x%x as %s\n", state->name,
479                start, end, 
480                (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : 
481                (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
482                (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
483                (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
484         
485     for (i = start; i <= end; i++) { 
486         switch (mode) { 
487             case GENERIC_PRINT_AND_PASSTHROUGH:
488                 if (v3_dev_hook_io(dev, i, 
489                                    &generic_read_port_print_and_passthrough, 
490                                    &generic_write_port_print_and_passthrough) == -1) { 
491                     PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
492                     return -1;
493                 }
494                 break;
495                 
496             case GENERIC_PRINT_AND_IGNORE:
497                 if (v3_dev_hook_io(dev, i, 
498                                    &generic_read_port_print_and_ignore, 
499                                    &generic_write_port_print_and_ignore) == -1) { 
500                     PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
501                     return -1;
502                 }
503                 break;
504             case GENERIC_PASSTHROUGH:
505                 if (v3_dev_hook_io(dev, i, 
506                                    &generic_read_port_passthrough, 
507                                    &generic_write_port_passthrough) == -1) { 
508                     PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
509                     return -1;
510                 }
511                 break;
512             case  GENERIC_IGNORE:
513                 if (v3_dev_hook_io(dev, i, 
514                                    &generic_read_port_ignore, 
515                                    &generic_write_port_ignore) == -1) { 
516                     PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook port 0x%x (already hooked?)\n", state->name, i);
517                     return -1;
518                 }
519                 break;
520             default:
521                 PrintError(VM_NONE, VCORE_NONE, "generic (%s): huh?\n", state->name);
522                 break;
523         }
524     }
525     
526     return 0;
527 }
528
529
530 static int add_mem_range(struct vm_device * dev, addr_t start, addr_t end, generic_mode_t mode) {
531
532     struct generic_internal *state = (struct generic_internal *) dev->private_data;
533
534     PrintDebug(VM_NONE, VCORE_NONE, "generic (%s): adding memory range 0x%p to 0x%p as %s\n", state->name,
535                (void*)start, (void*)end, 
536                (mode == GENERIC_PRINT_AND_PASSTHROUGH) ? "print-and-passthrough" : 
537                (mode == GENERIC_PRINT_AND_IGNORE) ? "print-and-ignore" :
538                (mode == GENERIC_PASSTHROUGH) ? "passthrough" :
539                (mode == GENERIC_IGNORE) ? "ignore" : "UNKNOWN");
540         
541     switch (mode) { 
542         case GENERIC_PRINT_AND_PASSTHROUGH:
543             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
544                                  &generic_read_mem_print_and_passthrough, 
545                                  &generic_write_mem_print_and_passthrough, dev) == -1) { 
546                 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
547                 return -1;
548             }
549             break;
550             
551         case GENERIC_PRINT_AND_IGNORE:
552             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
553                                  &generic_read_mem_print_and_ignore, 
554                                  &generic_write_mem_print_and_ignore, dev) == -1) { 
555                 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
556                 return -1;
557             }
558             break;
559
560         case GENERIC_PASSTHROUGH:
561             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
562                                  &generic_read_mem_passthrough, 
563                                  &generic_write_mem_passthrough, dev) == -1) { 
564                 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
565                 return -1;
566             }
567             break;
568             
569         case  GENERIC_IGNORE:
570             if (v3_hook_full_mem(dev->vm, V3_MEM_CORE_ANY, start, end+1, 
571                                  &generic_read_mem_ignore, 
572                                  &generic_write_mem_ignore, dev) == -1) { 
573                 PrintError(VM_NONE, VCORE_NONE, "generic (%s): can't hook memory region 0x%p to 0x%p\n", state->name,(void*)start,(void*)end);
574                 return -1;
575             }
576             break;
577         default:
578             PrintError(VM_NONE, VCORE_NONE, "generic (%s): huh?\n",state->name);
579             break;
580     }
581     
582     return 0;
583 }
584
585
586 #if 1
587
588 //This is a hack for host device testing and will be removed
589
590 static int osdebug_hcall(struct guest_info *core, uint_t hcall_id, void * priv_data) 
591 {
592     struct generic_internal * state = (struct generic_internal *)priv_data;
593
594     int msg_len = core->vm_regs.rcx;
595     addr_t msg_gpa = core->vm_regs.rbx;
596     int buf_is_va = core->vm_regs.rdx;
597     int i;
598     uint8_t c; 
599     PrintDebug(core->vm_info, core, "generic (%s): handling hypercall (len=%d) as sequence of port writes\n",
600                state->name, msg_len);
601
602
603     for (i=0;i<msg_len;i++) { 
604         if (buf_is_va == 1) {
605             if (v3_read_gva_memory(core, msg_gpa+i, 1, &c) != 1) {
606                 PrintError(core->vm_info, core, "generic (%s): could not read debug message\n",state->name);
607                 return -1;
608             }
609         } else {
610             if (v3_read_gpa_memory(core, msg_gpa+i, 1, &c) != 1) { 
611                 PrintError(core->vm_info, core, "generic (%s): Could not read debug message\n",state->name);
612                 return -1;
613             }
614         }
615         if (generic_write_port_print_and_passthrough(core,0xc0c0,&c,1,priv_data)!=1) { 
616             PrintError(core->vm_info, core, "generic (%s): write port passthrough failed\n",state->name);
617             return -1;
618         }
619     }   
620
621     return 0;
622 }
623
624 #endif
625
626 #ifdef V3_CONFIG_HOST_DEVICE
627 static void generic_intr_update_callback(v3_host_dev_t hdev, v3_guest_dev_t gdev, uint8_t irq, int raise)
628 {
629     if (gdev) { 
630         struct vm_device *dev = (struct vm_device *) gdev;
631         if (raise) { 
632             v3_raise_irq(dev->vm,irq);
633         } else {
634             v3_lower_irq(dev->vm,irq);
635         }
636     }
637 }
638 #endif
639
640 /*
641    The device can be used to forward to the underlying physical device 
642    or to a host device that has a given url.   Both memory and ports can be forwarded as
643
644         GENERIC_PASSTHROUGH => send writes and reads to physical device or host
645         GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
646
647         GENERIC_IGNORE => ignore writes and reads
648         GENERIC_PRINT_AND_PASSTHROUGH => also print what it's doing
649
650
651         The purpose of the "PRINT" variants is to make it easy to spy on
652         device interactions (although you will not see DMA or interrupts)
653
654
655    <device class="generic" id="my_id" 
656          empty | forward="physical_device" or forward="host_device" hostdev="url">
657
658   (empty implies physical_dev)
659
660      <ports>
661          <start>portno1</start>
662          <end>portno2</end>   => portno1 through portno2 (inclusive)
663          <mode>PRINT_AND_PASSTHROUGH</mode>  (as above)
664      </ports>
665
666      <memory>
667          <start>gpa1</start>
668          <end>gpa2</end>     => memory addreses gpa1 through gpa2 (inclusive); page granularity
669          <mode> ... as above </mode>
670      </memory>
671
672 */
673
674 static int generic_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
675     struct generic_internal * state = NULL;
676     char * dev_id = v3_cfg_val(cfg, "ID");
677     char * forward = v3_cfg_val(cfg, "forward");
678 #ifdef V3_CONFIG_HOST_DEVICE
679     char * host_dev = v3_cfg_val(cfg, "hostdev");
680 #endif
681     v3_cfg_tree_t * port_cfg = v3_cfg_subtree(cfg, "ports");
682     v3_cfg_tree_t * mem_cfg = v3_cfg_subtree(cfg, "memory");
683
684
685     state = (struct generic_internal *)V3_Malloc(sizeof(struct generic_internal));
686
687     if (state == NULL) {
688         PrintError(vm, VCORE_NONE, "generic (%s): could not allocate generic state\n",dev_id);
689         return -1;
690     }
691     
692     memset(state, 0, sizeof(struct generic_internal));
693     strncpy(state->name,dev_id,MAX_NAME);
694     state->name[MAX_NAME-1] = 0;
695
696     if (!forward) { 
697         state->forward_type=GENERIC_PHYSICAL;
698     } else {
699         if (!strcasecmp(forward,"physical_device")) { 
700             state->forward_type=GENERIC_PHYSICAL;
701         } else if (!strcasecmp(forward,"host_device")) { 
702 #ifdef V3_CONFIG_HOST_DEVICE
703             state->forward_type=GENERIC_HOST;
704 #else
705             PrintError(vm, VCORE_NONE, "generic (%s): cannot configure host device since host device support is not built in\n", state->name);
706             V3_Free(state);
707             return -1;
708 #endif
709         } else {
710             PrintError(vm, VCORE_NONE, "generic (%s): unknown forwarding type \"%s\"\n", state->name, forward);
711             V3_Free(state);
712             return -1;
713         }
714     }
715     
716     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
717
718     if (dev == NULL) {
719         PrintError(vm, VCORE_NONE, "generic: could not attach device %s\n", state->name);
720         V3_Free(state);
721         return -1;
722     }
723
724     state->dev=dev;
725
726
727 #ifdef V3_CONFIG_HOST_DEVICE
728     if (state->forward_type==GENERIC_HOST) { 
729         if (!host_dev) { 
730             PrintError(vm, VCORE_NONE, "generic (%s): host forwarding requested, but no host device given\n", state->name);
731             v3_remove_device(dev);
732             return -1;
733         } else {
734             state->host_dev = v3_host_dev_open(host_dev,V3_BUS_CLASS_DIRECT,dev,generic_intr_update_callback,vm);
735             if (!(state->host_dev)) { 
736                 PrintError(vm, VCORE_NONE, "generic (%s): unable to open host device \"%s\"\n", state->name,host_dev);
737                 v3_remove_device(dev);
738                 return -1;
739             } else {
740                 PrintDebug(vm, VCORE_NONE, "generic (%s): successfully attached host device \"%s\"\n", state->name,host_dev);
741             }
742         }
743     }
744 #endif
745
746     PrintDebug(vm, VCORE_NONE, "generic (%s): init_device\n", state->name);
747
748     // scan port list....
749     while (port_cfg) {
750         uint16_t start = atox(v3_cfg_val(port_cfg, "start"));
751         uint16_t end = atox(v3_cfg_val(port_cfg, "end"));
752         char * mode_str = v3_cfg_val(port_cfg, "mode");
753     if (!mode_str) {
754         PrintError(vm, VCORE_NONE, "generic (%s): error getting port mode\n", state->name);
755         return -1;
756     }
757         generic_mode_t mode = GENERIC_IGNORE;
758         if (strcasecmp(mode_str, "print_and_ignore") == 0) {
759             mode = GENERIC_PRINT_AND_IGNORE;
760         } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
761             mode = GENERIC_PRINT_AND_PASSTHROUGH;
762         } else if (strcasecmp(mode_str, "passthrough") == 0) {
763             mode = GENERIC_PASSTHROUGH;
764         } else if (strcasecmp(mode_str, "ignore") == 0) {
765             mode = GENERIC_IGNORE;
766         } else {
767             PrintError(vm, VCORE_NONE, "generic (%s): invalid mode %s in adding ports\n", state->name, mode_str);
768             v3_remove_device(dev);
769             return -1;
770         }
771         
772         
773         if (add_port_range(dev, start, end, mode) == -1) {
774             PrintError(vm, VCORE_NONE, "generic (%s): could not add port range 0x%x to 0x%x\n", state->name, start, end);
775             v3_remove_device(dev);
776             return -1;
777         }
778
779         port_cfg = v3_cfg_next_branch(port_cfg);
780     }
781
782     // scan memory list....
783     while (mem_cfg) {
784         addr_t  start = atox(v3_cfg_val(mem_cfg, "start"));
785         addr_t end = atox(v3_cfg_val(mem_cfg, "end"));
786         char * mode_str = v3_cfg_val(mem_cfg, "mode");
787         generic_mode_t mode = GENERIC_IGNORE;
788
789         if (strcasecmp(mode_str, "print_and_ignore") == 0) {
790             mode = GENERIC_PRINT_AND_IGNORE;
791         } else if (strcasecmp(mode_str, "print_and_passthrough") == 0) {
792             mode = GENERIC_PRINT_AND_PASSTHROUGH;
793         } else if (strcasecmp(mode_str, "passthrough") == 0) {
794             mode = GENERIC_PASSTHROUGH;
795         } else if (strcasecmp(mode_str, "ignore") == 0) {
796             mode = GENERIC_IGNORE;
797         } else {
798             PrintError(vm, VCORE_NONE, "generic (%s): invalid mode %s for adding memory\n", state->name, mode_str);
799             v3_remove_device(dev);
800             return -1;
801         }
802
803         if (state->num_mem_hooks>=MAX_MEM_HOOKS) { 
804             PrintError(vm, VCORE_NONE, "generic (%s): cannot add another memory hook (increase MAX_MEM_HOOKS)\n", state->name);
805             v3_remove_device(dev);
806             return -1;
807         }
808         
809         if (add_mem_range(dev, start, end, mode) == -1) {
810             PrintError(vm, VCORE_NONE, "generic (%s): could not add memory range 0x%p to 0x%p\n", state->name, (void*)start, (void*)end);
811             v3_remove_device(dev);
812             return -1;
813         }
814         
815         state->mem_hook[state->num_mem_hooks] = start;
816         state->num_mem_hooks++;
817
818         mem_cfg = v3_cfg_next_branch(port_cfg);
819     }
820
821 #if 1
822     // hack for os debug testing
823     if (strcasecmp(state->name,"os debug")==0) { 
824         PrintDebug(vm, VCORE_NONE, "generic (%s): adding hypercall for os debug device\n", state->name);
825         v3_register_hypercall(vm,0xc0c0,osdebug_hcall,state);
826     }
827 #endif
828     
829     PrintDebug(vm, VCORE_NONE, "generic (%s): initialization complete\n", state->name);
830
831     return 0;
832 }
833
834 device_register("GENERIC", generic_init)