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.


deallocate arch specific IO/MSR hook state
[palacios.git] / palacios / src / palacios / vmm_hypercall.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, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm_hypercall.h>
21 #include <palacios/vmm.h>
22 #include <palacios/vm_guest.h>
23
24
25 static int hcall_test(struct guest_info * info, hcall_id_t hcall_id, void * private_data) {
26     info->vm_regs.rbx = 0x1111;
27     info->vm_regs.rcx = 0x2222;
28     info->vm_regs.rdx = 0x3333;
29     info->vm_regs.rsi = 0x4444;
30     info->vm_regs.rdi = 0x5555;
31     return 0;
32 }
33
34
35
36 void v3_init_hypercall_map(struct v3_vm_info * vm) {
37     vm->hcall_map.rb_node = NULL;
38
39     v3_register_hypercall(vm, TEST_HCALL, hcall_test, NULL);
40 }
41
42
43 struct hypercall {
44     uint_t id;
45   
46     int (*hcall_fn)(struct guest_info * info, hcall_id_t hcall_id, void * priv_data);
47     void * priv_data;
48   
49     struct rb_node tree_node;
50 };
51
52
53
54 static inline struct hypercall * __insert_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
55     struct rb_node ** p = &(vm->hcall_map.rb_node);
56     struct rb_node * parent = NULL;
57     struct hypercall * tmp_hcall = NULL;
58
59     while (*p) {
60         parent = *p;
61         tmp_hcall = rb_entry(parent, struct hypercall, tree_node);
62
63         if (hcall->id < tmp_hcall->id) {
64             p = &(*p)->rb_left;
65         } else if (hcall->id > tmp_hcall->id) {
66             p = &(*p)->rb_right;
67         } else {
68             return tmp_hcall;
69         }
70     }
71
72     rb_link_node(&(hcall->tree_node), parent, p);
73
74     return NULL;
75 }
76
77
78 static inline struct hypercall * insert_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
79     struct hypercall * ret;
80
81     if ((ret = __insert_hypercall(vm, hcall))) {
82         return ret;
83     }
84
85     v3_rb_insert_color(&(hcall->tree_node), &(vm->hcall_map));
86
87     return NULL;
88 }
89
90
91 static struct hypercall * get_hypercall(struct v3_vm_info * vm, hcall_id_t id) {
92     struct rb_node * n = vm->hcall_map.rb_node;
93     struct hypercall * hcall = NULL;
94
95     while (n) {
96         hcall = rb_entry(n, struct hypercall, tree_node);
97     
98         if (id < hcall->id) {
99             n = n->rb_left;
100         } else if (id > hcall->id) {
101             n = n->rb_right;
102         } else {
103             return hcall;
104         }
105     }
106
107     return NULL;
108 }
109
110
111 int v3_register_hypercall(struct v3_vm_info * vm, hcall_id_t hypercall_id, 
112                           int (*hypercall)(struct guest_info * info, hcall_id_t hcall_id, void * priv_data), 
113                           void * priv_data) {
114
115     struct hypercall * hcall = (struct hypercall *)V3_Malloc(sizeof(struct hypercall));
116
117     hcall->id = hypercall_id;
118     hcall->priv_data = priv_data;
119     hcall->hcall_fn = hypercall;
120
121     if (insert_hypercall(vm, hcall)) {
122         V3_Free(hcall);
123         return -1;
124     }
125
126     return 0;
127 }
128
129
130 int v3_remove_hypercall(struct v3_vm_info * vm, hcall_id_t hypercall_id) {
131     struct hypercall * hcall = get_hypercall(vm, hypercall_id);
132
133     if (hcall == NULL) {
134         PrintError("Attempted to remove non existant hypercall\n");
135         return -1;
136     }
137
138     v3_rb_erase(&(hcall->tree_node), &(vm->hcall_map));
139
140     V3_Free(hcall);
141
142     return 0;
143 }
144
145
146 int v3_handle_hypercall(struct guest_info * info) {
147     hcall_id_t hypercall_id = *(uint_t *)&info->vm_regs.rax;
148     struct hypercall * hcall = get_hypercall(info->vm_info, hypercall_id);
149
150     if (!hcall) {
151         PrintError("Invalid Hypercall (%d(0x%x) not registered)\n", 
152                    hypercall_id, hypercall_id);
153         return -1;
154     }
155
156     if (hcall->hcall_fn(info, hypercall_id, hcall->priv_data) == 0) {
157         info->vm_regs.rax = 0;
158     } else {
159         info->vm_regs.rax = -1;
160     }
161
162     return 0;
163 }
164