#include <palacios/vm_guest.h>
-#define HYPERCALL_TEST_HCALL 0x1
-
-static int hcall_test(struct guest_info * info, uint_t hcall_id, void * private_data) {
+static int hcall_test(struct guest_info * info, hcall_id_t hcall_id, void * private_data) {
info->vm_regs.rbx = 0x1111;
info->vm_regs.rcx = 0x2222;
info->vm_regs.rdx = 0x3333;
}
-
-void v3_init_hypercall_map(struct guest_info * info) {
- info->hcall_map.rb_node = NULL;
-
- v3_register_hypercall(info, HYPERCALL_TEST_HCALL, hcall_test, NULL);
-}
-
-
struct hypercall {
uint_t id;
- int (*hcall_fn)(struct guest_info * info, uint_t hcall_id, void * priv_data);
+ int (*hcall_fn)(struct guest_info * info, hcall_id_t hcall_id, void * priv_data);
void * priv_data;
struct rb_node tree_node;
};
+static int free_hypercall(struct v3_vm_info * vm, struct hypercall * hcall);
+
+void v3_init_hypercall_map(struct v3_vm_info * vm) {
+ vm->hcall_map.rb_node = NULL;
+
+ v3_register_hypercall(vm, TEST_HCALL, hcall_test, NULL);
+}
+
+int v3_deinit_hypercall_map(struct v3_vm_info * vm) {
+ struct rb_node * node = NULL;
+ struct hypercall * hcall = NULL;
+ struct rb_node * tmp_node = NULL;
+
+ v3_remove_hypercall(vm, TEST_HCALL);
+
+ node = v3_rb_first(&(vm->hcall_map));
+
+ while (node) {
+ hcall = rb_entry(node, struct hypercall, tree_node);
+ tmp_node = node;
+ node = v3_rb_next(node);
+
+ free_hypercall(vm, hcall);
+ }
+
+ return 0;
+}
+
+
+
-static inline struct hypercall * __insert_hypercall(struct guest_info * info, struct hypercall * hcall) {
- struct rb_node ** p = &(info->hcall_map.rb_node);
+static inline struct hypercall * __insert_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
+ struct rb_node ** p = &(vm->hcall_map.rb_node);
struct rb_node * parent = NULL;
struct hypercall * tmp_hcall = NULL;
}
-static inline struct hypercall * insert_hypercall(struct guest_info * info, struct hypercall * hcall) {
+static inline struct hypercall * insert_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
struct hypercall * ret;
- if ((ret = __insert_hypercall(info, hcall))) {
+ if ((ret = __insert_hypercall(vm, hcall))) {
return ret;
}
- v3_rb_insert_color(&(hcall->tree_node), &(info->hcall_map));
+ v3_rb_insert_color(&(hcall->tree_node), &(vm->hcall_map));
return NULL;
}
-static struct hypercall * get_hypercall(struct guest_info * info, uint_t id) {
- struct rb_node * n = info->hcall_map.rb_node;
+static struct hypercall * get_hypercall(struct v3_vm_info * vm, hcall_id_t id) {
+ struct rb_node * n = vm->hcall_map.rb_node;
struct hypercall * hcall = NULL;
while (n) {
}
-int v3_register_hypercall(struct guest_info * info, uint_t hypercall_id,
- int (*hypercall)(struct guest_info * info, uint_t hcall_id, void * priv_data),
+int v3_register_hypercall(struct v3_vm_info * vm, hcall_id_t hypercall_id,
+ int (*hypercall)(struct guest_info * info, hcall_id_t hcall_id, void * priv_data),
void * priv_data) {
struct hypercall * hcall = (struct hypercall *)V3_Malloc(sizeof(struct hypercall));
+ if (!hcall) {
+ PrintError(vm, VCORE_NONE, "Cannot allocate in registering hypercall\n");
+ return -1;
+ }
+
hcall->id = hypercall_id;
hcall->priv_data = priv_data;
hcall->hcall_fn = hypercall;
- if (insert_hypercall(info, hcall)) {
+ if (insert_hypercall(vm, hcall)) {
V3_Free(hcall);
return -1;
}
}
-int v3_handle_hypercall(struct guest_info * info) {
- uint_t hypercall_id = *(uint_t *)&info->vm_regs.rax;
- struct hypercall * hcall = get_hypercall(info, hypercall_id);
+static int free_hypercall(struct v3_vm_info * vm, struct hypercall * hcall) {
+ v3_rb_erase(&(hcall->tree_node), &(vm->hcall_map));
+ V3_Free(hcall);
+
+ return 0;
+}
+
+int v3_remove_hypercall(struct v3_vm_info * vm, hcall_id_t hypercall_id) {
+ struct hypercall * hcall = get_hypercall(vm, hypercall_id);
+
+ if (hcall == NULL) {
+ PrintError(vm, VCORE_NONE, "Attempted to remove non existant hypercall\n");
+ return -1;
+ }
+
+ free_hypercall(vm, hcall);
+
+ return 0;
+}
+
+
+int v3_handle_hypercall(struct guest_info * info) {
+ hcall_id_t hypercall_id = *(uint_t *)&info->vm_regs.rax;
+ struct hypercall * hcall = get_hypercall(info->vm_info, hypercall_id);
if (!hcall) {
- PrintError("Invalid Hypercall (%d(0x%x) not registered)\n",
+ PrintError(info->vm_info, info, "Invalid Hypercall (%d(0x%x) not registered) => ignored with rax=-1\n",
hypercall_id, hypercall_id);
- return -1;
+ info->vm_regs.rax=-1;
+ return 0;
}
- if (hcall->hcall_fn(info, hypercall_id, hcall->priv_data) == 0) {
- info->vm_regs.rax = 0;
- } else {
- info->vm_regs.rax = -1;
+ if (hcall->hcall_fn(info, hypercall_id, hcall->priv_data) != 0) {
+ PrintError(info->vm_info, info, "Error handling hypercall\n");
+ return -1;
}
return 0;