diff --git a/hw/sm501.c b/hw/sm501.c
index cd1f595..ade88ff 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -29,16 +29,16 @@
  #include "devices.h"
  
  /*
- * Status: 2008/11/02
+ * Status: 2010/05/07
   *   - Minimum implementation for Linux console : mmio regs and CRT layer.
- *   - Always updates full screen.
+ *   - 2D grapihcs acceleration partially supported : only fill rectangle.
   *
   * TODO:
   *   - Panel support
- *   - Hardware cursor support
   *   - Touch panel support
   *   - USB support
   *   - UART support
+ *   - More 2D graphics engine support
   *   - Performance tuning
   */
  
@@ -508,6 +508,18 @@ typedef struct SM501State {
      uint32_t dc_crt_hwc_color_1_2;
      uint32_t dc_crt_hwc_color_3;
  
+    uint32_t _2d_destination;
+    uint32_t _2d_dimension;
+    uint32_t _2d_control;
+    uint32_t _2d_pitch;
+    uint32_t _2d_foreground;
+    uint32_t _2d_stretch;
+    uint32_t _2d_color_compare_mask;
+    uint32_t _2d_mask;
+    uint32_t _2d_window_width;
+    uint32_t _2d_source_base;
+    uint32_t _2d_destination_base;
+
  } SM501State;
  
  static uint32_t get_local_mem_size_index(uint32_t size)
@@ -617,6 +629,69 @@ static int within_hwc_y_range(SM501State *state, int y, int crt)
      return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
  }
  
+static void sm501_2d_operation(SM501State * s)
+{
+    /* obtain operation parameters */
+    int operation = (s->_2d_control >> 16) & 0x1f;
+    int dst_x = (s->_2d_destination >> 16) & 0x01FFF;
+    int dst_y = s->_2d_destination & 0xFFFF;
+    int operation_width = (s->_2d_dimension >> 16) & 0x1FFF;
+    int operation_height = s->_2d_dimension & 0xFFFF;
+    uint32_t color = s->_2d_foreground;
+    int format_flags = (s->_2d_stretch >> 20) & 0x3;
+    int addressing = (s->_2d_stretch >> 16) & 0xF;
+
+    /* get frame buffer info */
+#if 0 /* for future use */
+    uint8_t * src = s->local_mem + (s->_2d_source_base & 0x03FFFFFF);
+#endif
+    uint8_t * dst = s->local_mem + (s->_2d_destination_base & 0x03FFFFFF);
+    int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+
+    if (addressing != 0x0) {
+        printf("%s: only XY addressing is supported.\n", __func__);
+        abort();
+    }
+
+    if ((s->_2d_source_base & 0x08000000) ||
+        (s->_2d_destination_base & 0x08000000)) {
+        printf("%s: only local memory is supported.\n", __func__);
+        abort();
+    }
+
+    switch (operation) {
+    case 0x01: /* fill rectangle */
+
+#define FILL_RECT(_bpp, _pixel_type) {                                      \
+        int y, x;                                                           \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
+                *(_pixel_type*)&dst[index] = (_pixel_type)color;            \
+            }                                                               \
+        }                                                                   \
+    }
+
+        switch (format_flags) {
+        case 0:
+            FILL_RECT(1, uint8_t);
+            break;
+        case 1:
+            FILL_RECT(2, uint16_t);
+            break;
+        case 2:
+            FILL_RECT(4, uint32_t);
+            break;
+        }
+        break;
+
+    default:
+        printf("non-implemented SM501 2D operation. %d\n", operation);
+        abort();
+        break;
+    }
+}
+
  static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr)
  {
      SM501State * s = (SM501State *)opaque;
@@ -967,6 +1042,92 @@ static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = {
      &sm501_disp_ctrl_write,
  };
  
+static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+    case SM501_2D_SOURCE_BASE:
+        ret = s->_2d_source_base;
+        break;
+    default:
+        printf("sm501 disp ctrl : not implemented register read."
+               " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_2d_engine_write(void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
+                  addr, value);
+
+    switch(addr) {
+    case SM501_2D_DESTINATION:
+        s->_2d_destination = value;
+        break;
+    case SM501_2D_DIMENSION:
+        s->_2d_dimension = value;
+        break;
+    case SM501_2D_CONTROL:
+        s->_2d_control = value;
+
+        /* do 2d operation if start flag is set. */
+        if (value & 0x80000000) {
+            sm501_2d_operation(s);
+            s->_2d_control &= ~0x80000000; /* start flag down */
+        }
+
+        break;
+    case SM501_2D_PITCH:
+        s->_2d_pitch = value;
+        break;
+    case SM501_2D_FOREGROUND:
+        s->_2d_foreground = value;
+        break;
+    case SM501_2D_STRETCH:
+        s->_2d_stretch = value;
+        break;
+    case SM501_2D_COLOR_COMPARE_MASK:
+        s->_2d_color_compare_mask = value;
+        break;
+    case SM501_2D_MASK:
+        s->_2d_mask = value;
+        break;
+    case SM501_2D_WINDOW_WIDTH:
+        s->_2d_window_width = value;
+        break;
+    case SM501_2D_SOURCE_BASE:
+        s->_2d_source_base = value;
+        break;
+    case SM501_2D_DESTINATION_BASE:
+        s->_2d_destination_base = value;
+        break;
+    default:
+        printf("sm501 2d engine : not implemented register write."
+               " addr=%x, val=%x\n", (int)addr, value);
+        abort();
+    }
+}
+
+static CPUReadMemoryFunc * const sm501_2d_engine_readfn[] = {
+    NULL,
+    NULL,
+    &sm501_2d_engine_read,
+};
+
+static CPUWriteMemoryFunc * const sm501_2d_engine_writefn[] = {
+    NULL,
+    NULL,
+    &sm501_2d_engine_write,
+};
+
  /* draw line functions for all console modes */
  
  #include "pixel_ops.h"
@@ -1192,6 +1353,7 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
      SM501State * s;
      int sm501_system_config_index;
      int sm501_disp_ctrl_index;
+    int sm501_2d_engine_index;
  
      /* allocate management data region */
      s = (SM501State *)qemu_mallocz(sizeof(SM501State));
@@ -1220,6 +1382,10 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
  						   sm501_disp_ctrl_writefn, s);
      cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
                                   0x1000, sm501_disp_ctrl_index);
+    sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn,
+                                                   sm501_2d_engine_writefn, s);
+    cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
+                                 0x54, sm501_2d_engine_index);
  
      /* bridge to usb host emulation module */
      usb_ohci_init_sm501(base + MMIO_BASE_OFFSET + SM501_USB_HOST, base,
