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.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
Lei Xia [Wed, 13 Apr 2011 16:15:16 +0000 (11:15 -0500)]
42 files changed:
Kconfig
Makefile
linux_module/Makefile
linux_module/palacios-console.c
linux_module/palacios-file.c
linux_module/palacios-packet.c
linux_module/palacios-socket.c
linux_module/palacios-stream.c
palacios/include/interfaces/vmm_console.h [moved from palacios/include/palacios/vmm_console.h with 100% similarity]
palacios/include/interfaces/vmm_file.h [moved from palacios/include/palacios/vmm_file.h with 100% similarity]
palacios/include/interfaces/vmm_graphics_console.h [moved from palacios/include/palacios/vmm_graphics_console.h with 100% similarity]
palacios/include/interfaces/vmm_host_dev.h [new file with mode: 0644]
palacios/include/interfaces/vmm_keyed_stream.h [moved from palacios/include/palacios/vmm_keyed_stream.h with 100% similarity]
palacios/include/interfaces/vmm_packet.h [moved from palacios/include/palacios/vmm_packet.h with 100% similarity]
palacios/include/interfaces/vmm_socket.h [moved from palacios/include/palacios/vmm_socket.h with 100% similarity]
palacios/include/interfaces/vmm_stream.h [moved from palacios/include/palacios/vmm_stream.h with 100% similarity]
palacios/include/palacios/vmm_decoder.h
palacios/include/palacios/vmm_dev_mgr.h
palacios/src/devices/char_stream.c
palacios/src/devices/cirrus_gfx_card.c
palacios/src/devices/curses_cons.c
palacios/src/devices/filedisk.c
palacios/src/devices/netdisk.c
palacios/src/devices/nic_bridge.c
palacios/src/devices/telnet_cons.c
palacios/src/devices/vga.c
palacios/src/devices/vga_regs.h
palacios/src/interfaces/Kconfig [new file with mode: 0644]
palacios/src/interfaces/Makefile [new file with mode: 0644]
palacios/src/interfaces/vmm_console.c [moved from palacios/src/palacios/vmm_console.c with 98% similarity]
palacios/src/interfaces/vmm_file.c [moved from palacios/src/palacios/vmm_file.c with 98% similarity]
palacios/src/interfaces/vmm_graphics_console.c [moved from palacios/src/palacios/vmm_graphics_console.c with 98% similarity]
palacios/src/interfaces/vmm_keyed_stream.c [moved from palacios/src/palacios/vmm_keyed_stream.c with 98% similarity]
palacios/src/interfaces/vmm_packet.c [moved from palacios/src/palacios/vmm_packet.c with 98% similarity]
palacios/src/interfaces/vmm_socket.c [moved from palacios/src/palacios/vmm_socket.c with 99% similarity]
palacios/src/interfaces/vmm_stream.c [moved from palacios/src/palacios/vmm_stream.c with 97% similarity]
palacios/src/palacios/Makefile
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_emulator.c
palacios/src/palacios/vmm_mem_hook.c
palacios/src/palacios/vmm_v3dec.c
palacios/src/palacios/vmm_xed.c

diff --git a/Kconfig b/Kconfig
index b7f64e1..7a48606 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -125,52 +125,9 @@ config MAX_CPUS
          Specifies the maximum number of hardware CPUs supported by the OS
          For uniprocessor environments, set this to 1
 
-config FILE
-       bool "Host Support for file operations"
-       default n
-       help
-         Select this if your host OS supports file operatoins and you want Palacios to be able to use them.
-
-config KEYED_STREAMS
-       bool "Host support for keyed streams"
-       default n
-       help
-         Select this if your host OS supports keyed streams
-          Palacios Checkpoint/Restore and Migration depends on this feature
-
-config CONSOLE
-       bool "Host Support for VM text-mode console"
-       default n
-       help 
-         Select this if you want to forward a guest console interface to some host OS service
-          This is for a TEXT MODE console.   Select the framebuffer console for graphics and text
-
-config GRAPHICS_CONSOLE
-       bool "Host Support for VM graphics and text-mode console based on a frame buffer"
-       default n
-       help 
-         Select this if you want to forward a guest graphics-mode (and text-mode) console 
-          interface to some host OS service.  This is for a GRAPHICS console based on a shared frame buffer.
-          Text mode output is RENDERED onto the framebuffer
-
-config SOCKET
-        bool "Host support for Network Sockets"
-        default y
-        help
-          Select this if you host OS implements a socket API that is available to Palacios. This is required
-          to support the internal networking features of Palacios.
-
-
-config PACKET
-       bool "Host support for Raw Packet Transmision"
-       depends on EXPERIMENTAL
-       default n
-       help 
-         Select this if you host OS implements a raw packet network API that is available to Palacios. This is required 
-         to support the internal networking features of Palacios.
-
 endmenu
 
+source "palacios/src/interfaces/Kconfig"
 
 
 config TELEMETRY
index 360dbd6..46227ae 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -434,6 +434,7 @@ scripts_basic: palacios/include/autoconf.h
 core-y          := palacios/src/palacios/
 libs-y         := palacios/lib/$(ARCH)/
 devices-y       := palacios/src/devices/
+interfaces-y    := palacios/src/interfaces/
 modules-y       := modules/
 
 
@@ -528,7 +529,7 @@ export      INSTALL_PATH ?= /build
 
 
 palacios-dirs  := $(patsubst %/,%,$(filter %/,  \
-                    $(core-y) $(devices-y) $(libs-y)) $(modules-y))
+                    $(core-y) $(devices-y) $(interfaces-y) $(libs-y)) $(modules-y))
 
 
 
@@ -538,12 +539,14 @@ palacios-dirs     := $(patsubst %/,%,$(filter %/,  \
 
 
 palacios-cleandirs := $(sort $(palacios-dirs) $(patsubst %/,%,$(filter %/, \
-                       $(core-n) $(core-) $(devices-n) $(devices-) $(modules-n) $(modules-))))
+                       $(core-n) $(core-) $(devices-n) $(devices-) \
+                       $(interfaces-n) $(interfaces-) $(modules-n) $(modules-))))
 
 
 
 core-y         := $(patsubst %/, %/built-in.o, $(core-y))
 devices-y      := $(patsubst %/, %/built-in.o, $(devices-y))
+interfaces-y    := $(patsubst %/, %/built-in.o, $(interfaces-y))
 libs-y         := $(patsubst %/, %/built-in.o, $(libs-y))
 modules-y       := $(patsubst %/, %/built-in.o, $(modules-y))
 #lnxmod-y        := $(patsubst %/, %/built-in.o, $(lnxmod-y))
@@ -570,7 +573,7 @@ modules-y       := $(patsubst %/, %/built-in.o, $(modules-y))
 
 
 
-palacios := $(core-y) $(devices-y) $(libs-y) $(modules-y)
+palacios := $(core-y) $(devices-y) $(interfaces-y) $(libs-y) $(modules-y)
 
 
 # Rule to link palacios - also used during CONFIG_CONFIGKALLSYMS
index f20fb08..181df3c 100644 (file)
@@ -8,14 +8,15 @@ v3vee-objs:=  palacios.o \
                palacios-dev.o \
                palacios-vm.o \
                palacios-file.o \
-               palacios-stream.o \
                palacios-console.o \
                palacios-mm.o \
                palacios-serial.o \
+               palacios-stream.o \
                palacios-queue.o \
                palacios-ringbuffer.o \
                palacios-debugfs.o
 
+
 ifdef CONFIG_PALACIOS_VNET
                v3vee-objs += palacios-vnet.o           
 endif
index cc6d80e..7ba96bd 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/file.h>
 #include <linux/sched.h>
 
-#include <palacios/vmm_console.h>
+#include <interfaces/vmm_console.h>
 #include <palacios/vmm_host_events.h>
 
 #include "palacios.h"
index ed0b410..2f414b5 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "palacios.h"
 
-#include <palacios/vmm_file.h>
+#include <interfaces/vmm_file.h>
 
 static struct list_head global_files;
 
index 0fc3a9f..1907507 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/errno.h>
 #include <asm/msr.h>
  
-#include <palacios/vmm_packet.h>
+#include <interfaces/vmm_packet.h>
 #include <palacios/vmm_host_events.h>
 #include <palacios/vmm_vnet.h>
 #include <palacios/vmm_ethernet.h>
index d76c5c6..28b613f 100644 (file)
@@ -17,7 +17,7 @@
  * full text of the license.
  */
 
-#include <palacios/vmm_socket.h>
+#include <interfaces/vmm_socket.h>
 
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
index 702475c..e79f093 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/percpu.h>
 #include <linux/sched.h>
 
-#include <palacios/vmm_stream.h>
+#include <interfaces/vmm_stream.h>
 #include "palacios-stream.h"
 
 static struct list_head global_streams;
