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.


bug fix to check for illegal memory ranges
[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 struct hypercall {
36     uint_t id;
37   
38     int (*hcall_fn)(struct guest_info * info, hcall_id_t hcall_id, void * priv_data);
39     void * priv_data;
40   
41     struct rb_node tree_node;
42 };
43
44 static int free_hypercall(struct v3_vm_info * vm, struct hypercall * hcall);
45
46 void v3_init_hypercall_map(struct v3_vm_info * vm) {
47     vm->hcall_map.rb_node = NULL;
48
49     v3_register_hypercall(vm, TEST_HCALL, hcall_test, NULL);
50 }
51
52 int v3_deinit_hypercall_map(struct v3_vm_info * vm) {
53     struct rb_node * node = NULL;
54     struct hypercall * hcall = NULL;
55     struct rb_node * tmp_node = NULL;
56
57     v3_remove_hypercall(vm, TEST_HCALL);
58
59     node = v3_rb_first(&(vm->hcall_map));
60
61     while (node) {
62         hcall = rb_entry(node, struct hypercall, tree_node);
63         tmp_node = node;
64         node = v3_rb_next(node);
65
66         free_hypercall(vm, hcall);
67     }
68     
69     return 0;
70 }
71
72
73
74
75
76 static inline struct hypercall * __insert_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
77     struct rb_node ** p = &(vm->hcall_map.rb_node);
78     struct rb_node * parent = NULL;
79     struct hypercall * tmp_hcall = NULL;
80
81     while (*p) {
82         parent = *p;
83         tmp_hcall = rb_entry(parent, struct hypercall, tree_node);
84
85         if (hcall->id < tmp_hcall->id) {
86             p = &(*p)->rb_left;
87         } else if (hcall->id > tmp_hcall->id) {
88             p = &(*p)->rb_right;
89         } else {
90             return tmp_hcall;
91         }
92     }
93
94     rb_link_node(&(hcall->tree_node), parent, p);
95
96     return NULL;
97 }
98
99
100 static inline struct hypercall * insert_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
101     struct hypercall * ret;
102
103     if ((ret = __insert_hypercall(vm, hcall))) {
104         return ret;
105     }
106
107     v3_rb_insert_color(&(hcall->tree_node), &(vm->hcall_map));
108
109     return NULL;
110 }
111
112
113 static struct hypercall * get_hypercall(struct v3_vm_info * vm, hcall_id_t id) {
114     struct rb_node * n = vm->hcall_map.rb_node;
115     struct hypercall * hcall = NULL;
116
117     while (n) {
118         hcall = rb_entry(n, struct hypercall, tree_node);
119     
120         if (id < hcall->id) {
121             n = n->rb_left;
122         } else if (id > hcall->id) {
123             n = n->rb_right;
124         } else {
125             return hcall;
126         }
127     }
128
129     return NULL;
130 }
131
132
133 int v3_register_hypercall(struct v3_vm_info * vm, hcall_id_t hypercall_id, 
134                           int (*hypercall)(struct guest_info * info, hcall_id_t hcall_id, void * priv_data), 
135                           void * priv_data) {
136
137     struct hypercall * hcall = (struct hypercall *)V3_Malloc(sizeof(struct hypercall));
138
139     hcall->id = hypercall_id;
140     hcall->priv_data = priv_data;
141     hcall->hcall_fn = hypercall;
142
143     if (insert_hypercall(vm, hcall)) {
144         V3_Free(hcall);
145         return -1;
146     }
147
148     return 0;
149 }
150
151
152
153 static int free_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
154     v3_rb_erase(&(hcall->tree_node), &(vm->hcall_map));
155     V3_Free(hcall);
156
157     return 0;
158 }
159
160 int v3_remove_hypercall(struct v3_vm_info * vm, hcall_id_t hypercall_id) {
161     struct hypercall * hcall = get_hypercall(vm, hypercall_id);
162
163     if (hcall == NULL) {
164         PrintError("Attempted to remove non existant hypercall\n");
165         return -1;
166     }
167
168     free_hypercall(vm, hcall);
169
170     return 0;
171 }
172
173
174 int v3_handle_hypercall(struct guest_info * info) {
175     hcall_id_t hypercall_id = *(uint_t *)&info->vm_regs.rax;
176     struct hypercall * hcall = get_hypercall(info->vm_info, hypercall_id);
177
178     if (!hcall) {
179         PrintError("Invalid Hypercall (%d(0x%x) not registered)\n", 
180                    hypercall_id, hypercall_id);
181         return -1;
182     }
183
184     if (hcall->hcall_fn(info, hypercall_id, hcall->priv_data) == 0) {
185         info->vm_regs.rax = 0;
186     } else {
187         info->vm_regs.rax = -1;
188     }
189
190     return 0;
191 }
192