1 #include <palacios/vmm.h>
2 #include <palacios/vmm_emulator.h>
3 #include <palacios/vm_guest_mem.h>
4 #include <palacios/vmm_decoder.h>
6 static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
8 int init_emulator(struct guest_info * info) {
9 struct emulation_state * emulator = &(info->emulator);
11 emulator->num_emulated_pages = 0;
12 INIT_LIST_HEAD(&(emulator->emulated_pages));
15 emulator->num_saved_pages = 0;
16 INIT_LIST_HEAD(&(emulator->saved_pages));
18 emulator->num_write_regions = 0;
19 INIT_LIST_HEAD(&(emulator->write_regions));
21 emulator->running = 0;
22 emulator->instr_length = 0;
27 static addr_t get_new_page() {
28 void * page = V3_AllocPages(1);
29 memset(page, 0, PAGE_SIZE);
35 static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) {
36 addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip);
37 addr_t code_page = get_new_page();
38 struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page));
39 struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page));
42 saved_code_page->va = PT32_PAGE_ADDR(info->rip);
44 new_code_page->page_addr = code_page;
45 new_code_page->va = PT32_PAGE_ADDR(info->rip);
47 new_code_page->pte.present = 1;
48 new_code_page->pte.writable = 0;
49 new_code_page->pte.user_page = 1;
50 new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page);
52 memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length);
53 memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3);
55 PrintDebug("New Instr Stream:\n");
56 PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
57 PrintDebug("rip =%x\n", info->rip);
62 v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
65 list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
66 info->emulator.num_emulated_pages++;
68 list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
69 info->emulator.num_saved_pages++;
75 // get the current instr
76 // check if rep + remove
77 // put into new page, vmexit after
78 // replace new page with current eip page
80 int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva,
81 int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data),
82 addr_t read_gpa, void * private_data) {
83 struct basic_instr_info instr_info;
86 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
87 addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
90 PrintDebug("Emulating Read\n");
92 if (info->mem_mode == PHYSICAL_MEM) {
93 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
95 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
98 PrintDebug("Instr (15 bytes) at %x:\n", instr);
99 PrintTraceMemDump(instr, 15);
101 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
102 PrintError("Could not do a basic memory instruction decode\n");
107 if (instr_info.has_rep == 1) {
108 PrintError("We currently don't handle rep* instructions\n");
114 data_page->page_addr = get_new_page();
115 data_page->va = PT32_PAGE_ADDR(read_gva);
116 data_page->pte.present = 1;
117 data_page->pte.writable = 0;
118 data_page->pte.user_page = 1;
119 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
122 // Read the data directly onto the emulated page
123 if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
124 PrintError("Read error in emulator\n");
125 V3_FreePage((void *)(data_page->page_addr));
130 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
133 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
134 info->emulator.num_emulated_pages++;
136 if (saved_pte.present == 1) {
137 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
138 saved_data_page->pte = saved_pte;
139 saved_data_page->va = PT32_PAGE_ADDR(read_gva);
141 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
142 info->emulator.num_saved_pages++;
146 setup_code_page(info, instr, &instr_info);
148 info->emulator.running = 1;
149 info->run_state = VM_EMULATING;
150 info->emulator.instr_length = instr_info.instr_length;
157 int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
158 int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data),
159 addr_t write_gpa, void * private_data) {
161 struct basic_instr_info instr_info;
164 struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
165 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
166 addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
169 PrintDebug("Emulating Write\n");
171 if (info->mem_mode == PHYSICAL_MEM) {
172 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
174 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
177 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
178 PrintError("Could not do a basic memory instruction decode\n");
184 if (instr_info.has_rep == 1) {
185 PrintError("We currently don't handle rep* instructions\n");
192 data_page->page_addr = get_new_page();
193 data_page->va = PT32_PAGE_ADDR(write_gva);
194 data_page->pte.present = 1;
195 data_page->pte.writable = 1;
196 data_page->pte.user_page = 1;
197 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
201 write_op->write = write;
202 write_op->write_addr = write_gpa;
203 write_op->length = instr_info.op_size;
204 write_op->private_data = private_data;
206 write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
208 list_add(&(write_op->write_list), &(info->emulator.write_regions));
209 info->emulator.num_write_regions--;
211 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
214 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
215 info->emulator.num_emulated_pages++;
217 if (saved_pte.present == 1) {
218 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
219 saved_data_page->pte = saved_pte;
220 saved_data_page->va = PT32_PAGE_ADDR(write_gva);
222 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
223 info->emulator.num_saved_pages++;
227 if (info->emulator.running == 0) {
228 setup_code_page(info, instr, &instr_info);
229 info->emulator.running = 1;
230 info->run_state = VM_EMULATING;
231 info->emulator.instr_length = instr_info.instr_length;
239 int v3_emulation_exit_handler(struct guest_info * info) {
240 struct saved_page * svpg, * p_svpg;
241 struct emulated_page * empg, * p_empg;
242 struct write_region * wr_reg, * p_wr_reg;
245 // Complete the writes
247 // swap out emulated pages with blank dummies
248 // swap in saved pages
251 PrintDebug("V3 Emulation Exit Handler\n");
253 list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
254 wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
255 PrintDebug("Writing \n");
257 list_del(&(wr_reg->write_list));
261 info->emulator.num_write_regions = 0;
264 *(uint_t *)&dummy_pte = 0;
266 list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
269 PrintDebug("wiping page %x\n", empg->va);
271 v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
272 V3_FreePage((void *)(empg->page_addr));
274 list_del(&(empg->page_list));
277 info->emulator.num_emulated_pages = 0;
279 list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
281 PrintDebug("Setting Saved page %x back\n", svpg->va);
282 v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
284 list_del(&(svpg->page_list));
287 info->emulator.num_saved_pages = 0;
289 info->run_state = VM_RUNNING;
290 info->emulator.running = 0;
291 //info->rip += info->emulator.instr_length;
293 info->emulator.instr_length = 0;
295 PrintDebug("returning from emulation\n");