diff --git a/palacios/include/interfaces/vmm_host_dev.h b/palacios/include/interfaces/vmm_host_dev.h
new file mode 100644 (file)
index 0000000..9f7ea91
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2011, Peter Dinda <pdinda@northwestern.edu> 
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Peter Dinda <pdinda@northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#ifndef __VMM_HOST_DEV_H__
+#define __VMM_HOST_DEV_H__
+
+#include <palacios/vmm.h>
+
+
+/*
+
+  The purpose of this interface is to make it possible to implement
+  virtual devices in the host OS.   It is intended to be used by 
+  passthrough device implementations, such as the generic device 
+  and the PCI passthrough device.  
+
+  One use of this interface, and the generic and PCI passthrough devices
+  might be to build an interface with simulated devices in SST 
+  under a Linux host.  That scenario would look like this:
+
+Guest config:
+
+  generic device:
+    <device class="generic" id="mydev" impl="host_sst">
+       ports, memory regions, interrupts set with PASSTHROUGH option 
+    </device>
+
+  PCI passthrough devive:
+    <device class="pci_passthrough" id="mydev", impl="host_sst">
+       vendor and device ids, etc
+    </device>
+
+impl="physical" or lack of an impl key would indicate that direct hardware
+access is expected, which is how these devices currently operate. 
+
+
+Host (Linux) side:
+
+    There would be an implementation and registration of the hooks 
+    defined and explained in this file
+
+    The implementation might, for example, create an interface to 
+    a user space process, for example like the console 
+    (palacios-console.[ch] + v3_cons.c) or graphics console
+    (palacios-graphics-console.[ch] + v3_vncserver.c) do
+    and route the hook functions defined here through it. 
+    Through this interface, the calls could be routed to an SST
+    device module.   
+
+*/
+
+
+/* A host device is opaque to the palacios */
+typedef void * v3_host_dev_t;
+/* A guest device is opaque to the host */
+typedef void * v3_guest_dev_t;
+
+
+/* There is a notion of a bus class to which the device is attached */
+typedef enum { DIRECT, PCI } v3_bus_class_t;
+
+#ifdef __V3VEE__
+
+v3_host_dev_t v3_host_dev_open(char *impl, 
+                              v3_bus_class_t bus,
+                              v3_guest_dev_t gdev); 
+
+uin64_t v3_host_dev_read_io(v3_host_dev_t hostdev, 
+                           uint16_t      port,
+                           void          *dest
+                           uint64_t      len);
+
+uint64_t v3_host_dev_write_io(v3_host_dev_t hostdev, 
+                             uint16_t      port,
+                             void          *src,
+                             uint64_t      len);
+
+uint64_t v3_host_dev_read_mem(v3_host_dev_t hostdev, 
+                             addr_t        gpa,
+                             void          *dest,
+                             uint64_t      len);
+
+uint64_t v3_host_dev_write_mem(v3_host_dev_t hostdev, 
+                              addr_t        gpa,
+                              void          *src,
+                              uint64_t      len);
+
+int v3_host_dev_ack_irq(v3_host_dev_t hostdev, uint32_t irq);
+
+uint64_t v3_host_dev_config_read(v3_host_dev_t hostdev, 
+                                void          *dest,
+                                uint64_t      len);
+
+uint64_t v3_host_dev_config_write(v3_host_dev_t hostdev, 
+                                 void          *src,
+                                 uint64_t      len);
+#endif
+
+struct v3_host_dev_hooks {
+    
+    // The host is given the implementation name, the type of bus
+    // this device is attached to and an opaque pointer back to the
+    // guest device.  It returns an opaque representation of 
+    // the host device it has attached to, with zero indicating
+    // failure
+    v3_host_dev_t (*open)(char *impl, 
+                         v3_bus_class_t bus,
+                         v3_guest_dev_t gdev);
+    
+    // Read/Write from/to an IO port. The read must either
+    // completely succeed, returning len or completely
+    // fail, returning != len
+    // Callee gets the host dev id and the port in the guest
+    uint64_t (*read_io)(v3_host_dev_t hostdev, 
+                       uint16_t      port,
+                       void          *dest
+                       uint64_t      len);
+
+    uint64_t (*write_io)(v3_host_dev_t hostdev, 
+                        uint16_t      port,
+                        void          *src,
+                        uint64_t      len);
+    
+    // Read/Write from/to memory. The reads/writes must
+    // completely succeed, returning len or completely
+    // fail, returning != len
+    // Callee gets the host dev id, and the guest physical address
+    uint64_t (*read_mem)(v3_host_dev_t hostdev, 
+                        addr_t        gpa,
+                        void          *dest,
+                        uint64_t      len);
+    
+    uint64_t (*write_mem)(v3_host_dev_t hostdev, 
+                         addr_t        gpa,
+                         void          *src,
+                         uint64_t      len);
+    
+    // Palacis will call this when it has taken posession of the 
+    // IRQ ad wants the host device to lower it
+    // This interface is unclear 
+    // 
+    // One potential use would be to allow for a palacios
+    // side device to raise the irq asynchronously from
+    // the host device.  If this is permitted, then we
+    // need a way of informing the host device that the
+    // irq has actually been signalled.
+    int (*ack_irq)(v3_host_dev_t hostdev, uint8_t irq);
+
+    // Configuration space reads/writes for devices that
+    // have them, such as PCI devices
+    // As with other reads/writes, these must be fully successful
+    // or fail
+    //
+    // Palacios maintains its own configuration for some
+    // devices (e.g., pci_passthrough) and will take care of 
+    // relevant hooking/unhooking, and maintain its own
+    // config space info.   However, a read will return
+    // the host device's config, while a write will affect
+    // both the palacios-internal config and the hsot device's config
+    uint64_t (*config_read)(v3_host_dev_t hostdev, 
+                           void          *dest,
+                           uint64_t      len);
+
+    uint64_t (*config_write)(v3_host_dev_t hostdev, 
+                            void          *src,
+                            uint64_t      len);
+};
+
+/* This function is how the host will raise an irq to palacios
+   for the device.   The IRQ argument will be ignored for devices
+   whose irqs are managed by palacios */
+int v3_host_dev_raise_irq(v3_host_dev_t hostdev,
+                         v3_guest_dev_t guest_dev,
+                         uint8_t irq);
+
+/* These functions allow the host to read and write the guest
+   memory by physical address, for example to implement DMA 
+
+   These functions are incremental - that is, they can return
+   a smaller amount than requested
+*/
+uint64_t v3_host_dev_read_guest_mem(v3_host_dev_t  hostdev,
+                                   v3_guest_dev_t guest_dev,
+                                   addr_t         gpa,
+                                   void           *dest,
+                                   uint64_t       len);
+
+uint64_t v3_host_dev_write_guest_mem(v3_host_dev_t  hostdev,
+                                    v3_guest_dev_t guest_dev,
+                                    addr_t         gpa,
+                                    void           *src,
+                                    uint64_t       len);
+                             
+
+extern void V3_Init_Host_Device_Support(struct v3_host_dev_hooks *hooks);
+
+#endif
index 3631e14..aba2d40 100644 (file)
@@ -43,9 +43,9 @@ struct x86_operand {
     addr_t operand;
     uint_t size;
     v3_operand_type_t type;
-    uint8_t read : 1;
-    uint8_t write : 1;
-};
+    uint8_t read : 1;   // This operand value will be read by the instruction
+    uint8_t write : 1;  // This operand value will be written to by the instruction
+} __attribute__((packed));
 
 struct x86_prefixes {
     uint_t lock   : 1;  // 0xF0
index cd1d2ef..e789207 100644 (file)
@@ -29,7 +29,6 @@
 #include <palacios/vmm_msr.h>
 #include <palacios/vmm_config.h>
 #include <palacios/vmm_ethernet.h>
-#include <palacios/vmm_keyed_stream.h>
 
 struct v3_vm_info;
 
@@ -103,11 +102,17 @@ int V3_init_devices();
 int V3_deinit_devices();
 
 
+#ifdef CONFIG_KEYED_STREAMS
+#include <interfaces/vmm_keyed_stream.h>
+#endif 
+
 struct v3_device_ops {
     int (*free)(void * private_data);
 
+#ifdef CONFIG_KEYED_STREAMS
     int (*checkpoint)(struct vm_device *dev, v3_keyed_stream_t stream);
     int (*restore)(struct vm_device *dev, v3_keyed_stream_t stream);
+#endif
 };
 
 
index 2bf4841..f0c762d 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #include <palacios/vmm.h>
-#include <palacios/vmm_stream.h>
+#include <interfaces/vmm_stream.h>
 #include <palacios/vmm_dev_mgr.h>
 #include <palacios/vmm_sprintf.h>
 #include <palacios/vmm_host_events.h>
index ca1e0ba..e9d27be 100644 (file)
@@ -28,7 +28,7 @@
 #include <palacios/vmm_paging.h>
 #include <palacios/vmm_instr_emulator.h>
 #include <palacios/vm_guest_mem.h>
-#include <palacios/vmm_socket.h>
+#include <interfaces/vmm_socket.h>
 #include <palacios/vmm_host_events.h>
 #include <devices/pci.h>
 #include <devices/pci_types.h>
index aa85972..e71cb51 100644 (file)
@@ -21,7 +21,7 @@
 /* Interface between virtual video card and console */
 
 #include <palacios/vmm.h>
-#include <palacios/vmm_console.h>
+#include <interfaces/vmm_console.h>
 #include <palacios/vmm_dev_mgr.h>
 #include <palacios/vmm_sprintf.h>
 #include <palacios/vmm_host_events.h>
index b007ace..629b4ed 100644 (file)
@@ -20,7 +20,7 @@
 #include <palacios/vmm.h>
 #include <palacios/vmm_dev_mgr.h>
 
-#include <palacios/vmm_file.h>
+#include <interfaces/vmm_file.h>
 #include <palacios/vm_guest.h>
 
 #ifndef CONFIG_DEBUG_FILEDISK
index fd80bcd..9a1509a 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <palacios/vmm.h>
 #include <palacios/vmm_dev_mgr.h>
-#include <palacios/vmm_socket.h>
+#include <interfaces/vmm_socket.h>
 
 #ifndef CONFIG_DEBUG_IDE
 #undef PrintDebug
index ed1cd92..9bc28d2 100644 (file)
@@ -23,7 +23,7 @@
 #include <palacios/vmm_dev_mgr.h>
 #include <palacios/vm_guest_mem.h>
 #include <palacios/vmm_sprintf.h>
-#include <palacios/vmm_packet.h>
+#include <interfaces/vmm_packet.h>
 
 #ifndef CONFIG_DEBUG_NIC_BRIDGE
 #undef PrintDebug
index b155849..7bda58b 100644 (file)
@@ -27,7 +27,7 @@
 #include <palacios/vmm_host_events.h>
 #include <palacios/vmm_lock.h>
 #include <palacios/vmm_string.h>
-#include <palacios/vmm_socket.h>
+#include <interfaces/vmm_socket.h>
 
 #include <devices/console.h>
 
index b7b0a36..834f780 100644 (file)
@@ -22,7 +22,7 @@
 #include <palacios/vmm_types.h>
 #include <palacios/vm_guest_mem.h>
 #include <palacios/vmm_io.h>
-#include <palacios/vmm_graphics_console.h>
+#include <interfaces/vmm_graphics_console.h>
 
 #include "vga_regs.h"
 
@@ -82,6 +82,10 @@ typedef uint8_t *vga_map; // points to MAP_SIZE data
 
 #define VGA_DAC_NUM_ENTRIES 256
 
+
+#define VGA_FONT_WIDTH      8
+#define VGA_MAX_FONT_HEIGHT 32
+
 struct vga_misc_regs {
     /* Read: 0x3cc; Write: 0x3c2 */
     struct vga_misc_out_reg        vga_misc_out;
@@ -148,7 +152,7 @@ struct vga_crt_controller_regs {
     /* index 8 */
     struct vga_preset_row_scan_reg vga_preset_row_scan;
     /* index 9 */
-    struct vga_max_row_scan_reg vga_row_scan;
+    struct vga_max_row_scan_reg vga_max_row_scan;
     /* index 10 */
     struct vga_cursor_start_reg vga_cursor_start;
     /* index 11 */
@@ -166,7 +170,7 @@ struct vga_crt_controller_regs {
     /* index 17 */
     struct vga_vertical_retrace_end_reg vga_vertical_retrace_end;
     /* index 18 */
-    vga_vertical_display_enable_end_reg vga_vertical_display_enable;
+    vga_vertical_display_enable_end_reg vga_vertical_display_enable_end;
     /* index 19 */
     vga_offset_reg vga_offset;
     /* index 20 */
@@ -317,51 +321,459 @@ struct vga_internal {
 
 
 
-static int render(struct vga_internal *vga)
+static void find_text_char_dim(struct vga_internal *vga, uint32_t *w, uint32_t *h)
 {
-    vga->updates_since_render++;
+    *w = (vga->vga_sequencer.vga_clocking_mode.dot8 ? 8 : 9);
 
-    if (vga->host_cons && v3_graphics_console_inform_update(vga->host_cons)>0) { 
-       // Draw some crap for testing for now
+    *h = vga->vga_crt_controller.vga_max_row_scan.max_scan_line+1;
 
-       void *fb;
-       struct v3_frame_buffer_spec *s;
+}
 
-       fb = v3_graphics_console_get_frame_buffer_data_rw(vga->host_cons,&(vga->target_spec));
+static void find_text_res(struct vga_internal *vga, uint32_t *width, uint32_t *height)
+{
+    uint32_t vert_lsb, vert_msb;
+    uint32_t ph;
+    uint32_t ch, cw;
+
+    *width = (vga->vga_crt_controller.vga_horizontal_display_enable_end + 1) 
+       - vga->vga_crt_controller.vga_end_horizontal_blanking.display_enable_skew;
+
+    vert_lsb = vga->vga_crt_controller.vga_vertical_display_enable_end; // 8 bits here
+    vert_msb = (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end9 << 1)  // 2 bits here
+       + (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end8);
+              
+    ph  = ( (vert_msb << 8) + vert_lsb + 1) ; // pixels high (scanlines)
+
+    find_text_char_dim(vga,&cw, &ch);
+
+    *height = ph / ch; 
+
+}
+
+
+static void find_text_data_start(struct vga_internal *vga, void **data)
+{
+    uint32_t offset;
+
+    offset = vga->vga_crt_controller.vga_start_address_high;
+    offset <<= 8;
+    offset += vga->vga_crt_controller.vga_start_address_low;
+
+    *data = vga->map[0]+offset;
+
+}
+
+static void find_text_attr_start(struct vga_internal *vga, void **data)
+{
+    uint32_t offset;
+
+    offset = vga->vga_crt_controller.vga_start_address_high;
+    offset <<= 8;
+    offset += vga->vga_crt_controller.vga_start_address_low;
+
+    *data = vga->map[1]+offset;
+
+}
+
+static void find_text_cursor_pos(struct vga_internal *vga, uint32_t *x, uint32_t *y, void **data)
+{
+    uint32_t w,h;
+    uint32_t offset;
+    uint32_t charsin;
+    void *buf;
+
+    find_text_res(vga,&w,&h);
+
+    find_text_data_start(vga,&buf);
+
+    offset = vga->vga_crt_controller.vga_cursor_location_high;
+    offset <<= 8;
+    offset += vga->vga_crt_controller.vga_cursor_location_low;
+
+    *data = vga->map[0]+offset;
+
+    charsin = (uint32_t)(*data - buf);
+    
+    *x = charsin % w;
+    *y = charsin / w;
+        
+}
+
+
+static void find_text_font_start(struct vga_internal *vga, void **data, uint8_t char_map)
+{
+    uint32_t mapa_offset, mapb_offset;
+
+
+    switch (char_map) { 
+       case 0:
+           mapa_offset = (vga->vga_sequencer.vga_char_map_select.char_map_a_sel_lsb << 1)
+                          + vga->vga_sequencer.vga_char_map_select.char_map_a_sel_msb ;
+           *data = vga->map[2] + mapa_offset;
+           break;
+           
+       case 1:
+           mapb_offset = (vga->vga_sequencer.vga_char_map_select.char_map_b_sel_lsb << 1)
+                          + vga->vga_sequencer.vga_char_map_select.char_map_b_sel_msb ;
+           *data = vga->map[2] + mapb_offset;
+           break;
+       default:
+           PrintError("vga: unknown char_map given to find_text_font_start\n");
+           break;
+           
+    }
+}
+
+static int extended_fontset(struct vga_internal *vga)
+{
+    if (vga->vga_sequencer.vga_mem_mode.extended_memory &&
+       ! ( (vga->vga_sequencer.vga_char_map_select.char_map_a_sel_lsb 
+            == vga->vga_sequencer.vga_char_map_select.char_map_b_sel_lsb) &&
+           (vga->vga_sequencer.vga_char_map_select.char_map_a_sel_msb 
+            == vga->vga_sequencer.vga_char_map_select.char_map_b_sel_msb))) { 
+       return 1;
+    } else {
+       return 0;
+    }
+
+}
+
+static int blinking(struct vga_internal *vga)
+{
+    return vga->vga_attribute_controller.vga_attribute_mode_control.enable_blink;
+}
+
+
+static void find_graphics_res(struct vga_internal *vga, uint32_t *width, uint32_t *height)
+{
+    uint32_t vert_lsb, vert_msb;
+
+    *width = ((vga->vga_crt_controller.vga_horizontal_display_enable_end + 1) 
+             - vga->vga_crt_controller.vga_end_horizontal_blanking.display_enable_skew);
+
+    *width *= (vga->vga_sequencer.vga_clocking_mode.dot8 ? 8 : 9);
 
-       s=&(vga->target_spec);
+    vert_lsb = vga->vga_crt_controller.vga_vertical_display_enable_end; // 8 bits here
+    vert_msb = (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end9 << 1)  // 2 bits here
+       + (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end8);
+              
+    *height  = ( (vert_msb << 8) + vert_lsb + 1) ; // pixels high (scanlines)
+    
+}
+
+
+static void find_graphics_cursor_pos(struct vga_internal *vga, uint32_t *width, uint32_t *height)
+{
+
+}
+
+static void render_graphics(struct vga_internal *vga, void *fb)
+{
+
+    PrintDebug("vga: render_graphics is unimplemented\n");
+    // Multiuplane 16
+    // Packed pixel mono
+    // packed pixel 4 color
+    // packed pixel 256 color
+
+    find_graphics_cursor_pos(0,0,0);
+
+}
+
+static void render_text_cursor(struct vga_internal *vga, void *fb)
+{
+}
+
+
+
+static void dac_lookup_24bit_color(struct vga_internal *vga,
+                                  uint8_t entry,
+                                  uint8_t *red,
+                                  uint8_t *green,
+                                  uint8_t *blue)
+{
+    // use internal or external palette?
+
+    vga_palette_reg *r = &(vga->vga_dac.vga_dac_palette[entry]);
+
+    // converting from 6 bits to 8 bits so << 2
+    *red = (*r & 0x3f) << 2;
+    *green = ((*r >> 8) & 0x3f) << 2;
+    *blue = ((*r >> 16) & 0x3f) << 2;
+
+}
+
+//
+// A variant of this function could render to
+// a text console interface as well
+//
+static void render_text(struct vga_internal *vga, void *fb)
+{
+    // line graphics enable bit means to  dupe column 8 to 9 when
+    // in 9 dot wide mode
+    // otherwise 9th dot is background
+
+    struct v3_frame_buffer_spec *spec = &(vga->target_spec);
+
+    uint32_t gw, gh; // graphics w/h
+    uint32_t tw, th; // text w/h
+    uint32_t rtw, rth; // rendered text w/h
+    uint32_t cw, ch; // char font w/h including 8/9
+    uint32_t fw, fh; // fb w/h
+
+    uint32_t px, py; // cursor position
+    
+    uint32_t x, y, l, p; // text location, line and pixel within the char
+    uint32_t fx, fy;     // pixel position within the frame buffer
+    
+    uint8_t *text_start; 
+    uint8_t *text;    // points to current char
+    uint8_t *attr;    // and its matching attribute
+    uint8_t *curs;    // to where the cursor is
+    uint8_t *font;    // to where the current font is
+
+    uint8_t fg_entry; // foreground color entry
+    uint8_t bg_entry; // background color entry
+    uint8_t fgr,fgg,fgb;    // looked up  foreground colors
+    uint8_t bgr,bgg,bgb;    // looked up  bg colors
+
+    uint8_t ct, ca;   // the current char and attribute
+    struct vga_attribute_byte a; // decoded attribute
 
-       if (fb && s->height>=480 && s->width>=640 ) { 
-           uint8_t color = (uint8_t)(vga->updates_since_render);
+    void *pixel;      // current pixel in the fb
+    uint8_t *red;     // and the channels in the pixel
+    uint8_t *green;   //
+    uint8_t *blue;    //
 
-           uint32_t x, y;
+    
+
+    find_graphics_res(vga,&gw,&gh);
+    find_text_res(vga,&tw,&th);
+    find_text_char_dim(vga,&cw,&ch);
+    fw = spec->width;
+    fh = spec->height;
+
+    find_text_cursor_pos(vga,&px,&py,(void**)&curs);
+    find_text_data_start(vga,(void**)&text);
+    find_text_attr_start(vga,(void**)&attr);
+
+    find_text_font_start(vga,(void**)&font,0); // will need to switch this as we go since it is part of attr
+
+    PrintDebug("vga: attempting text render: graphics_res=(%u,%u), fb_res=(%u,%u), text_res=(%u,%u), "
+              "char_res=(%u,%u), cursor=(%u,%u) font=0x%p, text=0x%p, attr=0x%p, curs=0x%p, fb=0x%p"
+              "graphics extension=%u, extended_fontset=%d, blinking=%d\n",
+              gw,gh,fw,fh,tw,th,cw,ch,px,py,font,text,attr,curs,fb,
+              vga->vga_attribute_controller.vga_attribute_mode_control.enable_line_graphics_char_code,
+              extended_fontset(vga), blinking(vga));
+
+    text_start=text;
+
+    // First we need to clip to what we can actually show
+    rtw = tw < fw/cw ? tw : fw/cw;
+    rth = th < fh/ch ? th : fh/ch;
+
+    
+
+    // Now let's scan by char across the whole thing
+    for (y=0;y<th;y++) { 
+       for (x=0;x<tw;x++, text++, attr++) { 
+           if (x < rtw && y < rth) { 
+               // grab the character and attribute for the position
+               ct = *text; 
+               ca = *attr;  
+               a.val = ca;
+
+               // find the character's font bitmap (one byte per row)
+               find_text_font_start(vga,(void**)&font,
+                                    extended_fontset(vga) ? a.foreground_intensity_or_font_select : 0 ); 
+
+               font += ct * ((VGA_MAX_FONT_HEIGHT * VGA_FONT_WIDTH)/8);
+
+               // Now let's find out what colors we will be using
+               // foreground
+               
+               if (!extended_fontset(vga)) { 
+                   fg_entry = ((uint8_t)(a.foreground_intensity_or_font_select)) << 3;
+               } else {
+                   fg_entry = 0;
+               }
+               fg_entry |= a.fore;
+
+               dac_lookup_24bit_color(vga,fg_entry,&fgr,&fgg,&fgb);
+
+               if (!blinking(vga)) { 
+                   bg_entry = ((uint8_t)(a.blinking_or_bg_intensity)) << 3;
+               } else {
+                   bg_entry = 0;
+               }
+               bg_entry |= a.back;
+               
+               dac_lookup_24bit_color(vga,bg_entry,&bgr,&bgg,&bgb);
+
+               // Draw the character
+               for (l=0; l<ch; l++, font++) {
+                   uint8_t frow = *font;  // this is the row of of the font map
+                   for (p=0;p<cw;p++) {
+                       uint8_t fbit;
+                       
+                       // a char can be 9 bits wide, but the font map
+                       // is only 8 bits wide, which means we need to know where to
+                       // get the 9th bit
+                       if (p >= 8) { 
+                           // We get it from the font map if
+                           // its line line graphics mode and its a graphics char
+                           // otherwise it's the background color
+                           if (vga->vga_attribute_controller.vga_attribute_mode_control.enable_line_graphics_char_code
+                               && ct>=0xc0 && ct<=0xdf ) { 
+                               fbit = frow & 0x1;
+                           } else {
+                               fbit = 0;
+                           }
+                       } else {
+                           fbit= (frow >> (7-p) ) & 0x1;
+                       }
+                       
+                       // We are now at the pixel level, with fbit being the pixel we draw (color+attr or bg+attr)
+                       // For now, we will draw it as black/white
+
+                       // find its position in the framebuffer;
+                       fx = x*cw + p;
+                       fy = y*ch + l;
+                       pixel =  fb + ((fx + (fy*spec->width)) * spec->bytes_per_pixel);
+                       red = pixel + spec->red_offset;
+                       green = pixel + spec->green_offset;
+                       blue = pixel + spec->blue_offset;
+
+                       // Are we on the cursor?
+                       // if so, let's negate this pixel to invert the cell
+                       if (curs==text) { 
+                           fbit^=0x1;
+                       }
+                       // update the framebuffer
+                       if (fbit) { 
+                           *red=fgr; 
+                           *green=fgg;
+                           *blue=fgb;
+                       } else {
+                           *red=bgr;
+                           *green=bgg;
+                           *blue=bgb;
+                       }
+                   }
+               }
+           }
+       }
+       PrintDebug("\n");
+    }
+
+}
+
+                       
+                       
 
-           for (y=0;y<480;y++) {
-               for (x=0;x<640;x++) { 
-                   void *pixel = fb + (x + y*s->width) *s->bytes_per_pixel;
+
+static void render_test(struct vga_internal *vga, void *fb)
+{
+    struct v3_frame_buffer_spec *s;
+
+    s=&(vga->target_spec);
+
+    if (fb && s->height>=480 && s->width>=640 ) { 
+       uint8_t color = (uint8_t)(vga->updates_since_render);
+       
+       uint32_t x, y;
+       
+       for (y=0;y<480;y++) {
+           for (x=0;x<640;x++) { 
+               void *pixel = fb + ((x + (y*s->width)) * s->bytes_per_pixel);
+               uint8_t *red = pixel + s->red_offset;
+               uint8_t *green = pixel + s->green_offset;
+               uint8_t *blue = pixel + s->blue_offset;
+               
+               if (y<(480/4)) { 
+                   *red=color+x;
+                   *green=0;
+                   *blue=0;
+               } else if (y<(480/2)) { 
+                   *red=0;
+                   *green=color+x;
+                   *blue=0;
+               } else if (y<(3*(480/4))) { 
+                   *red=0;
+                   *green=0;
+                   *blue=color+x;
+               } else {
+                   *red=*green=*blue=color+x;
+               }
+           }
+       }
+    }
+}
+
+static void render_maps(struct vga_internal *vga, void *fb)
+{
+
+    struct v3_frame_buffer_spec *s;
+    
+
+    s=&(vga->target_spec);
+
+    if (fb && s->height>=768 && s->width>=1024 && !(vga->updates_since_render % 100)) { 
+       // we draw the maps next, each being a 256x256 block appearing 32 pixels below the display block
+       uint8_t m;
+       uint32_t x,y;
+       uint8_t *b;
+       
+       for (m=0;m<4;m++) { 
+           b=(vga->map[m]);
+           for (y=480+32;y<768;y++) { 
+               for (x=m*256;x<(m+1)*256;x++,b++) { 
+                   void *pixel = fb + ((x + (y*s->width)) * s->bytes_per_pixel);
                    uint8_t *red = pixel + s->red_offset;
                    uint8_t *green = pixel + s->green_offset;
                    uint8_t *blue = pixel + s->blue_offset;
-
-                   if (y<480/4) { 
-                       *red=color+x;
-                       *green=0;
-                       *blue=0;
-                   } else if (y<480/2) { 
-                       *red=0;
-                       *green=color+x;
-                       *blue=0;
-                   } else if (y<3*480/4) { 
-                       *red=0;
-                       *green=0;
-                       *blue=color+x;
-                   } else {
-                       *red=*green=*blue=color+x;
-                   }
+                   
+                   *red=*green=*blue=*b;
                }
            }
        }
     }
+}
+
+
+static int render(struct vga_internal *vga)
+{
+    void *fb;
+
+
+    vga->updates_since_render++;
+
+    if (vga->updates_since_render%100) { 
+       // skip render
+       return 0;
+    }
+
+    if (vga->host_cons && v3_graphics_console_inform_update(vga->host_cons)>0) { 
+
+       fb = v3_graphics_console_get_frame_buffer_data_rw(vga->host_cons,&(vga->target_spec));
+
+       // Draw some crap for testing for now
+       if (0) { render_test(vga,fb);}
+       // Draw the maps for debugging
+       if (0) { render_maps(vga,fb);}
+
+       if (vga->vga_graphics_controller.vga_misc.graphics_mode) { 
+           render_graphics(vga,fb);
+       } else {
+           render_text(vga,fb);
+           render_text_cursor(vga,fb);
+       }
+
+       render_maps(vga,fb);
+
+
+       v3_graphics_console_release_frame_buffer_data_rw(vga->host_cons);
+    }
 
     return 0;
 }
@@ -389,19 +801,57 @@ static void get_mem_region(struct vga_internal *vga, uint64_t *mem_start, uint64
     }
 }
 
-static uint64_t find_offset(struct vga_internal *vga, addr_t guest_addr)
+static uint64_t find_offset_write(struct vga_internal *vga, addr_t guest_addr)
 {
     uint64_t mem_start, mem_end;
+    uint64_t size;
     
     mem_start=mem_end=0;
     
     get_mem_region(vga, &mem_start, &mem_end);
+    
+    size=(mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start)); 
 
-    return (guest_addr-mem_start) % (mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start)); 
-
+    if (vga->vga_sequencer.vga_mem_mode.odd_even) { 
+       return (guest_addr-mem_start) % size;
+    } else {
+       // odd/even mode
+       return ((guest_addr-mem_start) >> 1 ) % size;
+    }
 }
 
+
+
     
+// Determines which maps should be enabled for this single byte write
+// and what the increment (actually 1/increment for the copy loop
+//
+//  memory_mode.odd_even == 0 => even address = maps 0 and 2 enabled; 1,3 otherwise
+//  
+static uint8_t find_map_write(struct vga_internal *vga, addr_t guest_addr)
+{
+    uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+
+    if (vga->vga_sequencer.vga_mem_mode.odd_even) { 
+       return mm;
+    } else {
+       if (guest_addr & 0x1) { 
+           return mm & 0xa;  // 0x1010
+       } else {
+           return mm & 0x5;  // 0x0101
+       }
+    }
+}
+
+static uint8_t find_increment_write(struct vga_internal *vga, addr_t new_guest_addr)
+{
+    if (vga->vga_sequencer.vga_mem_mode.odd_even) { 
+       return 1;
+    } else {
+       return !(new_guest_addr & 0x1);
+    }
+}
+
 
 
 static int vga_write(struct guest_info * core, 
@@ -410,7 +860,6 @@ static int vga_write(struct guest_info * core,
                     uint_t length, 
                     void * priv_data)
 {
-    int i;
     struct vm_device *dev = (struct vm_device *)priv_data;
     struct vga_internal *vga = (struct vga_internal *) dev->private_data;
 
@@ -421,15 +870,28 @@ static int vga_write(struct guest_info * core,
        memcpy(V3_VAddr((void*)guest_addr),src,length);
     }
     
-    PrintDebug("vga: data written was \"");
+#if 0
+    int i;
+    PrintDebug("vga: data written was 0x");
+    for (i=0;i<length;i++) {
+       uint8_t c= ((char*)src)[i];
+       PrintDebug("%.2x", c);
+    }
+    PrintDebug(" \"");
     for (i=0;i<length;i++) {
        char c= ((char*)src)[i];
-       PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') ? c : '.');
+       PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || (c==' ') ? c : '.');
     }
     PrintDebug("\"\n");
+#endif
 
     /* Write mode determine by Graphics Mode Register (Index 05h).writemode */
-    
+
+    // Probably need to add odd/even mode access here for text
+
+    PrintDebug("vga: write is with odd/even = %u\n", vga->vga_sequencer.vga_mem_mode.odd_even);
+
+
     switch (vga->vga_graphics_controller.vga_graphics_mode.write_mode) {
        case 0: {
            
@@ -452,16 +914,18 @@ static int vga_write(struct guest_info * core,
            uint8_t ror = vga->vga_graphics_controller.vga_data_rotate.rotate_count;
            uint8_t func = vga->vga_graphics_controller.vga_data_rotate.function;
            
-           offset = find_offset(vga, guest_addr);
+           offset = find_offset_write(vga, guest_addr);
 
            PrintDebug("vga: mode 0 write, offset=0x%llx, ror=%u, func=%u\n", offset,ror,func);
 
-           for (i=0;i<length;i++,offset++) { 
+           for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) { 
                // now for each map
                uint8_t sr = vga->vga_graphics_controller.vga_set_reset.val & 0xf;
                uint8_t esr = vga->vga_graphics_controller.vga_enable_set_reset.val &0xf;
                uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
-               uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+               uint8_t mm = find_map_write(vga,guest_addr+i);
+
+               PrintDebug("vga: write i=%u, mm=0x%x, offset=0x%x\n",i,(unsigned int)mm,(unsigned int)offset);
 
                for (mapnum=0;mapnum<4;mapnum++, sr>>=1, esr>>=1, bm>>=1, mm>>=1) { 
                    vga_map map = vga->map[mapnum];
@@ -523,14 +987,14 @@ static int vga_write(struct guest_info * core,
 
            int i;
 
-           uint64_t offset = find_offset(vga,guest_addr);
+           uint64_t offset = find_offset_write(vga,guest_addr);
 
            PrintDebug("vga: mode 1 write, offset=0x%llx\n", offset);
 
-           for (i=0;i<length;i++,offset++) { 
+           for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) { 
 
                uint8_t mapnum;
-               uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+               uint8_t mm = find_map_write(vga,guest_addr+i);
 
                for (mapnum=0;mapnum<4;mapnum++,  mm>>=1) { 
                    vga_map map = vga->map[mapnum];
@@ -564,14 +1028,14 @@ static int vga_write(struct guest_info * core,
 
            uint8_t func = vga->vga_graphics_controller.vga_data_rotate.function;
            
-           offset = find_offset(vga, guest_addr);
+           offset = find_offset_write(vga, guest_addr);
 
            PrintDebug("vga: mode 2 write, offset=0x%llx, func=%u\n", offset,func);
 
-           for (i=0;i<length;i++,offset++) { 
+           for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) { 
                // now for each map
                uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
-               uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+               uint8_t mm = find_map_write(vga,guest_addr+i);
 
                for (mapnum=0;mapnum<4;mapnum++,  bm>>=1, mm>>=1) { 
                    vga_map map = vga->map[mapnum];
@@ -635,11 +1099,11 @@ static int vga_write(struct guest_info * core,
 
            uint8_t ror = vga->vga_graphics_controller.vga_data_rotate.rotate_count;
            
-           offset = find_offset(vga, guest_addr);
+           offset = find_offset_write(vga, guest_addr);
 
            PrintDebug("vga: mode 3 write, offset=0x%llx, ror=%u\n", offset,ror);
 
-           for (i=0;i<length;i++,offset++) { 
+           for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) { 
                // now for each map
                uint8_t data = ((uint8_t *)src)[i];
 
@@ -647,7 +1111,7 @@ static int vga_write(struct guest_info * core,
 
                uint8_t bm = vga->vga_graphics_controller.vga_bit_mask & data;
                uint8_t sr = vga->vga_graphics_controller.vga_set_reset.val & 0xf;
-               uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
+               uint8_t mm = find_map_write(vga,guest_addr+i);
 
                for (mapnum=0;mapnum<4;mapnum++, sr>>=1, bm>>=1, mm>>=1) { 
                    vga_map map = vga->map[mapnum];
@@ -686,44 +1150,35 @@ static int vga_write(struct guest_info * core,
 }
 
 
-/*
-up to 256K mapped through a window of 32 to 128K
-
-most cards support linear mode as well
-
-Need to implement readability too
-
-Write extended memory bit to enable all 256K: 
-
-   Sequencer Memory Mode Register (Index 04h) . extended memory
-
-Must enable writes before effects happen:
-  
-  Miscellaneous Output Register (Read at 3CCh, Write at 3C2h).ram enable
-
-Choose which addresses are supported for CPU writes:
-
-Miscellaneous Graphics Register (Index 06h).memory map select
-00b -- A0000h-BFFFFh (128K region)
-01b -- A0000h-AFFFFh (64K region)
-10b -- B0000h-B7FFFh (32K region)
-11b -- B8000h-BFFFFh (32K region)
-
-There are three addressing modes: Chain 4, Odd/Even mode, and normal mode:
-
-Chain 4: This mode is used for MCGA emulation in the 320x200 256-color mode. The address is mapped to memory MOD 4 (shifted right 2 places.)
-
-Memory model: 64K 32 bit locations; divided into 4 64K bit planes
-
-
-   
 
+static uint64_t find_offset_read(struct vga_internal *vga, addr_t guest_addr)
+{
+    uint64_t mem_start, mem_end;
+    uint64_t size;
+    
+    mem_start=mem_end=0;
+    
+    get_mem_region(vga, &mem_start, &mem_end);
+    
+    size=(mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start)); 
 
-Assume linear framebuffer, starting at address buf:
+    if (!vga->vga_sequencer.vga_mem_mode.chain4) { 
+       return (guest_addr-mem_start) % size;
+    } else {
+       // chain4 mode
+       return ((guest_addr - mem_start) >> 2) % size;
+    }
+}
 
-*/
+static uint8_t find_increment_read(struct vga_internal *vga, addr_t new_guest_addr)
+{
 
+    if (vga->vga_sequencer.vga_mem_mode.chain4) { 
+       return !(new_guest_addr & 0x3);
+    } else {
+       return 1;
+    }
+}
 
 
 static int vga_read(struct guest_info * core, 
@@ -732,15 +1187,13 @@ static int vga_read(struct guest_info * core,
                    uint_t length, 
                    void * priv_data)
 {
-    int i;
     struct vm_device *dev = (struct vm_device *)priv_data;
     struct vga_internal *vga = (struct vga_internal *) dev->private_data;
     
 
     PrintDebug("vga: memory read: guest_addr=0x%p len=%u\n",(void*)guest_addr, length);
 
-
-               
+        
    
     /*
       Reading, 2 modes, set via Graphics Mode Register (index 05h).Read Mode:
@@ -751,21 +1204,31 @@ static int vga_read(struct guest_info * core,
                    which plane is determined by Read Map Select (Read Map Select Register (Index 04h)) */
            uint8_t  mapnum;
            uint64_t offset;
-           
-           mapnum = vga->vga_graphics_controller.vga_read_map_select.map_select;
-           offset = find_offset(vga,guest_addr);
-           
-           if (offset>=65536) { 
-               PrintError("vga: read to offset=%llu map=%u (%u bytes)\n",offset,mapnum,length);
-           }
 
-           memcpy(dst,(vga->map[mapnum])+offset,length);
 
-           // load the latches with the last item read
-           for (mapnum=0;mapnum<4;mapnum++) { 
-               vga->latch[mapnum] = vga->map[mapnum][offset+length-1];
+           if (vga->vga_sequencer.vga_mem_mode.chain4) { 
+               uint32_t i;
+               offset = find_offset_read(vga,guest_addr);
+               // address bytes select the map
+               for (i=0;i<length;i++,offset+=find_increment_read(vga,guest_addr+i)) { 
+                   mapnum = (guest_addr+i) % 4;
+                   ((uint8_t*)dst)[i] = vga->latch[mapnum] = *(vga->map[mapnum]+offset);
+               }
+           } else {
+               mapnum = vga->vga_graphics_controller.vga_read_map_select.map_select;
+               offset = find_offset_read(vga,guest_addr);
+               
+               if (offset>=65536) { 
+                   PrintError("vga: read to offset=%llu map=%u (%u bytes)\n",offset,mapnum,length);
+               }
+               
+               memcpy(dst,(vga->map[mapnum])+offset,length);
+               
+               // load the latches with the last item read
+               for (mapnum=0;mapnum<4;mapnum++) { 
+                   vga->latch[mapnum] = vga->map[mapnum][offset+length-1];
+               }
            }
-           
        
        }
            break;
@@ -788,7 +1251,7 @@ static int vga_read(struct guest_info * core,
            uint8_t  byte;
            uint8_t  bits;
            
-           offset = find_offset(vga,guest_addr);
+           offset = find_offset_read(vga,guest_addr);
            
            for (i=0;i<length;i++,offset++) { 
                vga_map map;
@@ -826,12 +1289,20 @@ static int vga_read(struct guest_info * core,
     }
 
 
-    PrintDebug("vga: data read is \"");
+#if 0
+    int i;
+    PrintDebug("vga: data read is 0x");
+    for (i=0;i<length;i++) {
+       uint8_t c= ((char*)dst)[i];
+       PrintDebug("%.2x", c);
+    }
+    PrintDebug(" \"");
     for (i=0;i<length;i++) {
        char c= ((char*)dst)[i];
-       PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') ? c : '.');
+       PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || (c==' ') ? c : '.');
     }
     PrintDebug("\"\n");
+#endif
 
     return length;
 
index c62d29f..c9858db 100644 (file)
@@ -858,4 +858,40 @@ typedef uint8_t vga_dac_pixel_mask_reg;
 // This is red, green, blue
 typedef uint32_t vga_palette_reg; 
 
+
+//
+//  What attribute bytes mean in text mode
+//
+struct vga_attribute_byte {
+    union {
+       uint8_t val;
+       struct {
+           union {
+               uint8_t fore:3;
+               struct { 
+                   uint8_t fore_red:1;
+                   uint8_t fore_green:1;
+                   uint8_t fore_blue:1;
+               } __attribute__((packed));
+           } __attribute__((packed));
+           uint8_t foreground_intensity_or_font_select:1; // depends on char map select reg
+           // character map selection is effected
+           // when memory_mode.extended meomory=1
+           // and the two character map enteries on character_map_select are 
+           // different
+           union {
+               uint8_t back:3;
+               struct { 
+                   uint8_t back_red:1;
+                   uint8_t back_green:1;
+                   uint8_t back_blue:1;
+               } __attribute__((packed));
+           } __attribute__((packed));
+           uint8_t blinking_or_bg_intensity:1; 
+           // attribute mode control.enableblink = 1 => blink
+           // =0 => intensity (16 colors of bg)
+       } __attribute__((packed));
+    } __attribute__((packed));
+} __attribute__((packed));
+
 #endif
diff --git a/palacios/src/interfaces/Kconfig b/palacios/src/interfaces/Kconfig
new file mode 100644 (file)
index 0000000..0bd9d15
--- /dev/null
@@ -0,0 +1,53 @@
+menu "Host Interfaces"
+
+config FILE
+        bool "Host Support for file operations"
+        default n
+        help
+          Select this if your host OS supports file operatoins and you want Palacios to be able to use them.
+       
+config KEYED_STREAMS
+        bool "Host support for keyed streams"
+        default n
+        help
+          Select this if your host OS supports keyed streams
+          Palacios Checkpoint/Restore and Migration depends on this feature
+
+config STREAM
+       bool "Stream support"
+       default n
+
+          
+config CONSOLE
+       bool "Host Support for VM text-mode console"
+        default n
+        help
+          Select this if you want to forward a guest console interface to some host OS service
+          This is for a TEXT MODE console.   Select the framebuffer console for graphics and text
+            
+config GRAPHICS_CONSOLE
+        bool "Host Support for VM graphics and text-mode console based on a frame buffer"
+        default n
+       help
+          Select this if you want to forward a guest graphics-mode (and text-mode) console
+          interface to some host OS service.  This is for a GRAPHICS console based on a shared frame buffer.
+          Text mode output is RENDERED onto the framebuffer
+
+config SOCKET
+        bool "Host support for Network Sockets"
+        default y
+        help
+          Select this if you host OS implements a socket API that is available to Palacios. This is required
+          to support the internal networking features of Palacios.
+
+
+config PACKET
+        bool "Host support for Raw Packet Transmision"
+        depends on EXPERIMENTAL
+        default n
+        help
+         Select this if you host OS implements a raw packet network API that is available to Palacios. This is required
+          to support the internal networking features of Palacios.
+
+
+endmenu
diff --git a/palacios/src/interfaces/Makefile b/palacios/src/interfaces/Makefile
new file mode 100644 (file)
index 0000000..4f3a17b
--- /dev/null
@@ -0,0 +1,9 @@
+obj-$(CONFIG_SOCKET) +=  vmm_socket.o
+obj-$(CONFIG_PACKET) +=  vmm_packet.o
+obj-$(CONFIG_FILE) += vmm_file.o
+obj-$(CONFIG_CONSOLE) += vmm_console.o
+obj-$(CONFIG_STREAM) += vmm_stream.o
+obj-$(CONFIG_GRAPHICS_CONSOLE) += vmm_graphics_console.o
+obj-$(CONFIG_KEYED_STREAMS) += vmm_keyed_stream.o
+
+
similarity index 98%
rename from palacios/src/palacios/vmm_console.c
rename to palacios/src/interfaces/vmm_console.c
index bf5d5ae..244fbf6 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 
-#include <palacios/vmm_console.h>
+#include <interfaces/vmm_console.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_types.h>
similarity index 98%
rename from palacios/src/palacios/vmm_file.c
rename to palacios/src/interfaces/vmm_file.c
index f2e191a..c22267a 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 
-#include <palacios/vmm_file.h>
+#include <interfaces/vmm_file.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_types.h>
@@ -18,7 +18,7 @@
  */
 
 
-#include <palacios/vmm_graphics_console.h>
+#include <interfaces/vmm_graphics_console.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_types.h>
similarity index 98%
rename from palacios/src/palacios/vmm_keyed_stream.c
rename to palacios/src/interfaces/vmm_keyed_stream.c
index e430ae8..4ba376b 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 
-#include <palacios/vmm_keyed_stream.h>
+#include <interfaces/vmm_keyed_stream.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_types.h>
similarity index 98%
rename from palacios/src/palacios/vmm_packet.c
rename to palacios/src/interfaces/vmm_packet.c
index 7d90d3e..a813a7c 100644 (file)
@@ -16,7 +16,8 @@
  * This is free software.  You are permitted to use,
  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
  */
-#include <palacios/vmm.h>
+
+#include <interfaces/vmm.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_types.h>
 #include <palacios/vm_guest.h>
similarity index 99%
rename from palacios/src/palacios/vmm_socket.c
rename to palacios/src/interfaces/vmm_socket.c
index 683f6e4..5ac5c15 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 
-#include <palacios/vmm_socket.h>
+#include <interfaces/vmm_socket.h>
 #include <palacios/vmm.h>
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_types.h>
similarity index 97%
rename from palacios/src/palacios/vmm_stream.c
rename to palacios/src/interfaces/vmm_stream.c
index c7a2e51..66ce081 100644 (file)
@@ -22,7 +22,7 @@
 #include <palacios/vmm_debug.h>
 #include <palacios/vmm_types.h>
 
-#include <palacios/vmm_stream.h>
+#include <interfaces/vmm_stream.h>
 #include <palacios/vm_guest.h>
 
 static struct v3_stream_hooks * stream_hooks = NULL;
index e06c481..5747261 100644 (file)
@@ -68,13 +68,8 @@ obj-$(CONFIG_VMX) +=         vmx.o \
 
 obj-$(CONFIG_INSTRUMENT_VMM) += vmm_instrument.o
 obj-$(CONFIG_TELEMETRY) += vmm_telemetry.o 
-obj-$(CONFIG_SOCKET) +=  vmm_socket.o
-obj-$(CONFIG_PACKET) +=  vmm_packet.o
+
 obj-$(CONFIG_VNET) += vmm_vnet_core.o
-obj-$(CONFIG_FILE) += vmm_file.o
-obj-$(CONFIG_CONSOLE) += vmm_console.o vmm_stream.o
-obj-$(CONFIG_GRAPHICS_CONSOLE) += vmm_graphics_console.o
-obj-$(CONFIG_KEYED_STREAMS) += vmm_keyed_stream.o
 
 
 obj-$(CONFIG_SYMBIOTIC) += vmm_symbiotic.o vmm_symspy.o
index f24dc38..b1d747e 100644 (file)
@@ -38,7 +38,6 @@
 
 
 #include <palacios/vmm_host_events.h>
-#include <palacios/vmm_socket.h>
 
 #include "vmm_config_class.h"
 
index e5cf1f2..15a56d6 100644 (file)
@@ -313,6 +313,10 @@ static int run_str_op(struct guest_info * core, struct x86_instr * instr,
     int emulation_length = op_size * rep_cnt;
     struct rflags * flags_reg = (struct rflags *)&(core->ctrl_regs.rflags);
 
+
+    PrintError("Emulation_len=%d, tmp_rcx=%d\n", emulation_length, (uint_t)tmp_rcx);
+
+
     if (instr->op_type == V3_OP_MOVS) {
        if (op_size== 1) {
            movs8((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
@@ -358,6 +362,8 @@ static int run_str_op(struct guest_info * core, struct x86_instr * instr,
            return -1;
        }
 
+
+
        if (flags_reg->df == 0) {
            core->vm_regs.rdi += emulation_length;
        } else {
@@ -383,8 +389,7 @@ int v3_emulate(struct guest_info * core, struct x86_instr * instr,
 
     addr_t src_hva = 0;
     addr_t dst_hva = 0;
-    
-    PrintError("USING THE NEW EMULATOR\n");
+
 
     if (instr->src_operand.type == MEM_OPERAND) {
        src_hva = mem_hva_src;
@@ -393,7 +398,7 @@ int v3_emulate(struct guest_info * core, struct x86_instr * instr,
     } else {
        src_hva = (addr_t)&(instr->src_operand.operand);
     }
-       
+
     if (instr->dst_operand.type == MEM_OPERAND) {
        dst_hva = mem_hva_dst;
     } else if (instr->dst_operand.type == REG_OPERAND) {
@@ -401,7 +406,7 @@ int v3_emulate(struct guest_info * core, struct x86_instr * instr,
     } else {
        dst_hva = (addr_t)&(instr->dst_operand.operand);
     }
-    
 
     if (instr->is_str_op == 0) {
        int src_op_len = instr->src_operand.size;
@@ -421,6 +426,5 @@ int v3_emulate(struct guest_info * core, struct x86_instr * instr,
     }
 
 
-
     return -1;
 }
index 6993c9e..aee8c33 100644 (file)
@@ -145,6 +145,7 @@ static int handle_mem_hook(struct guest_info * core, addr_t guest_va, addr_t gue
     }
 
 
+
     // Test source operand, if it's memory we need to do some translations, and handle a possible hook
     if (instr.src_operand.type == MEM_OPERAND) {
        struct v3_mem_region * src_reg = NULL;
@@ -162,8 +163,8 @@ static int handle_mem_hook(struct guest_info * core, addr_t guest_va, addr_t gue
            }
        }
 
-       if ((guest_pa >= reg->guest_start) && 
-           (guest_pa <= reg->guest_end)) {
+       if ((src_mem_op_gpa >= reg->guest_start) && 
+           (src_mem_op_gpa < reg->guest_end)) {   
            // Src address corresponds to faulted region
            src_reg = reg;
        } else {
@@ -208,8 +209,8 @@ static int handle_mem_hook(struct guest_info * core, addr_t guest_va, addr_t gue
            }
        }
 
-       if ((guest_pa >= reg->guest_start) && 
-           (guest_pa <= reg->guest_end)) {
+       if ((dst_mem_op_gpa >= reg->guest_start) && 
+           (dst_mem_op_gpa < reg->guest_end)) {
            // Dst address corresponds to faulted region
            dst_reg = reg;
        } else {
index c1df822..4fa6e04 100644 (file)
@@ -27,7 +27,7 @@
 
 
 #define MASK(val, length) ({                                           \
-            ullong_t mask = 0x0LL;                                     \
+            uint64_t mask = 0x0LL;                                     \
             switch (length) {                                          \
                case 1:                                                 \
                    mask = 0x00000000000000ffLL;                        \
@@ -102,7 +102,6 @@ int v3_decode(struct guest_info * core, addr_t instr_ptr, struct x86_instr * ins
 
     form = op_code_to_form((uint8_t *)(instr_ptr + length), &length);
 
-
     V3_Print("\t decoded as (%s)\n", op_form_to_str(form));
 
     if (form == INVALID_INSTR) {
@@ -119,11 +118,9 @@ int v3_decode(struct guest_info * core, addr_t instr_ptr, struct x86_instr * ins
        return -1;
     }
     length += ret;
-    
 
     instr->instr_length += length;
 
-
     v3_print_instr(instr);
 
     return 0;
@@ -264,6 +261,56 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr,
 
            break;
        }
+       case MOVSX_8:
+       case MOVZX_8: {
+           uint8_t reg_code = 0;
+
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), &reg_code);
+           instr->src_operand.size = 1;
+
+           if (ret == -1) {
+               PrintError("Error decoding operand\n");
+               return -1;
+           }
+
+           instr_ptr += ret;
+
+           instr->dst_operand.size = operand_width;
+           instr->dst_operand.type = REG_OPERAND;
+           decode_gpr(core, reg_code, &(instr->dst_operand));
+
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
+
+           instr->num_operands = 2;
+
+           break;
+       }
+       case MOVSX:
+       case MOVZX: {
+           uint8_t reg_code = 0;
+
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand), &reg_code);
+           instr->src_operand.size = 2;
+
+           if (ret == -1) {
+               PrintError("Error decoding operand\n");
+               return -1;
+           }
+
+           instr_ptr += ret;
+
+           instr->dst_operand.size = operand_width;
+           instr->dst_operand.type = REG_OPERAND;
+           decode_gpr(core, reg_code, &(instr->dst_operand));
+
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
+
+           instr->num_operands = 2;
+
+           break;
+       }
        case ADC_IMM2SX_8:
        case ADD_IMM2SX_8:
        case AND_IMM2SX_8:
@@ -274,7 +321,6 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr,
 
            ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), &reg_code);
 
-
            if (ret == -1) {
                PrintError("Error decoding operand\n");
                return -1;
@@ -284,7 +330,7 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr,
 
            instr->src_operand.type = IMM_OPERAND;
            instr->src_operand.size = operand_width;
-           instr->src_operand.operand = *(sint8_t *)instr_ptr;  // sign extend.
+           instr->src_operand.operand = (addr_t)MASK((sint64_t)*(sint8_t *)instr_ptr, operand_width);  // sign extend.
 
            instr->src_operand.read = 1;
            instr->dst_operand.write = 1;
@@ -324,99 +370,97 @@ static int parse_operands(struct guest_info * core, uint8_t * instr_ptr,
            instr->num_operands = 2;
 
            break;
+       }
+       case MOV_2CR: {
+           uint8_t reg_code = 0;
+           
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand),
+                                   &reg_code);
 
-           case MOV_2CR: {
-               uint8_t reg_code = 0;
-
-               ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->src_operand),
-                                       &reg_code);
-
-               if (ret == -1) {
-                   PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
-                   return -1;
-               }
-               
-               instr_ptr += ret;
-
-               instr->dst_operand.type = REG_OPERAND;
-               instr->dst_operand.size = operand_width;
-               decode_cr(core, reg_code, &(instr->dst_operand));
-
-               instr->src_operand.read = 1;
-               instr->dst_operand.write = 1;
-
-               instr->num_operands = 2;
-               break;
+           if (ret == -1) {
+               PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
+               return -1;
            }
-           case MOV_CR2: {
-               uint8_t reg_code = 0;
-
-               ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand),
-                                       &reg_code);
-
-
-               if (ret == -1) {
-                   PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
-                   return -1;
-               }
-
-               instr_ptr += ret;
                
-               instr->src_operand.type = REG_OPERAND;
-               instr->src_operand.size = operand_width;
-               decode_cr(core, reg_code, &(instr->src_operand));
+           instr_ptr += ret;
 
-               instr->src_operand.read = 1;
-               instr->dst_operand.write = 1;
+           instr->dst_operand.type = REG_OPERAND;
+           instr->dst_operand.size = operand_width;
+           decode_cr(core, reg_code, &(instr->dst_operand));
+           
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
 
-               instr->num_operands = 2;
-               break;
+           instr->num_operands = 2;
+           break;
+       }
+       case MOV_CR2: {
+           uint8_t reg_code = 0;
+           
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand),
+                                   &reg_code);
+           
+           if (ret == -1) {
+               PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
+               return -1;
            }
-           case STOS:
-           case STOS_8: {
-               instr->is_str_op = 1;
-               
-               if (instr->prefixes.rep == 1) {
-                   instr->str_op_length = MASK(core->vm_regs.rcx, operand_width);
-               } else {
-                   instr->str_op_length = 1;
-               }
-               
-               instr->src_operand.size = operand_width;
-               instr->src_operand.type = REG_OPERAND;
-               instr->src_operand.operand = (addr_t)&(core->vm_regs.rax);
 
-               instr->dst_operand.type = MEM_OPERAND;
-               instr->dst_operand.size = operand_width;
-               instr->dst_operand.operand = get_addr_linear(core, MASK(core->vm_regs.rdi, addr_width), &(core->segments.es));
+           instr_ptr += ret;
+           
+           instr->src_operand.type = REG_OPERAND;
+           instr->src_operand.size = operand_width;
+           decode_cr(core, reg_code, &(instr->src_operand));
 
-               instr->src_operand.read = 1;
-               instr->dst_operand.write = 1;
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
 
-               instr->num_operands = 2;
+           instr->num_operands = 2;
+           break;
+       }
+       case STOS:
+       case STOS_8: {
+           instr->is_str_op = 1;
 
-               break;
+           if (instr->prefixes.rep == 1) {
+               instr->str_op_length = MASK(core->vm_regs.rcx, operand_width);
+           } else {
+               instr->str_op_length = 1;
            }
-           case INVLPG: {
-               uint8_t reg_code = 0;
 
-               ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), &reg_code);
+           instr->src_operand.size = operand_width;
+           instr->src_operand.type = REG_OPERAND;
+           instr->src_operand.operand = (addr_t)&(core->vm_regs.rax);
 
-               if (ret == -1) {
-                   PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
-                   return -1;
-               }
+           instr->dst_operand.type = MEM_OPERAND;
+           instr->dst_operand.size = operand_width;
+           instr->dst_operand.operand = get_addr_linear(core, MASK(core->vm_regs.rdi, addr_width), &(core->segments.es));
 
-               instr_ptr += ret;
+           instr->src_operand.read = 1;
+           instr->dst_operand.write = 1;
 
-               instr->num_operands = 1;
-               break;
-           }
-           case CLTS: {
-               // no operands. 
-               break;
+           instr->num_operands = 2;
 
+           break;
+       }
+       case INVLPG: {
+           uint8_t reg_code = 0;
+           
+           ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), &reg_code);
+           
+           if (ret == -1) {
+               PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
+               return -1;
            }
+           
+           instr_ptr += ret;
+           
+           instr->num_operands = 1;
+           break;
+       }
+       case CLTS: {
+           // no operands. 
+           break;
+           
        }
        default:
            PrintError("Invalid Instruction form: %s\n", op_form_to_str(form));
index 36612ba..bb1e856 100644 (file)
@@ -313,6 +313,8 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
     xed_decoded_inst_t xed_instr;
     xed_error_enum_t xed_error;
 
+    memset(instr, 0, sizeof(struct x86_instr));
+
 
     v3_get_prefixes((uchar_t *)instr_ptr, &(instr->prefixes));
 
@@ -402,18 +404,6 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
 
        v3_op = &(instr->dst_operand);
 
-       if ((op->_rw == XED_OPERAND_ACTION_RW) || 
-           (op->_rw == XED_OPERAND_ACTION_R)|| 
-           (op->_rw == XED_OPERAND_ACTION_RCW)) {
-           v3_op->read = 1;
-       }
-
-       if ((op->_rw == XED_OPERAND_ACTION_RW) || 
-           (op->_rw == XED_OPERAND_ACTION_W) || 
-           (op->_rw == XED_OPERAND_ACTION_CRW)) {
-           v3_op->write = 1;
-       }
-
        if (xed_operand_is_register(op_enum)) {
            xed_reg_enum_t xed_reg =  xed_decoded_inst_get_reg(&xed_instr, op_enum);
            int v3_reg_type = xed_reg_to_v3_reg(info, 
@@ -461,6 +451,18 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
                    return -1;
            }
        }
+
+       V3_Print("Operand 0 mode: %s\n", xed_operand_action_enum_t2str(xed_operand_rw(op)));
+
+
+       if (xed_operand_read(op)) {
+           v3_op->read = 1;
+       }
+
+       if (xed_operand_written(op)) {
+           v3_op->write = 1;
+       }
+
     }
 
     // set second operand
@@ -480,17 +482,6 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
        */
        v3_op = &(instr->src_operand);
 
-       if ((op->_rw == XED_OPERAND_ACTION_RW) || 
-           (op->_rw == XED_OPERAND_ACTION_R)|| 
-           (op->_rw == XED_OPERAND_ACTION_RCW)) {
-           v3_op->read = 1;
-       }
-
-       if ((op->_rw == XED_OPERAND_ACTION_RW) || 
-           (op->_rw == XED_OPERAND_ACTION_W) || 
-           (op->_rw == XED_OPERAND_ACTION_CRW)) {
-           v3_op->write = 1;
-       }
 
        if (xed_operand_is_register(op_enum)) {
            xed_reg_enum_t xed_reg =  xed_decoded_inst_get_reg(&xed_instr, op_enum);
@@ -550,6 +541,17 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
                    return -1;
            }
        }
+
+       V3_Print("Operand 1 mode: %s\n", xed_operand_action_enum_t2str(xed_operand_rw(op)));
+
+       if (xed_operand_read(op)) {
+           v3_op->read = 1;
+       }
+
+       if (xed_operand_written(op)) {
+           v3_op->write = 1;
+       }
+
     }
 
     // set third operand
@@ -558,17 +560,7 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
        xed_operand_type_enum_t op_type = xed_operand_type(op);
        xed_operand_enum_t op_enum = xed_operand_name(op);
 
-       if ((op->_rw == XED_OPERAND_ACTION_RW) || 
-           (op->_rw == XED_OPERAND_ACTION_R)|| 
-           (op->_rw == XED_OPERAND_ACTION_RCW)) {
-           instr->third_operand.read = 1;
-       }
 
-       if ((op->_rw == XED_OPERAND_ACTION_RW) || 
-           (op->_rw == XED_OPERAND_ACTION_W) || 
-           (op->_rw == XED_OPERAND_ACTION_CRW)) {
-           instr->third_operand.write = 1;
-       }
 
        if (xed_operand_is_register(op_enum)) {
            xed_reg_enum_t xed_reg =  xed_decoded_inst_get_reg(&xed_instr, op_enum);
@@ -589,6 +581,17 @@ int v3_decode(struct guest_info * info, addr_t instr_ptr, struct x86_instr * ins
 
            instr->third_operand.type = REG_OPERAND;
 
+           PrintDebug("Operand 3 mode: %s\n", xed_operand_action_enum_t2str(xed_operand_rw(op)));
+
+
+           if (xed_operand_read(op)) {
+               instr->third_operand.read = 1;
+           }
+
+           if (xed_operand_written(op)) {
+               instr->third_operand.write = 1;
+           }
+
        } else {
            PrintError("Unhandled third operand type %s\n", xed_operand_type_enum_t2str(op_type));
            instr->num_operands = 2;