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.


Cleanup and sanity-checking of OOB accesses and pointer-to-local issues (Coverity...
[palacios.git] / palacios / src / devices / cga.c
index b720c6b..7652b04 100644 (file)
 #include <devices/console.h>
 
 
-#if CONFIG_DEBUG_CGA >= 2
+#if V3_CONFIG_DEBUG_CGA >= 2
 #define PrintVerbose PrintDebug
 #else
 #define PrintVerbose(fmt, args...)
 #endif
-#if CONFIG_DEBUG_CGA == 0
+#if V3_CONFIG_DEBUG_CGA == 0
 #undef PrintDebug
 #define PrintDebug(fmt, args...)
 #endif
@@ -227,7 +227,7 @@ struct video_internal {
 static void refresh_screen(struct video_internal * state) {
     uint_t screen_size;
     
-    PrintDebug("Screen config: framebuf=0x%x-0x%x, gres=%dx%d, tres=%dx%d, %s mode\n", 
+    PrintDebug(VM_NONE, VCORE_NONE, "Screen config: framebuf=0x%x-0x%x, gres=%dx%d, tres=%dx%d, %s mode\n", 
        (unsigned) state->activefb_addr, 
        (unsigned) state->activefb_addr + state->activefb_len, 
        state->hres,
@@ -242,14 +242,14 @@ static void refresh_screen(struct video_internal * state) {
     if (state->reschanged) {
         /* resolution change message will trigger update */
        state->reschanged = 0;
-       PrintDebug("Video: set_text_resolution(%d, %d)\n", 
+       PrintDebug(VM_NONE, VCORE_NONE, "Video: set_text_resolution(%d, %d)\n", 
            state->hchars, state->vchars);
        if (state->ops && state->ops->set_text_resolution) {
            state->ops->set_text_resolution(state->hchars, state->vchars, state->private_data);
        }
     } else {
         /* send update for full buffer */
-       PrintDebug("Video: update_screen(0, 0, %d * %d * %d)\n", state->vchars, state->hchars, BYTES_PER_COL);
+       PrintDebug(VM_NONE, VCORE_NONE, "Video: update_screen(0, 0, %d * %d * %d)\n", state->vchars, state->hchars, BYTES_PER_COL);
        screen_size = state->vchars * state->hchars * BYTES_PER_COL;
        if (state->ops) {
            state->ops->update_screen(0, 0, screen_size, state->private_data);
@@ -280,7 +280,7 @@ static void registers_updated(struct video_internal * state) {
        state->activefb_addr = activefb_addr;
        state->activefb_len = activefb_len;
        state->dirty = 1;
-       PrintVerbose("Video: need refresh (activefb=0x%x-0x%x)\n", 
+       PrintVerbose(VM_NONE, VCORE_NONE, "Video: need refresh (activefb=0x%x-0x%x)\n", 
            activefb_addr, activefb_addr + activefb_len);
     } 
     
@@ -288,7 +288,7 @@ static void registers_updated(struct video_internal * state) {
     if (state->graphmode != misc->gm) {
        state->graphmode = misc->gm;
        state->dirty = 1;
-       PrintVerbose("Video: need refresh (graphmode=%d)\n", state->graphmode);
+       PrintVerbose(VM_NONE, VCORE_NONE, "Video: need refresh (graphmode=%d)\n", state->graphmode);
     }
 
     /* graphics resolution */
@@ -296,7 +296,7 @@ static void registers_updated(struct video_internal * state) {
        vres = (state->misc_outp_reg.vsp) ? 480 : 400;
     } else {
        if (!state->misc_outp_reg.vsp) {
-           PrintError("Video: reserved value in misc_outp_reg (0x%x)\n", 
+           PrintError(VM_NONE, VCORE_NONE, "Video: reserved value in misc_outp_reg (0x%x)\n", 
                *(uint8_t *) &state->misc_outp_reg);
        }
        vres = 350;
@@ -307,14 +307,14 @@ static void registers_updated(struct video_internal * state) {
     if (state->vres != vres) {
        state->vres = vres;
        state->reschanged = 1;
-       PrintVerbose("Video: need refresh (vres=%d)\n", vres);
+       PrintVerbose(VM_NONE, VCORE_NONE, "Video: need refresh (vres=%d)\n", vres);
     }
     
     switch (state->misc_outp_reg.cs) {
         case 0: hres = 640; break;
         case 1: hres = 720; break;
        default:
-               PrintError("Video: reserved value in misc_outp_reg (0x%x)\n", 
+               PrintError(VM_NONE, VCORE_NONE, "Video: reserved value in misc_outp_reg (0x%x)\n", 
                        *(uint8_t *) &state->misc_outp_reg);
                hres = 640;
                break;
@@ -325,7 +325,7 @@ static void registers_updated(struct video_internal * state) {
     if (state->hres != hres) {
        state->hres = hres;
        state->reschanged = 1;
-       PrintVerbose("Video: need refresh (hres=%d)\n", hres);
+       PrintVerbose(VM_NONE, VCORE_NONE, "Video: need refresh (hres=%d)\n", hres);
     }
 
     /* text resolution */
@@ -341,7 +341,7 @@ static void registers_updated(struct video_internal * state) {
        state->hchars = hchars;
        state->vchars = vchars;
        state->reschanged = 1;
-       PrintVerbose("Video: need refresh (hchars=%d, vchars=%d)\n", hchars, vchars);
+       PrintVerbose(VM_NONE, VCORE_NONE, "Video: need refresh (hchars=%d, vchars=%d)\n", hchars, vchars);
     }
     
     /* resolution change implies refresh needed */
@@ -391,19 +391,19 @@ static void registers_initialize(struct video_internal * state) {
     state->misc_outp_reg.hsp = 1;    
     
     /* sequencer registers */
-    V3_ASSERT(sizeof(seq_defaults) == sizeof(state->seq_data_regs));
+    V3_ASSERT(VM_NONE, VCORE_NONE, sizeof(seq_defaults) == sizeof(state->seq_data_regs));
     memcpy(state->seq_data_regs, seq_defaults, sizeof(state->seq_data_regs));    
     
     /* CRT controller registers */
-    V3_ASSERT(sizeof(crtc_defaults) == sizeof(state->crtc_data_regs));
+    V3_ASSERT(VM_NONE, VCORE_NONE, sizeof(crtc_defaults) == sizeof(state->crtc_data_regs));
     memcpy(state->crtc_data_regs, crtc_defaults, sizeof(state->crtc_data_regs));    
     
     /* graphics controller registers */
-    V3_ASSERT(sizeof(graphc_defaults) == sizeof(state->graphc_data_regs));
+    V3_ASSERT(VM_NONE, VCORE_NONE, sizeof(graphc_defaults) == sizeof(state->graphc_data_regs));
     memcpy(state->graphc_data_regs, graphc_defaults, sizeof(state->graphc_data_regs));    
     
     /* attribute controller registers */
-    V3_ASSERT(sizeof(attrc_defaults) == sizeof(state->attrc_data_regs));
+    V3_ASSERT(VM_NONE, VCORE_NONE, sizeof(attrc_defaults) == sizeof(state->attrc_data_regs));
     memcpy(state->attrc_data_regs, attrc_defaults, sizeof(state->attrc_data_regs));    
     
     /* initialize auxilary fields */
@@ -443,7 +443,7 @@ static void passthrough_out(uint16_t port, const void * src, uint_t length) {
     }
 }
 
-#if CONFIG_DEBUG_CGA >= 2
+#if V3_CONFIG_DEBUG_CGA >= 2
 static unsigned long get_value(const void *ptr, int len) {
   unsigned long value = 0;
 
@@ -470,10 +470,10 @@ static int video_write_mem(struct guest_info * core, addr_t guest_addr, void * d
     uint_t length_adjusted, screen_pos, x, y;
     addr_t framebuf_offset, framebuf_offset_screen, screen_offset;
     
-    V3_ASSERT(guest_addr >= START_ADDR);
-    V3_ASSERT(guest_addr < END_ADDR);
+    V3_ASSERT(core->vm_info, core, guest_addr >= START_ADDR);
+    V3_ASSERT(core->vm_info, core, guest_addr < END_ADDR);
     
-    PrintVerbose("Video: write(%p, 0x%lx, %d)\n", 
+    PrintVerbose(core->vm_info, core, "Video: write(%p, 0x%lx, %d)\n", 
        (void *)guest_addr, 
        get_value(state->framebuf + (guest_addr - START_ADDR), length),
        length);
@@ -526,7 +526,7 @@ static int video_write_mem(struct guest_info * core, addr_t guest_addr, void * d
     x = screen_pos % state->hchars;
     y = screen_pos / state->hchars;
     if (y >= state->vchars) return length;
-    PrintVerbose("Video: update_screen(%d, %d, %d)\n", x, y, length_adjusted);
+    PrintVerbose(core->vm_info, core, "Video: update_screen(%d, %d, %d)\n", x, y, length_adjusted);
     state->ops->update_screen(x, y, length_adjusted, state->private_data);
 
     return length;
@@ -538,17 +538,17 @@ static void debug_port(struct video_internal * video_state, const char *function
 
     /* report any unexpected guest behaviour, it may explain failures */
     if (portrange != 0x3c0 && portrange != video_state->iorange) {
-       PrintError("Video %s: got bad port 0x%x\n", function, port);
+       PrintError(VM_NONE, VCORE_NONE, "Video %s: got bad port 0x%x\n", function, port);
     }
 
     if (!video_state->passthrough && length > maxlength) {
-       PrintError("Video %s: got bad length %d\n", function, length);
+       PrintError(VM_NONE, VCORE_NONE, "Video %s: got bad length %d\n", function, length);
     }
-    V3_ASSERT(length >= 1);
+    V3_ASSERT(VM_NONE, VCORE_NONE, length >= 1);
 }
 
 static void handle_port_read(struct video_internal * video_state, const char *function, uint16_t port, void *dest, uint_t length, uint_t maxlength) {
-    PrintVerbose("Video %s: in%c(0x%x): 0x%lx\n", function, opsize_char(length), port, get_value(dest, length));
+    PrintVerbose(VM_NONE, VCORE_NONE, "Video %s: in%c(0x%x): 0x%lx\n", function, opsize_char(length), port, get_value(dest, length));
     debug_port(video_state, function, port, length, maxlength);
 
     if (video_state->passthrough) {
@@ -557,7 +557,7 @@ static void handle_port_read(struct video_internal * video_state, const char *fu
 }
 
 static void handle_port_write(struct video_internal * video_state, const char *function, uint16_t port, const void *src, uint_t length, uint_t maxlength) {
-    PrintVerbose("Video %s: out%c(0x%x, 0x%lx)\n", function, opsize_char(length), port, get_value(src, length));
+    PrintVerbose(VM_NONE, VCORE_NONE, "Video %s: out%c(0x%x, 0x%lx)\n", function, opsize_char(length), port, get_value(src, length));
     debug_port(video_state, function, port, length, maxlength);
 
     if (video_state->passthrough) {
@@ -569,7 +569,7 @@ static int notimpl_port_read(struct video_internal * video_state, const char *fu
     memset(dest, 0xff, length);
     handle_port_read(video_state, function, port, dest, length, 1);
     if (!video_state->passthrough) {
-       PrintError("Video %s: not implemented\n", function);
+       PrintError(VM_NONE, VCORE_NONE, "Video %s: not implemented\n", function);
     }
     return length;
 }
@@ -577,7 +577,7 @@ static int notimpl_port_read(struct video_internal * video_state, const char *fu
 static int notimpl_port_write(struct video_internal * video_state, const char *function, uint16_t port, const void *src, uint_t length) {
     handle_port_write(video_state, function, port, src, length, 1);
     if (!video_state->passthrough) {
-       PrintError("Video %s: not implemented\n", function);
+       PrintError(VM_NONE, VCORE_NONE, "Video %s: not implemented\n", function);
     }
     return length;
 }
@@ -596,7 +596,7 @@ static int misc_outp_write(struct guest_info * core, uint16_t port, void * src,
     struct video_internal * video_state = priv_data;
     handle_port_write(video_state, __FUNCTION__, port, src, length, 1);
 
-    PrintDebug("Video: misc_outp=0x%x\n", *(uint8_t *) src);
+    PrintDebug(core->vm_info, core, "Video: misc_outp=0x%x\n", *(uint8_t *) src);
     video_state->misc_outp_reg = *(struct misc_outp_reg *) src;
     registers_updated(video_state);
 
@@ -612,8 +612,10 @@ static int inp_status1_read(struct guest_info * core, uint16_t port, void * dest
 
     /* next write to attrc selects the index rather than data */
     video_state->attrc_index_flipflop = 0;
+    memset(dest, 0x0, length);
 
-    return notimpl_port_read(priv_data, __FUNCTION__, port, dest, length);
+    handle_port_read(priv_data, __FUNCTION__, port, dest, length, 1);
+    return length;
 }
 
 static int feat_ctrl_read(struct guest_info * core, uint16_t port, void * dest, uint_t length, void * priv_data) {
@@ -640,7 +642,7 @@ static int seq_data_read(struct guest_info * core, uint16_t port, void * dest, u
     if (index < SEQ_REG_COUNT) {
        *(uint8_t *) dest = video_state->seq_data_regs[index];
     } else {
-       PrintError("Video %s: index %d out of range\n", __FUNCTION__, video_state->seq_index_reg);
+       PrintError(core->vm_info, core, "Video %s: index %d out of range\n", __FUNCTION__, video_state->seq_index_reg);
        *(uint8_t *) dest = 0;
     }
 
@@ -655,11 +657,11 @@ static int seq_data_write(struct guest_info * core, uint16_t port, void * src, u
     handle_port_write(video_state, __FUNCTION__, port, src, length, 1);
 
     if (index < SEQ_REG_COUNT) {
-       PrintDebug("Video: seq[%d]=0x%x\n", index, val);
+       PrintDebug(core->vm_info, core, "Video: seq[%d]=0x%x\n", index, val);
        video_state->seq_data_regs[index] = val;
        registers_updated(video_state);
     } else {
-       PrintError("Video %s: index %d out of range\n", __FUNCTION__, video_state->seq_index_reg);
+       PrintError(core->vm_info, core, "Video %s: index %d out of range\n", __FUNCTION__, video_state->seq_index_reg);
     }
 
     return length;    
@@ -706,7 +708,7 @@ static int crtc_data_write(struct guest_info * core, uint16_t port, void * src,
 
     handle_port_write(video_state, __FUNCTION__, port, src, length, 1);
     if (length != 1) {
-       PrintError("Invalid write length for port 0x%x\n", port);
+       PrintError(core->vm_info, core, "Invalid write length for port 0x%x\n", port);
        return -1;
     }
 
@@ -732,7 +734,7 @@ static int crtc_data_write(struct guest_info * core, uint16_t port, void * src,
                diff = (screen_offset - video_state->screen_offset) / video_state->hchars;
                refresh = 0;
            }
-           PrintVerbose("Video: screen_offset=%d, video_state->screen_offset=%d, video_state->hchars=%d, diff=%d, refresh=%d\n",
+           PrintVerbose(core->vm_info, core, "Video: screen_offset=%d, video_state->screen_offset=%d, video_state->hchars=%d, diff=%d, refresh=%d\n",
                screen_offset, video_state->screen_offset, video_state->hchars, diff, refresh);
 
            // Update the true offset value
@@ -741,9 +743,9 @@ static int crtc_data_write(struct guest_info * core, uint16_t port, void * src,
            if (refresh || video_state->dirty) {
                refresh_screen(video_state);
            } else if (diff && video_state->ops) {
-               PrintVerbose("Video: scroll(%d)\n", diff);
+               PrintVerbose(core->vm_info, core, "Video: scroll(%d)\n", diff);
                if (video_state->ops->scroll(diff, video_state->private_data) == -1) {
-                   PrintError("Error sending scroll event\n");
+                   PrintError(core->vm_info, core, "Error sending scroll event\n");
                    return -1;
                }
            }
@@ -759,17 +761,17 @@ static int crtc_data_write(struct guest_info * core, uint16_t port, void * src,
                ((uint16_t) video_state->crtc_data_regs[CRTC_REGIDX_CURSOR_LOC_LOW]);
            x = video_state->cursor_offset % video_state->hchars;
            y = (video_state->cursor_offset - video_state->screen_offset) / video_state->hchars;
-           PrintVerbose("Video: video_state->cursor_offset=%d, x=%d, y=%d\n",
+           PrintVerbose(core->vm_info, core, "Video: video_state->cursor_offset=%d, x=%d, y=%d\n",
                video_state->cursor_offset, x, y);
 
            if (video_state->dirty) {
                refresh_screen(video_state);
            }
            
-           PrintVerbose("Video: set cursor(%d, %d)\n", x, y);
+           PrintVerbose(core->vm_info, core, "Video: set cursor(%d, %d)\n", x, y);
            if (video_state->ops) {
                if (video_state->ops->update_cursor(x, y, video_state->private_data) == -1) {
-                   PrintError("Error updating cursor\n");
+                   PrintError(core->vm_info, core, "Error updating cursor\n");
                    return -1;
                }
            } 
@@ -777,7 +779,7 @@ static int crtc_data_write(struct guest_info * core, uint16_t port, void * src,
            break;
        }
        default:
-           PrintDebug("Video: crtc[%d]=0x%x\n", index, val);
+           PrintDebug(core->vm_info, core, "Video: crtc[%d]=0x%x\n", index, val);
            break;
     }
 
@@ -802,7 +804,7 @@ static int crtc_index_write(struct guest_info * core, uint16_t port, void * src,
 
     handle_port_write(video_state, __FUNCTION__, port, src, length, 2);
     if (length > 2) {
-       PrintError("Invalid write length for crtc index register port: %d (0x%x)\n",
+       PrintError(core->vm_info, core, "Invalid write length for crtc index register port: %d (0x%x)\n",
                   port, port);
        return -1;
     }
@@ -832,7 +834,7 @@ static int graphc_data_read(struct guest_info * core, uint16_t port, void * dest
     if (index < GRAPHC_REG_COUNT) {
        *(uint8_t *) dest = video_state->graphc_data_regs[index];
     } else {
-       PrintError("Video %s: index %d out of range\n", __FUNCTION__, video_state->graphc_index_reg);
+       PrintError(core->vm_info, core, "Video %s: index %d out of range\n", __FUNCTION__, video_state->graphc_index_reg);
        *(uint8_t *) dest = 0;
     }
 
@@ -847,11 +849,11 @@ static int graphc_data_write(struct guest_info * core, uint16_t port, void * src
     handle_port_write(video_state, __FUNCTION__, port, src, length, 1);
 
     if (index < GRAPHC_REG_COUNT) {
-       PrintDebug("Video: graphc[%d]=0x%x\n", index, val);
+       PrintDebug(core->vm_info, core, "Video: graphc[%d]=0x%x\n", index, val);
        video_state->graphc_data_regs[index] = val;
        registers_updated(video_state);
     } else {
-       PrintError("Video %s: index %d out of range\n", __FUNCTION__, video_state->graphc_index_reg);
+       PrintError(core->vm_info, core, "Video %s: index %d out of range\n", __FUNCTION__, video_state->graphc_index_reg);
     }
 
     return length;    
@@ -889,7 +891,7 @@ static int attrc_data_read(struct guest_info * core, uint16_t port, void * dest,
     if (index < ATTRC_REG_COUNT) {
        *(uint8_t *) dest = video_state->attrc_data_regs[index];
     } else {
-       PrintError("Video %s: index %d out of range\n", __FUNCTION__, video_state->attrc_index_reg);
+       PrintError(core->vm_info, core, "Video %s: index %d out of range\n", __FUNCTION__, video_state->attrc_index_reg);
        *(uint8_t *) dest = 0;
     }
 
@@ -904,10 +906,10 @@ static int attrc_data_write(struct guest_info * core, uint16_t port, void * src,
     handle_port_write(video_state, __FUNCTION__, port, src, length, 1);
 
     if (index < ATTRC_REG_COUNT) {
-       PrintDebug("Video: attrc[%d]=0x%x\n", index, val);
+       PrintDebug(core->vm_info, core, "Video: attrc[%d]=0x%x\n", index, val);
        video_state->attrc_data_regs[index] = val;
     } else {
-       PrintError("Video %s: index %d out of range\n", __FUNCTION__, video_state->attrc_index_reg);
+       PrintError(core->vm_info, core, "Video %s: index %d out of range\n", __FUNCTION__, video_state->attrc_index_reg);
     }
 
     return length;    
@@ -987,7 +989,7 @@ static int dac_data_read(struct guest_info * core, uint16_t port, void * dest, u
     /* update palette */
     index = (unsigned) video_state->dac_indexr_reg * DAC_COLOR_COUNT + 
        video_state->dac_indexr_color;
-    V3_ASSERT(index < DAC_REG_COUNT);
+    V3_ASSERT(core->vm_info, core, index < DAC_REG_COUNT);
     *(uint8_t *) dest = video_state->dac_data_regs[index];
     
     /* move on to next entry/color */
@@ -1008,7 +1010,7 @@ static int dac_data_write(struct guest_info * core, uint16_t port, void * src, u
     /* update palette */
     index = (unsigned) video_state->dac_indexw_reg * DAC_COLOR_COUNT + 
        video_state->dac_indexw_color;
-    V3_ASSERT(index < DAC_REG_COUNT);
+    V3_ASSERT(core->vm_info, core, index < DAC_REG_COUNT);
     video_state->dac_data_regs[index] = *(uint8_t *) src;
     
     /* move on to next entry/color */
@@ -1068,12 +1070,12 @@ int v3_cons_get_fb_text(struct video_internal * state, uint8_t * dst, uint_t off
     uint_t framebuf_offset, len1, len2;
     uint_t screen_byte_offset = state->screen_offset * BYTES_PER_COL;
 
-    PrintVerbose("Video: getfb o=%d l=%d so=%d aa=0x%x al=0x%x hc=%d vc=%d\n",
+    PrintVerbose(VM_NONE, VCORE_NONE, "Video: getfb o=%d l=%d so=%d aa=0x%x al=0x%x hc=%d vc=%d\n",
        offset, length, state->screen_offset, 
        (unsigned) state->activefb_addr, (unsigned) state->activefb_len,
        state->hchars, state->vchars);
-    V3_ASSERT(state->activefb_addr >= START_ADDR);
-    V3_ASSERT(state->activefb_addr + state->activefb_len <= END_ADDR);
+    V3_ASSERT(VM_NONE, VCORE_NONE, state->activefb_addr >= START_ADDR);
+    V3_ASSERT(VM_NONE, VCORE_NONE, state->activefb_addr + state->activefb_len <= END_ADDR);
 
     /* Copy memory with wrapping (should be configurable, but where else to get the data?) */
     framebuf = state->framebuf + (state->activefb_addr - START_ADDR);
@@ -1081,7 +1083,8 @@ int v3_cons_get_fb_text(struct video_internal * state, uint8_t * dst, uint_t off
     len1 = min_uint(length, state->activefb_len - framebuf_offset);
     len2 = length - len1;
     if (len1 > 0) memcpy(dst, framebuf + framebuf_offset, len1);
-    if (len2 > 0) memcpy(dst + len1, framebuf, len2);
+    // the following is tagged as OOB access to dst but appears to be fine
+    if (len2 > 0) memcpy(dst + len1, framebuf, len2);  
 
     return 0;
 }
@@ -1097,10 +1100,10 @@ int v3_cons_get_fb(struct vm_device * frontend_dev, uint8_t * dst, uint_t offset
     }
 }
 
-static int free_cga(struct video_internal * video_state) {
+static int cga_free(struct video_internal * video_state) {
 
     if (video_state->framebuf_pa) {
-       PrintError("Freeing framebuffer PA %p\n", (void *)(video_state->framebuf_pa));
+       PrintDebug(VM_NONE, VCORE_NONE, "Freeing framebuffer PA %p\n", (void *)(video_state->framebuf_pa));
        V3_FreePages((void *)(video_state->framebuf_pa), (FRAMEBUF_SIZE / 4096));
     }
 
@@ -1112,8 +1115,115 @@ static int free_cga(struct video_internal * video_state) {
 }
 
 
+#ifdef V3_CONFIG_CHECKPOINT
+static int cga_save(struct v3_chkpt_ctx * ctx, void * private_data) {
+    struct video_internal * cga = (struct video_internal *)private_data;
+
+    if (v3_chkpt_save(ctx, "FRAMEBUFFER", FRAMEBUF_SIZE, cga->framebuf)) { 
+      goto savefailout;
+    }
+
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->misc_outp_reg, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->seq_index_reg, savefailout);               
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->seq_data_regs, savefailout);       
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->crtc_index_reg, savefailout);              
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->crtc_data_regs, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->graphc_index_reg, savefailout);            
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->graphc_data_regs, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->attrc_index_flipflop, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->attrc_index_reg, savefailout);     
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->attrc_data_regs, savefailout);     
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->dac_indexr_reg, savefailout);      
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->dac_indexr_color, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->dac_indexw_reg, savefailout);              
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->dac_indexw_color, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->dac_data_regs, savefailout);
+
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->activefb_addr, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->activefb_len, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->iorange, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->vres, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->hres, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->vchars, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->hchars, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->graphmode, savefailout);
+
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->dirty, savefailout);
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->reschanged, savefailout);
+
+    V3_CHKPT_SAVE_AUTOTAG(ctx, cga->passthrough, savefailout);
+
+    V3_CHKPT_SAVE(ctx, "SCREEN_OFFSET", cga->screen_offset, savefailout);
+    V3_CHKPT_SAVE(ctx, "CURSOR_OFFSET", cga->cursor_offset, savefailout);
+
+    return 0;
+
+ savefailout:
+    PrintError(VM_NONE, VCORE_NONE, "Failed to save CGA\n");
+    return -1;
+
+}
+
+static int cga_load(struct v3_chkpt_ctx * ctx, void * private_data) {
+    struct video_internal * cga = (struct video_internal *)private_data;
+
+    if (v3_chkpt_load(ctx, "FRAMEBUFFER", FRAMEBUF_SIZE, cga->framebuf)) { 
+      goto loadfailout;
+    }
+
+
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->misc_outp_reg, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->seq_index_reg, loadfailout);               
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->seq_data_regs, loadfailout);       
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->crtc_index_reg, loadfailout);              
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->crtc_data_regs, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->graphc_index_reg, loadfailout);            
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->graphc_data_regs, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->attrc_index_flipflop, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->attrc_index_reg, loadfailout);     
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->attrc_data_regs, loadfailout);     
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->dac_indexr_reg, loadfailout);      
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->dac_indexr_color, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->dac_indexw_reg, loadfailout);              
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->dac_indexw_color, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->dac_data_regs, loadfailout);
+
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->activefb_addr, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->activefb_len, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->iorange, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->vres, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->hres, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->vchars, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->hchars, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->graphmode, loadfailout);
+
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->dirty, loadfailout);
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->reschanged, loadfailout);
+
+    V3_CHKPT_LOAD_AUTOTAG(ctx, cga->passthrough, loadfailout);
+
+    V3_CHKPT_LOAD(ctx, "SCREEN_OFFSET", cga->screen_offset, loadfailout);
+    V3_CHKPT_LOAD(ctx, "CURSOR_OFFSET", cga->cursor_offset, loadfailout);
+
+
+    return 0;
+
+ loadfailout:
+    PrintError(VM_NONE, VCORE_NONE, "Failed to load cga\n");
+    return -1;
+
+}
+
+#endif
+
+
 static struct v3_device_ops dev_ops = {
-    .free = (int (*)(void *))free_cga,
+    .free = (int (*)(void *))cga_free,
+#ifdef V3_CONFIG_CHECKPOINT
+    .save = cga_save, 
+    .load = cga_load
+#endif
+
 };
 
 static int cga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
@@ -1122,15 +1232,21 @@ static int cga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     char * passthrough_str = v3_cfg_val(cfg, "passthrough");
     int ret = 0;
     
-    PrintDebug("video: init_device\n");
+    PrintDebug(vm, VCORE_NONE, "video: init_device\n");
 
     video_state = (struct video_internal *)V3_Malloc(sizeof(struct video_internal));
+
+    if (!video_state) {
+       PrintError(vm, VCORE_NONE, "Cannot allocate space for CGA state\n");
+       return -1;
+    }
+
     memset(video_state, 0, sizeof(struct video_internal));
 
     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, video_state);
 
     if (dev == NULL) {
-       PrintError("Could not attach device %s\n", dev_id);
+       PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
        V3_Free(video_state);
        return -1;
     }
@@ -1138,10 +1254,18 @@ static int cga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     video_state->dev = dev;
 
     video_state->framebuf_pa = (addr_t)V3_AllocPages(FRAMEBUF_SIZE / 4096);
+
+    if (!video_state->framebuf_pa) { 
+       PrintError(vm, VCORE_NONE, "Cannot allocate frame buffer\n");
+       V3_Free(video_state);
+       return -1;
+    }
+
     video_state->framebuf = V3_VAddr((void *)(video_state->framebuf_pa));
+
     memset(video_state->framebuf, 0, FRAMEBUF_SIZE);
 
-    PrintDebug("PA of array: %p\n", (void *)(video_state->framebuf_pa));
+    PrintDebug(vm, VCORE_NONE, "PA of array: %p\n", (void *)(video_state->framebuf_pa));
 
     if ((passthrough_str != NULL) &&
        (strcasecmp(passthrough_str, "enable") == 0)) {;
@@ -1150,15 +1274,17 @@ static int cga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
 
 
     if (video_state->passthrough) {
-       PrintDebug("Enabling CGA Passthrough\n");
+       PrintDebug(vm, VCORE_NONE, "Enabling CGA Passthrough\n");
        if (v3_hook_write_mem(vm, V3_MEM_CORE_ANY, START_ADDR, END_ADDR, 
                              START_ADDR, &video_write_mem, dev) == -1) {
-           PrintDebug("\n\nVideo Hook failed.\n\n");
+           PrintError(vm, VCORE_NONE, "\n\nVideo Hook failed.\n\n");
+           return -1;
        }
     } else {
        if (v3_hook_write_mem(vm, V3_MEM_CORE_ANY, START_ADDR, END_ADDR, 
                              video_state->framebuf_pa, &video_write_mem, dev) == -1) {
-           PrintDebug("\n\nVideo Hook failed.\n\n");
+           PrintError(vm, VCORE_NONE, "\n\nVideo Hook failed.\n\n");
+           return -1;
        }
     }
 
@@ -1197,7 +1323,7 @@ static int cga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
     ret |= v3_dev_hook_io(dev, 0x3c6, &dac_pelmask_read, &dac_pelmask_write);
 
     if (ret != 0) {
-       PrintError("Error allocating VGA IO ports\n");
+       PrintError(vm, VCORE_NONE, "Error allocating VGA IO ports\n");
        v3_remove_device(dev);
        return -1;
     }