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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Andy Gocke <agocke@gmail.com>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Andy Gocke <agocke@gmail.com>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmx_io.h>
21 #include <palacios/vmm_io.h>
22 #include <palacios/vmcs.h>
23 #include <palacios/vmx_lowlevel.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmx_handler.h>
26 #include <palacios/vmm_ctrl_regs.h>
27 #include <palacios/vm_guest_mem.h>
28 #include <palacios/vmm_decoder.h>
30 #ifndef CONFIG_DEBUG_IO
32 #define PrintDebug(fmt, args...)
37 static int update_map(struct guest_info * info, uint16_t port, int hook_read, int hook_write)
39 uchar_t * bitmap = (uint8_t *)(info->io_map.arch_data);
43 if ((hook_read == 0) && (hook_write == 0)) {
44 *(bitmap + major) &= ~(0x1 << minor);
46 *(bitmap + major) |= (0x1 << minor);
52 int v3_init_vmx_io_map(struct guest_info * info)
54 info->io_map.update_map = update_map;
56 info->io_map.arch_data = V3_VAddr(V3_AllocPages(2));
57 memset(info->io_map.arch_data, 0, PAGE_SIZE_4KB*2);
62 int v3_handle_vmx_io_in(struct guest_info * info) {
64 uint32_t instr_length = 0;
66 vmcs_read(VMCS_EXIT_QUAL, &exit_qual);
68 struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual;
70 struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port);
74 PrintError("Hook not present for IN on port %x\n", io_qual->port);
78 read_size = io_qual->access_size + 1;
80 PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_qual->port, io_qual->port);
82 if (hook->read(io_qual->port, &(info->vm_regs.rax), read_size, hook->priv_data) != read_size) {
83 PrintError("Read failure for IN on port %x\n", io_qual->port);
89 if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) {
90 PrintError("Could not read instruction length\n");
94 info->rip += instr_length;
99 int v3_handle_vmx_io_ins(struct guest_info * info)
103 vmcs_read(VMCS_EXIT_QUAL, &exit_qual);
105 struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual;
106 struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port);
114 PrintError("Hook not present for INS on port 0x%x\n", io_qual->port);
118 PrintDebug("INS on port 0x%x\n", io_qual->port);
120 read_size = io_qual->access_size + 1;
123 rep_num = info->vm_regs.rcx & get_gpr_mask(info);
126 if ( ((struct rflags *)&(info->ctrl_regs.rflags))->df ) {
127 rdi_change = -read_size;
129 rdi_change = read_size;
132 PrintDebug("INS size=%d for %ld steps\n", read_size, rep_num);
134 vmcs_read(VMCS_GUEST_LINEAR_ADDR, &guest_va);
136 if (guest_va_to_host_va(info, guest_va, &host_addr) == -1) {
137 PrintError("Could not convert Guest VA to host VA\n");
142 if (hook->read(io_qual->port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
143 PrintError("Read Failure for INS on port 0x%x\n", io_qual->port);
147 host_addr += rdi_change;
148 info->vm_regs.rdi += rdi_change;
155 } while (rep_num > 0);
159 vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
161 info->rip += instr_len;
168 int v3_handle_vmx_io_out(struct guest_info * info) {
171 vmcs_read(VMCS_EXIT_QUAL, &exit_qual);
173 struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual;
175 struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port);
178 PrintError("Hook not present for out on port %x\n", io_qual->port);
182 int write_size = io_qual->access_size + 1;
184 PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual->port, io_qual->port);
187 if (hook->write(io_qual->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
188 PrintError("Write failure for out on port %x\n",io_qual->port);
192 uint32_t instr_length = 0;
194 if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) {
195 PrintError("Could not read instruction length\n");
199 info->rip += instr_length;
206 int v3_handle_vmx_io_outs(struct guest_info * info) {
209 vmcs_read(VMCS_EXIT_QUAL, &exit_qual);
211 struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual;
212 struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port);
220 PrintError("Hook not present for OUTS on port 0x%x\n", io_qual->port);
224 PrintDebug("OUTS on port 0x%x\n", io_qual->port);
226 write_size = io_qual->access_size + 1;
229 // Grab the address sized bits of rcx
230 rep_num = info->vm_regs.rcx & get_gpr_mask(info);
233 if ( ((struct rflags *)&(info->ctrl_regs.rflags))->df ) {
234 rsi_change = -write_size;
236 rsi_change = write_size;
239 vmcs_read(VMCS_GUEST_LINEAR_ADDR, &guest_va);
241 PrintDebug("OUTS size=%d for %ld steps\n", write_size, rep_num);
243 if (guest_va_to_host_va(info, guest_va, &host_addr) == -1) {
244 PrintError("Could not convert guest VA to host VA\n");
249 if (hook->write(io_qual->port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
250 PrintError("Read failure for INS on port 0x%x\n", io_qual->port);
254 host_addr += rsi_change;
255 info->vm_regs.rsi += rsi_change;
262 } while (rep_num > 0);
266 vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
268 info->rip += instr_len;