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.


Multiboot enhancements
[palacios.releases.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     if (!hcall) {
140         PrintError(vm, VCORE_NONE, "Cannot allocate in registering hypercall\n");
141         return -1;
142     }
143
144     hcall->id = hypercall_id;
145     hcall->priv_data = priv_data;
146     hcall->hcall_fn = hypercall;
147
148     if (insert_hypercall(vm, hcall)) {
149         V3_Free(hcall);
150         return -1;
151     }
152
153     return 0;
154 }
155
156
157
158 static int free_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
159     v3_rb_erase(&(hcall->tree_node), &(vm->hcall_map));
160     V3_Free(hcall);
161
162     return 0;
163 }
164
165 int v3_remove_hypercall(struct v3_vm_info * vm, hcall_id_t hypercall_id) {
166     struct hypercall * hcall = get_hypercall(vm, hypercall_id);
167
168     if (hcall == NULL) {
169         PrintError(vm, VCORE_NONE, "Attempted to remove non existant hypercall\n");
170         return -1;
171     }
172
173     free_hypercall(vm, hcall);
174
175     return 0;
176 }
177
178
179 int v3_handle_hypercall(struct guest_info * info) {
180     hcall_id_t hypercall_id = *(uint_t *)&info->vm_regs.rax;
181     struct hypercall * hcall = get_hypercall(info->vm_info, hypercall_id);
182
183     if (!hcall) {
184         PrintError(info->vm_info, info,  "Invalid Hypercall (%d(0x%x) not registered)\n", 
185                    hypercall_id, hypercall_id);
186         return -1;
187     }
188
189     if (hcall->hcall_fn(info, hypercall_id, hcall->priv_data) != 0) {
190         PrintError(info->vm_info, info, "Error handling hypercall\n");
191         return -1;
192     }
193
194     return 0;
195 }
196