VNC: Add VNC server to M5
authorAli Saidi <Ali.Saidi@ARM.com>
Sat, 12 Feb 2011 00:29:35 +0000 (18:29 -0600)
committerAli Saidi <Ali.Saidi@ARM.com>
Sat, 12 Feb 2011 00:29:35 +0000 (18:29 -0600)
configs/common/FSConfig.py
src/base/SConscript
src/base/bitmap.cc [new file with mode: 0644]
src/base/bitmap.hh [new file with mode: 0644]
src/base/compiler.hh
src/base/vnc/SConscript [new file with mode: 0644]
src/base/vnc/VncServer.py [new file with mode: 0644]
src/base/vnc/convert.cc [new file with mode: 0644]
src/base/vnc/convert.hh [new file with mode: 0644]
src/base/vnc/vncserver.cc [new file with mode: 0644]
src/base/vnc/vncserver.hh [new file with mode: 0644]

index 9e5fd3a0b11827c7ca4154d4ddb3a437e00eeb04..f58fd3d2e91ba6542371c814f80a6c54f2e86743 100644 (file)
@@ -238,6 +238,7 @@ def makeLinuxArmSystem(mem_mode, mdesc = None, bare_metal=False,
 
     self.intrctrl = IntrControl()
     self.terminal = Terminal()
+    self.vncserver = VncServer()
     self.kernel = binary('vmlinux.arm')
     self.boot_osflags = 'earlyprintk mem=128MB console=ttyAMA0 lpj=19988480' + \
                         ' norandmaps slram=slram0,0x8000000,+0x8000000' +      \
index 2bb6b13ab873cb928ed34898fa1f53c4969e9dcb..3f069bf9eefd1e9d14c0f5b85c779f4aaa4dcee7 100644 (file)
@@ -35,6 +35,7 @@ if env['CP_ANNOTATE']:
     Source('cp_annotate.cc')
 Source('atomicio.cc')
 Source('bigint.cc')
+Source('bitmap.cc')
 Source('callback.cc')
 Source('circlebuf.cc')
 Source('cprintf.cc')
diff --git a/src/base/bitmap.cc b/src/base/bitmap.cc
new file mode 100644 (file)
index 0000000..0d2a930
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: William Wang
+ *          Ali Saidi
+ */
+
+#include <cassert>
+
+#include "base/bitmap.hh"
+#include "base/misc.hh"
+
+// bitmap class ctor
+Bitmap::Bitmap(VideoConvert::Mode _mode, uint16_t w, uint16_t h, uint8_t *d)
+    : mode(_mode), height(h), width(w), data(d),
+    vc(mode, VideoConvert::rgb8888, width, height)
+{
+}
+
+void
+Bitmap::write(std::ostream *bmp)
+{
+    assert(data);
+
+    // For further information see: http://en.wikipedia.org/wiki/BMP_file_format
+    Magic  magic = {{'B','M'}};
+    Header header = {sizeof(VideoConvert::Rgb8888) * width * height , 0, 0, 54};
+    Info   info = {sizeof(Info), width, height, 1,
+                   sizeof(VideoConvert::Rgb8888) * 8, 0,
+                   sizeof(VideoConvert::Rgb8888) * width * height, 1, 1, 0, 0};
+
+    bmp->write(reinterpret_cast<char*>(&magic),  sizeof(magic));
+    bmp->write(reinterpret_cast<char*>(&header), sizeof(header));
+    bmp->write(reinterpret_cast<char*>(&info),   sizeof(info));
+
+    uint8_t *tmp = vc.convert(data);
+    uint32_t *tmp32 = (uint32_t*)tmp;
+
+    // BMP start store data left to right starting with the bottom row
+    // so we need to do some creative flipping
+    for (int i = height - 1; i >= 0; i--)
+        for (int j = 0; j < width; j++)
+            bmp->write((char*)&tmp32[i * width + j], sizeof(uint32_t));
+
+    bmp->flush();
+
+    delete [] tmp;
+}
+
diff --git a/src/base/bitmap.hh b/src/base/bitmap.hh
new file mode 100644 (file)
index 0000000..9dfaa87
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: William Wang
+ *          Ali Saidi
+ */
+#ifndef __BASE_BITMAP_HH__
+#define __BASE_BITMAP_HH__
+
+#include <fstream>
+
+#include "base/vnc/convert.hh"
+
+/**
+ * @file Declaration of a class that writes a frame buffer to a bitmap
+ */
+
+
+// write frame buffer into a bitmap picture
+class  Bitmap
+{
+  public:
+    /** Create a Bitmap creator that takes data in the given mode & size
+     * and outputs to an fstream
+     * @param mode the type of data that is being provided
+     * @param h the hight of the image
+     * @param w the width of the image
+     * @param d the data for the image in mode
+     */
+    Bitmap(VideoConvert::Mode mode, uint16_t w, uint16_t h, uint8_t *d);
+
+    /** Provide the converter with the data that should be output. It will be
+     * converted into rgb8888 and write out when write() is called.
+     * @param d the data
+     */
+    void rawData(uint8_t* d) { data = d; }
+
+    /** Write the provided data into the fstream provided
+     * @param bmp stream to write to
+     */
+    void write(std::ostream *bmp);
+
+  private:
+    VideoConvert::Mode mode;
+    uint16_t height;
+    uint16_t width;
+    uint8_t *data;
+
+    VideoConvert vc;
+
+    struct Magic
+    {
+        unsigned char magic_number[2];
+    };
+
+    struct Header
+    {
+        uint32_t size;
+        uint16_t reserved1;
+        uint16_t reserved2;
+        uint32_t offset;
+    };
+
+    struct Info
+    {
+        uint32_t Size;
+        uint32_t Width;
+        uint32_t Height;
+        uint16_t Planes;
+        uint16_t BitCount;
+        uint32_t Compression;
+        uint32_t SizeImage;
+        uint32_t XPelsPerMeter;
+        uint32_t YPelsPerMeter;
+        uint32_t ClrUsed;
+        uint32_t ClrImportant;
+    };
+};
+
+#endif // __BASE_BITMAP_HH__
+
index 2c655af608959070d0642cb30c6cb1fcfd3c206c..3315fb2f7473cdf57108bcb7e86553867ed6aeec 100644 (file)
@@ -41,6 +41,7 @@
 #define M5_PRAGMA_NORETURN(x)
 #define M5_DUMMY_RETURN
 #define M5_VAR_USED __attribute__((unused))
+#define M5_ATTR_PACKED __attribute__ ((__packed__))
 #elif defined(__SUNPRO_CC)
 // this doesn't do anything with sun cc, but why not
 #define M5_ATTR_NORETURN  __sun_attr__((__noreturn__))
@@ -48,6 +49,7 @@
 #define DO_PRAGMA(x) _Pragma(#x)
 #define M5_VAR_USED
 #define M5_PRAGMA_NORETURN(x) DO_PRAGMA(does_not_return(x))
+#define M5_ATTR_PACKED __attribute__ ((__packed__))
 #else
 #error "Need to define compiler options in base/compiler.hh"
 #endif
diff --git a/src/base/vnc/SConscript b/src/base/vnc/SConscript
new file mode 100644 (file)
index 0000000..c926765
--- /dev/null
@@ -0,0 +1,48 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2010 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: William Wang
+
+Import('*')
+
+if env['FULL_SYSTEM']:
+    SimObject('VncServer.py')
+    Source('vncserver.cc')
+    TraceFlag('VNC')
+
+Source('convert.cc')
+
diff --git a/src/base/vnc/VncServer.py b/src/base/vnc/VncServer.py
new file mode 100644 (file)
index 0000000..21eb3ed
--- /dev/null
@@ -0,0 +1,45 @@
+# Copyright (c) 2010 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: William Wang
+
+from m5.SimObject import SimObject
+from m5.params import *
+from m5.proxy import *
+
+class VncServer(SimObject):
+    type = 'VncServer'
+    port = Param.TcpPort(5900, "listen port")
+    number = Param.Int(0, "vnc client number")
diff --git a/src/base/vnc/convert.cc b/src/base/vnc/convert.cc
new file mode 100644 (file)
index 0000000..ea7a9b1
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ *          William Wang
+ */
+
+#include <cassert>
+
+#include "base/misc.hh"
+#include "base/vnc/convert.hh"
+
+/** @file
+ * This file provides conversion functions for a variety of video modes
+ */
+
+VideoConvert::VideoConvert(Mode input_mode, Mode output_mode, int _width,
+        int _height)
+    : inputMode(input_mode), outputMode(output_mode), width(_width),
+    height(_height)
+{
+    if (inputMode != bgr565 && inputMode != rgb565 && inputMode != bgr8888)
+        fatal("Only support converting from bgr565, rdb565, and bgr8888\n");
+
+    if (outputMode != rgb8888)
+        fatal("Only support converting to rgb8888\n");
+
+    assert(0 < height && height < 4000);
+    assert(0 < width && width < 4000);
+}
+
+VideoConvert::~VideoConvert()
+{
+}
+
+uint8_t*
+VideoConvert::convert(uint8_t *fb)
+{
+    switch (inputMode) {
+      case bgr565:
+        return m565rgb8888(fb, true);
+      case rgb565:
+        return m565rgb8888(fb, false);
+      case bgr8888:
+        return bgr8888rgb8888(fb);
+      default:
+        panic("Unimplemented Mode\n");
+    }
+}
+
+uint8_t*
+VideoConvert::m565rgb8888(uint8_t *fb, bool bgr)
+{
+    uint8_t *out = new uint8_t[area() * sizeof(uint32_t)];
+    uint32_t *out32 = (uint32_t*)out;
+
+    uint16_t *in16 = (uint16_t*)fb;
+
+    for (int x = 0; x < area(); x++) {
+        Bgr565 inpx;
+        Rgb8888 outpx = 0;
+
+        inpx = in16[x];
+
+        if (bgr) {
+            outpx.red = inpx.blue << 3;
+            outpx.green = inpx.green << 2;
+            outpx.blue = inpx.red << 3;
+        } else {
+            outpx.blue = inpx.blue << 3;
+            outpx.green = inpx.green << 2;
+            outpx.red = inpx.red << 3;
+        }
+
+        out32[x] = outpx;
+    }
+
+    return out;
+}
+
+
+uint8_t*
+VideoConvert::bgr8888rgb8888(uint8_t *fb)
+{
+    uint8_t *out = new uint8_t[area() * sizeof(uint32_t)];
+    uint32_t *out32 = (uint32_t*)out;
+
+    uint32_t *in32 = (uint32_t*)fb;
+
+    for (int x = 0; x < area(); x++) {
+        Rgb8888 outpx = 0;
+        Bgr8888 inpx;
+
+
+        inpx = in32[x];
+
+        outpx.red = inpx.blue;
+        outpx.green = inpx.green;
+        outpx.blue = inpx.red;
+
+        out32[x] = outpx;
+    }
+
+    return out;
+}
+
diff --git a/src/base/vnc/convert.hh b/src/base/vnc/convert.hh
new file mode 100644 (file)
index 0000000..68a21d6
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/** @file
+ * This file provides conversion functions for a variety of video modes
+ */
+
+#ifndef __BASE_VNC_CONVERT_HH__
+#define __BASE_VNC_CONVERT_HH__
+
+#include "base/bitunion.hh"
+
+class VideoConvert
+{
+  public:
+    enum Mode {
+        UnknownMode,
+        bgr565,
+        rgb565,
+        bgr8888,
+        rgb8888,
+        rgb888,
+        bgr888,
+        bgr444,
+        bgr4444,
+        rgb444,
+        rgb4444,
+    };
+
+    // supports bpp32 RGB (bmp) and bpp16 5:6:5 mode BGR (linux)
+    BitUnion32(Rgb8888)
+        Bitfield<7,0> blue;
+        Bitfield<15,8> green;
+        Bitfield<23,16> red;
+        Bitfield<31,24> alpha;
+    EndBitUnion(Rgb8888)
+
+    BitUnion32(Bgr8888)
+        Bitfield<7,0> red;
+        Bitfield<15,8> green;
+        Bitfield<23,16> blue;
+        Bitfield<31,24> alpha;
+    EndBitUnion(Bgr8888)
+
+    BitUnion16(Bgr565)
+        Bitfield<4,0> red;
+        Bitfield<10,5> green;
+        Bitfield<15,11> blue;
+    EndBitUnion(Bgr565)
+
+    BitUnion16(Rgb565)
+        Bitfield<4,0> red;
+        Bitfield<10,5> green;
+        Bitfield<15,11> blue;
+    EndBitUnion(Rgb565)
+
+    /** Setup the converter with the given parameters
+     * @param input_mode type of data that will be provided
+     * @param output_mode type of data that should be output
+     * @param _width width of the frame buffer
+     * @param _height height of the frame buffer
+     */
+    VideoConvert(Mode input_mode, Mode output_mode, int _width, int _height);
+
+    /** Destructor
+     */
+    ~VideoConvert();
+
+    /** Convert the provided frame buffer data into the format specified in the
+     * constructor.
+     * @param fb the frame buffer to convert
+     * @return the converted data (user must free)
+     */
+    uint8_t* convert(uint8_t *fb);
+
+    /** Return the number of pixels that this buffer specifies
+     * @return number of pixels
+     */
+    int area() { return width * height; }
+
+  private:
+
+    /**
+     * Convert a bgr8888 input to rgb8888.
+     * @param fb the data to convert
+     * @return converted data
+     */
+    uint8_t* bgr8888rgb8888(uint8_t *fb);
+
+    /**
+     * Convert a bgr565 or rgb565 input to rgb8888.
+     * @param fb the data to convert
+     * @param bgr true if the input data is bgr565
+     * @return converted data
+     */
+    uint8_t* m565rgb8888(uint8_t *fb, bool bgr);
+
+    Mode inputMode;
+    Mode outputMode;
+    int width;
+    int height;
+};
+
+#endif // __BASE_VNC_CONVERT_HH__
+
diff --git a/src/base/vnc/vncserver.cc b/src/base/vnc/vncserver.cc
new file mode 100644 (file)
index 0000000..8936fa6
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ *          William Wang
+ */
+
+/** @file
+ * Implementiation of a VNC server
+ */
+
+#include <cstdio>
+
+#include <sys/ioctl.h>
+#include <sys/termios.h>
+#include <errno.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "base/atomicio.hh"
+#include "base/misc.hh"
+#include "base/socket.hh"
+#include "base/trace.hh"
+#include "base/vnc/vncserver.hh"
+#include "sim/byteswap.hh"
+
+using namespace std;
+
+/**
+ * Poll event for the listen socket
+ */
+VncServer::ListenEvent::ListenEvent(VncServer *vs, int fd, int e)
+    : PollEvent(fd, e), vncserver(vs)
+{
+}
+
+void
+VncServer::ListenEvent::process(int revent)
+{
+    vncserver->accept();
+}
+
+/**
+ * Poll event for the data socket
+ */
+VncServer::DataEvent::DataEvent(VncServer *vs, int fd, int e)
+    : PollEvent(fd, e), vncserver(vs)
+{
+}
+
+void
+VncServer::DataEvent::process(int revent)
+{
+    if (revent & POLLIN)
+        vncserver->data();
+    else if (revent & POLLNVAL)
+        vncserver->detach();
+}
+
+/**
+ * VncServer
+ */
+VncServer::VncServer(const Params *p)
+    : SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number),
+      dataFd(-1), _videoWidth(1), _videoHeight(1), clientRfb(0), keyboard(NULL),
+      mouse(NULL), sendUpdate(false), videoMode(VideoConvert::UnknownMode),
+      vc(NULL)
+{
+    if (p->port)
+        listen(p->port);
+
+    curState = WaitForProtocolVersion;
+
+
+    // currently we only support this one pixel format
+    // unpacked 32bit rgb (rgb888 + 8 bits of nothing/alpha)
+    // keep it around for telling the client and making
+    // sure the client cooperates
+    pixelFormat.bpp = 32;
+    pixelFormat.depth = 24;
+    pixelFormat.bigendian = 0;
+    pixelFormat.truecolor = 1;
+    pixelFormat.redmax = 0xff;
+    pixelFormat.greenmax = 0xff;
+    pixelFormat.bluemax = 0xff;
+    pixelFormat.redshift = 16;
+    pixelFormat.greenshift = 8;
+    pixelFormat.blueshift = 0;
+
+
+    DPRINTF(VNC, "Vnc server created at port %d\n", p->port);
+}
+
+VncServer::~VncServer()
+{
+    if (dataFd != -1)
+        ::close(dataFd);
+
+    if (listenEvent)
+        delete listenEvent;
+
+    if (dataEvent)
+        delete dataEvent;
+}
+
+
+//socket creation and vnc client attach
+void
+VncServer::listen(int port)
+{
+    if (ListenSocket::allDisabled()) {
+        warn_once("Sockets disabled, not accepting vnc client connections");
+        return;
+    }
+
+    while (!listener.listen(port, true)) {
+        DPRINTF(VNC,
+                "can't bind address vnc server port %d in use PID %d\n",
+                port, getpid());
+        port++;
+    }
+
+    int p1, p2;
+    p2 = name().rfind('.') - 1;
+    p1 = name().rfind('.', p2);
+    ccprintf(cerr, "Listening for %s connection on port %d\n",
+             name().substr(p1 + 1, p2 - p1), port);
+
+    listenEvent = new ListenEvent(this, listener.getfd(), POLLIN);
+    pollQueue.schedule(listenEvent);
+}
+
+// attach a vnc client
+void
+VncServer::accept()
+{
+    if (!listener.islistening())
+        panic("%s: cannot accept a connection if not listening!", name());
+
+    int fd = listener.accept(true);
+    if (dataFd != -1) {
+        char message[] = "vnc server already attached!\n";
+        atomic_write(fd, message, sizeof(message));
+        ::close(fd);
+        return;
+    }
+
+    dataFd = fd;
+
+    // Send our version number to the client
+    write((uint8_t*)vncVersion(), strlen(vncVersion()));
+
+    // read the client response
+    dataEvent = new DataEvent(this, dataFd, POLLIN);
+    pollQueue.schedule(dataEvent);
+
+    inform("VNC client attached\n");
+}
+
+// data called by data event
+void
+VncServer::data()
+{
+    // We have new data, see if we can handle it
+    size_t len;
+    DPRINTF(VNC, "Vnc client message recieved\n");
+
+    switch (curState) {
+      case WaitForProtocolVersion:
+        checkProtocolVersion();
+        break;
+      case WaitForSecurityResponse:
+        checkSecurity();
+        break;
+      case WaitForClientInit:
+        // Don't care about shared, just need to read it out of the socket
+        uint8_t shared;
+        len = read(&shared);
+        assert(len == 1);
+
+        // Send our idea of the frame buffer
+        sendServerInit();
+
+        break;
+      case NormalPhase:
+        uint8_t message_type;
+        len = read(&message_type);
+        if (!len) {
+            detach();
+            return;
+        }
+        assert(len == 1);
+
+        switch (message_type) {
+          case ClientSetPixelFormat:
+            setPixelFormat();
+            break;
+          case ClientSetEncodings:
+            setEncodings();
+            break;
+          case ClientFrameBufferUpdate:
+             requestFbUpdate();
+             break;
+          case ClientKeyEvent:
+             recvKeyboardInput();
+             break;
+          case ClientPointerEvent:
+             recvPointerInput();
+             break;
+          case ClientCutText:
+             recvCutText();
+             break;
+          default:
+             panic("Unimplemented message type recv from client: %d\n",
+                     message_type);
+             break;
+        }
+        break;
+      default:
+        panic("Unknown vnc server state\n");
+    }
+}
+
+
+// read from socket
+size_t
+VncServer::read(uint8_t *buf, size_t len)
+{
+    if (dataFd < 0)
+        panic("vnc not properly attached.\n");
+
+    size_t ret;
+    do {
+        ret = ::read(dataFd, buf, len);
+    } while (ret == -1 && errno == EINTR);
+
+
+    if (ret <= 0){
+        DPRINTF(VNC, "Read failed.\n");
+        detach();
+        return 0;
+    }
+
+    return ret;
+}
+
+size_t
+VncServer::read1(uint8_t *buf, size_t len)
+{
+    size_t read_len M5_VAR_USED;
+    read_len = read(buf + 1, len - 1);
+    assert(read_len == len - 1);
+    return read_len;
+}
+
+
+template<typename T>
+size_t
+VncServer::read(T* val)
+{
+    return read((uint8_t*)val, sizeof(T));
+}
+
+// write to socket
+size_t
+VncServer::write(const uint8_t *buf, size_t len)
+{
+    if (dataFd < 0)
+        panic("Vnc client not properly attached.\n");
+
+    ssize_t ret;
+    ret = atomic_write(dataFd, buf, len);
+
+    if (ret < len)
+        detach();
+
+    return ret;
+}
+
+template<typename T>
+size_t
+VncServer::write(T* val)
+{
+    return write((uint8_t*)val, sizeof(T));
+}
+
+size_t
+VncServer::write(const char* str)
+{
+    return write((uint8_t*)str, strlen(str));
+}
+
+// detach a vnc client
+void
+VncServer::detach()
+{
+    if (dataFd != -1) {
+        ::close(dataFd);
+        dataFd = -1;
+    }
+
+    if (!dataEvent || !dataEvent->queued())
+        return;
+
+    pollQueue.remove(dataEvent);
+    delete dataEvent;
+    dataEvent = NULL;
+    curState = WaitForProtocolVersion;
+
+    inform("VNC client detached\n");
+    DPRINTF(VNC, "detach vnc client %d\n", number);
+}
+
+void
+VncServer::sendError(const char* error_msg)
+{
+   uint32_t len = strlen(error_msg);
+   write(&len);
+   write(error_msg);
+}
+
+void
+VncServer::checkProtocolVersion()
+{
+    assert(curState == WaitForProtocolVersion);
+
+    size_t len M5_VAR_USED;
+    char version_string[13];
+
+    // Null terminate the message so it's easier to work with
+    version_string[12] = 0;
+
+    len = read((uint8_t*)version_string, 12);
+    assert(len == 12);
+
+    uint32_t major, minor;
+
+    // Figure out the major/minor numbers
+    if (sscanf(version_string, "RFB %03d.%03d\n", &major, &minor) != 2) {
+        warn(" Malformed protocol version %s\n", version_string);
+        sendError("Malformed protocol version\n");
+        detach();
+    }
+
+    DPRINTF(VNC, "Client request protocol version %d.%d\n", major, minor);
+
+    // If it's not 3.X we don't support it
+    if (major != 3 || minor < 2) {
+        warn("Unsupported VNC client version... disconnecting\n");
+        uint8_t err = AuthInvalid;
+        write(&err);
+        detach();
+    }
+    // Auth is different based on version number
+    if (minor < 7) {
+        uint32_t sec_type = htobe((uint32_t)AuthNone);
+        write(&sec_type);
+    } else {
+        uint8_t sec_cnt = 1;
+        uint8_t sec_type = htobe((uint8_t)AuthNone);
+        write(&sec_cnt);
+        write(&sec_type);
+    }
+
+    // Wait for client to respond
+    curState = WaitForSecurityResponse;
+}
+
+void
+VncServer::checkSecurity()
+{
+    assert(curState == WaitForSecurityResponse);
+
+    uint8_t security_type;
+    size_t len M5_VAR_USED = read(&security_type);
+
+    assert(len == 1);
+
+    if (security_type != AuthNone) {
+        warn("Unknown VNC security type\n");
+        sendError("Unknown security type\n");
+    }
+
+    DPRINTF(VNC, "Sending security auth OK\n");
+
+    uint32_t success = htobe(VncOK);
+    write(&success);
+    curState = WaitForClientInit;
+}
+
+void
+VncServer::sendServerInit()
+{
+    ServerInitMsg msg;
+
+    DPRINTF(VNC, "Sending server init message to client\n");
+
+    msg.fbWidth = htobe(videoWidth());
+    msg.fbHeight = htobe(videoHeight());
+
+    msg.px.bpp = htobe(pixelFormat.bpp);
+    msg.px.depth = htobe(pixelFormat.depth);
+    msg.px.bigendian = htobe(pixelFormat.bigendian);
+    msg.px.truecolor = htobe(pixelFormat.truecolor);
+    msg.px.redmax = htobe(pixelFormat.redmax);
+    msg.px.greenmax = htobe(pixelFormat.greenmax);
+    msg.px.bluemax = htobe(pixelFormat.bluemax);
+    msg.px.redshift = htobe(pixelFormat.redshift);
+    msg.px.greenshift = htobe(pixelFormat.greenshift);
+    msg.px.blueshift = htobe(pixelFormat.blueshift);
+    memset(msg.px.padding, 0, 3);
+    msg.namelen = 2;
+    msg.namelen = htobe(msg.namelen);
+    memcpy(msg.name, "M5", 2);
+
+    write(&msg);
+    curState = NormalPhase;
+}
+
+
+void
+VncServer::setPixelFormat()
+{
+    DPRINTF(VNC, "Received pixel format from client message\n");
+
+    PixelFormatMessage pfm;
+    read1((uint8_t*)&pfm, sizeof(PixelFormatMessage));
+
+    DPRINTF(VNC, " -- bpp = %d; depth = %d; be = %d\n", pfm.px.bpp,
+            pfm.px.depth, pfm.px.bigendian);
+    DPRINTF(VNC, " -- true color = %d red,green,blue max = %d,%d,%d\n",
+            pfm.px.truecolor, betoh(pfm.px.redmax), betoh(pfm.px.greenmax),
+                betoh(pfm.px.bluemax));
+    DPRINTF(VNC, " -- red,green,blue shift = %d,%d,%d\n", pfm.px.redshift,
+            pfm.px.greenshift, pfm.px.blueshift);
+
+    if (betoh(pfm.px.bpp) != pixelFormat.bpp ||
+        betoh(pfm.px.depth) != pixelFormat.depth ||
+        betoh(pfm.px.bigendian) != pixelFormat.bigendian ||
+        betoh(pfm.px.truecolor) != pixelFormat.truecolor ||
+        betoh(pfm.px.redmax) != pixelFormat.redmax ||
+        betoh(pfm.px.greenmax) != pixelFormat.greenmax ||
+        betoh(pfm.px.bluemax) != pixelFormat.bluemax ||
+        betoh(pfm.px.redshift) != pixelFormat.redshift ||
+        betoh(pfm.px.greenshift) != pixelFormat.greenshift ||
+        betoh(pfm.px.blueshift) != pixelFormat.blueshift)
+        fatal("VNC client doesn't support true color raw encoding\n");
+}
+
+void
+VncServer::setEncodings()
+{
+    DPRINTF(VNC, "Received supported encodings from client\n");
+
+    PixelEncodingsMessage pem;
+    read1((uint8_t*)&pem, sizeof(PixelEncodingsMessage));
+
+    pem.num_encodings = betoh(pem.num_encodings);
+
+    DPRINTF(VNC, " -- %d encoding present\n", pem.num_encodings);
+    supportsRawEnc = supportsResizeEnc = false;
+
+    for (int x = 0; x < pem.num_encodings; x++) {
+        int32_t encoding;
+        size_t len M5_VAR_USED;
+        len = read(&encoding);
+        assert(len == sizeof(encoding));
+        DPRINTF(VNC, " -- supports %d\n", betoh(encoding));
+
+        switch (betoh(encoding)) {
+          case EncodingRaw:
+            supportsRawEnc = true;
+            break;
+          case EncodingDesktopSize:
+            supportsResizeEnc = true;
+            break;
+        }
+    }
+
+    if (!supportsRawEnc)
+        fatal("VNC clients must always support raw encoding\n");
+}
+
+void
+VncServer::requestFbUpdate()
+{
+    DPRINTF(VNC, "Received frame buffer update request from client\n");
+
+    FrameBufferUpdateReq fbr;
+    read1((uint8_t*)&fbr, sizeof(FrameBufferUpdateReq));
+
+    fbr.x = betoh(fbr.x);
+    fbr.y = betoh(fbr.y);
+    fbr.width = betoh(fbr.width);
+    fbr.height = betoh(fbr.height);
+
+    DPRINTF(VNC, " -- x = %d y = %d w = %d h = %d\n", fbr.x, fbr.y, fbr.width,
+            fbr.height);
+
+    sendFrameBufferUpdate();
+}
+
+void
+VncServer::recvKeyboardInput()
+{
+    DPRINTF(VNC, "Received keyboard input from client\n");
+    KeyEventMessage kem;
+    read1((uint8_t*)&kem, sizeof(KeyEventMessage));
+
+    kem.key = betoh(kem.key);
+    DPRINTF(VNC, " -- received key code %d (%s)\n", kem.key, kem.down_flag ?
+            "down" : "up");
+
+    if (keyboard)
+        keyboard->keyPress(kem.key, kem.down_flag);
+}
+
+void
+VncServer::recvPointerInput()
+{
+    DPRINTF(VNC, "Received pointer input from client\n");
+    PointerEventMessage pem;
+
+    read1((uint8_t*)&pem, sizeof(PointerEventMessage));;
+
+    pem.x = betoh(pem.x);
+    pem.y = betoh(pem.y);
+    DPRINTF(VNC, " -- pointer at x = %d y = %d buttons = %#x\n", pem.x, pem.y,
+            pem.button_mask);
+
+    if (mouse)
+        mouse->mouseAt(pem.x, pem.y, pem.button_mask);
+}
+
+void
+VncServer::recvCutText()
+{
+    DPRINTF(VNC, "Received client copy buffer message\n");
+
+    ClientCutTextMessage cct;
+    read1((uint8_t*)&cct, sizeof(ClientCutTextMessage));
+
+    char str[1025];
+    size_t data_len = betoh(cct.length);
+    DPRINTF(VNC, "String length %d\n", data_len);
+    while (data_len > 0) {
+        size_t len;
+        size_t bytes_to_read = data_len > 1024 ? 1024 : data_len;
+        len = read((uint8_t*)&str, bytes_to_read);
+        str[bytes_to_read] = 0;
+        data_len -= len;
+        assert(data_len >= 0);
+        DPRINTF(VNC, "Buffer: %s\n", str);
+    }
+
+}
+
+
+void
+VncServer::sendFrameBufferUpdate()
+{
+
+    if (!clientRfb || dataFd <= 0 || curState != NormalPhase || !sendUpdate) {
+        DPRINTF(VNC, "NOT sending framebuffer update\n");
+        return;
+    }
+
+    assert(vc);
+
+    // The client will request data constantly, unless we throttle it
+    sendUpdate = false;
+
+    DPRINTF(VNC, "Sending framebuffer update\n");
+
+    FrameBufferUpdate fbu;
+    FrameBufferRect fbr;
+
+    fbu.type = ServerFrameBufferUpdate;
+    fbu.num_rects = 1;
+    fbr.x = 0;
+    fbr.y = 0;
+    fbr.width = videoWidth();
+    fbr.height = videoHeight();
+    fbr.encoding = EncodingRaw;
+
+    // fix up endian
+    fbu.num_rects = htobe(fbu.num_rects);
+    fbr.x = htobe(fbr.x);
+    fbr.y = htobe(fbr.y);
+    fbr.width = htobe(fbr.width);
+    fbr.height = htobe(fbr.height);
+    fbr.encoding = htobe(fbr.encoding);
+
+    // send headers to client
+    write(&fbu);
+    write(&fbr);
+
+    assert(clientRfb);
+
+    uint8_t *tmp = vc->convert(clientRfb);
+    write(tmp, videoWidth() * videoHeight() * sizeof(uint32_t));
+    delete [] tmp;
+
+}
+
+void
+VncServer::sendFrameBufferResized()
+{
+    assert(clientRfb && dataFd > 0 && curState == NormalPhase);
+    DPRINTF(VNC, "Sending framebuffer resize\n");
+
+    FrameBufferUpdate fbu;
+    FrameBufferRect fbr;
+
+    fbu.type = ServerFrameBufferUpdate;
+    fbu.num_rects = 1;
+    fbr.x = 0;
+    fbr.y = 0;
+    fbr.width = videoWidth();
+    fbr.height = videoHeight();
+    fbr.encoding = EncodingDesktopSize;
+
+    // fix up endian
+    fbu.num_rects = htobe(fbu.num_rects);
+    fbr.x = htobe(fbr.x);
+    fbr.y = htobe(fbr.y);
+    fbr.width = htobe(fbr.width);
+    fbr.height = htobe(fbr.height);
+    fbr.encoding = htobe(fbr.encoding);
+
+    // send headers to client
+    write(&fbu);
+    write(&fbr);
+
+    // No actual data is sent in this message
+}
+
+void
+VncServer::setFrameBufferParams(VideoConvert::Mode mode, int width, int height)
+{
+    DPRINTF(VNC, "Updating video params: mode: %d width: %d height: %d\n", mode,
+            width, height);
+
+    if (mode != videoMode || width != videoWidth() || height != videoHeight()) {
+        videoMode = mode;
+        _videoWidth = width;
+        _videoHeight = height;
+
+        if (vc)
+            delete vc;
+
+        vc = new VideoConvert(mode, VideoConvert::rgb8888, videoWidth(),
+                videoHeight());
+
+        if (dataFd > 0 && clientRfb && curState == NormalPhase) {
+            if (supportsResizeEnc)
+                sendFrameBufferResized();
+            else
+                // The frame buffer changed size and we can't update the client
+                detach();
+        }
+    }
+}
+
+// create the VNC server object
+VncServer *
+VncServerParams::create()
+{
+    return new VncServer(this);
+}
diff --git a/src/base/vnc/vncserver.hh b/src/base/vnc/vncserver.hh
new file mode 100644 (file)
index 0000000..23b097b
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ *          William Wang
+ */
+
+/** @file
+ * Declaration of a VNC server
+ */
+
+#ifndef __DEV_VNC_SERVER_HH__
+#define __DEV_VNC_SERVER_HH__
+
+#include <iostream>
+
+#include "base/circlebuf.hh"
+#include "base/pollevent.hh"
+#include "base/socket.hh"
+#include "base/vnc/convert.hh"
+#include "cpu/intr_control.hh"
+#include "sim/sim_object.hh"
+#include "params/VncServer.hh"
+
+/**
+ * A device that expects to receive input from the vnc server should derrive
+ * (through mulitple inheritence if necessary from VncKeyboard or VncMouse
+ * and call setKeyboard() or setMouse() respectively on the vnc server.
+ */
+class VncKeyboard
+{
+  public:
+    /**
+     * Called when the vnc server receives a key press event from the
+     * client.
+     * @param key the key passed is an x11 keysym
+     * @param down is the key now down or up?
+     */
+    virtual void keyPress(uint32_t key, bool down) = 0;
+};
+
+class VncMouse
+{
+  public:
+    /**
+     * called whenever the mouse moves or it's button state changes
+     * buttons is a simple mask with each button (0-8) corresponding to
+     * a bit position in the byte with 1 being down and 0 being up
+     * @param x the x position of the mouse
+     * @param y the y position of the mouse
+     * @param buttos the button state as described above
+     */
+    virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons) = 0;
+};
+
+class VncServer : public SimObject
+{
+  public:
+
+    /**
+     * \defgroup VncConstants A set of constants and structs from the VNC spec
+     * @{
+     */
+    /** Authentication modes */
+    const static uint32_t AuthInvalid = 0;
+    const static uint32_t AuthNone    = 1;
+
+    /** Error conditions */
+    const static uint32_t VncOK   = 0;
+
+    /** Client -> Server message IDs */
+    enum ClientMessages {
+        ClientSetPixelFormat    = 0,
+        ClientSetEncodings      = 2,
+        ClientFrameBufferUpdate = 3,
+        ClientKeyEvent          = 4,
+        ClientPointerEvent      = 5,
+        ClientCutText           = 6
+    };
+
+    /** Server -> Client message IDs */
+    enum ServerMessages {
+        ServerFrameBufferUpdate     = 0,
+        ServerSetColorMapEntries    = 1,
+        ServerBell                  = 2,
+        ServerCutText               = 3
+    };
+
+    /** Encoding types */
+    enum EncodingTypes {
+        EncodingRaw         = 0,
+        EncodingCopyRect    = 1,
+        EncodingHextile     = 5,
+        EncodingDesktopSize = -223
+    };
+
+    /** keyboard/mouse support */
+    enum MouseEvents {
+        MouseLeftButton     = 0x1,
+        MouseRightButton    = 0x2,
+        MouseMiddleButton   = 0x4
+    };
+
+    const char* vncVersion() const
+    {
+        return "RFB 003.008\n";
+    }
+
+    enum ConnectionState {
+        WaitForProtocolVersion,
+        WaitForSecurityResponse,
+        WaitForClientInit,
+        InitializationPhase,
+        NormalPhase
+    };
+
+    struct PixelFormat {
+        uint8_t bpp;
+        uint8_t depth;
+        uint8_t bigendian;
+        uint8_t truecolor;
+        uint16_t redmax;
+        uint16_t greenmax;
+        uint16_t bluemax;
+        uint8_t redshift;
+        uint8_t greenshift;
+        uint8_t blueshift;
+        uint8_t padding[3];
+    } M5_ATTR_PACKED;
+
+    struct ServerInitMsg {
+        uint16_t fbWidth;
+        uint16_t fbHeight;
+        PixelFormat px;
+        uint32_t namelen;
+        char name[2]; // just to put M5 in here
+    } M5_ATTR_PACKED;
+
+    struct PixelFormatMessage {
+        uint8_t type;
+        uint8_t padding[3];
+        PixelFormat px;
+    } M5_ATTR_PACKED;
+
+    struct PixelEncodingsMessage {
+        uint8_t type;
+        uint8_t padding;
+        uint16_t num_encodings;
+    } M5_ATTR_PACKED;
+
+    struct FrameBufferUpdateReq {
+        uint8_t type;
+        uint8_t incremental;
+        uint16_t x;
+        uint16_t y;
+        uint16_t width;
+        uint16_t height;
+    } M5_ATTR_PACKED;
+
+    struct KeyEventMessage {
+        uint8_t type;
+        uint8_t down_flag;
+        uint8_t padding[2];
+        uint32_t key;
+    } M5_ATTR_PACKED;
+
+    struct PointerEventMessage {
+        uint8_t type;
+        uint8_t button_mask;
+        uint16_t x;
+        uint16_t y;
+    } M5_ATTR_PACKED;
+
+    struct ClientCutTextMessage {
+        uint8_t type;
+        uint8_t padding[3];
+        uint32_t length;
+    } M5_ATTR_PACKED;
+
+    struct FrameBufferUpdate {
+        uint8_t type;
+        uint8_t padding;
+        uint16_t num_rects;
+    } M5_ATTR_PACKED;
+
+    struct FrameBufferRect {
+        uint16_t x;
+        uint16_t y;
+        uint16_t width;
+        uint16_t height;
+        int32_t encoding;
+    } M5_ATTR_PACKED;
+
+    struct ServerCutText {
+        uint8_t type;
+        uint8_t padding[3];
+        uint32_t length;
+    } M5_ATTR_PACKED;
+
+    /** @} */
+
+  protected:
+    /** ListenEvent to accept a vnc client connection */
+    class ListenEvent: public PollEvent
+    {
+      protected:
+        VncServer *vncserver;
+
+      public:
+        ListenEvent(VncServer *vs, int fd, int e);
+        void process(int revent);
+    };
+
+    friend class ListenEvent;
+    ListenEvent *listenEvent;
+
+    /** DataEvent to read data from vnc */
+    class DataEvent: public PollEvent
+    {
+      protected:
+        VncServer *vncserver;
+
+      public:
+        DataEvent(VncServer *vs, int fd, int e);
+        void process(int revent);
+    };
+
+    friend class DataEvent;
+    DataEvent *dataEvent;
+
+    int number;
+    int dataFd; // data stream file describer
+
+    ListenSocket listener;
+
+    void listen(int port);
+    void accept();
+    void data();
+    void detach();
+
+  public:
+    typedef VncServerParams Params;
+    VncServer(const Params *p);
+    ~VncServer();
+
+    // RFB
+  protected:
+
+    /** The rfb prototol state the connection is in */
+    ConnectionState curState;
+
+    /** the width of the frame buffer we are sending to the client */
+    uint16_t _videoWidth;
+
+    /** the height of the frame buffer we are sending to the client */
+    uint16_t _videoHeight;
+
+    /** pointer to the actual data that is stored in the frame buffer device */
+    uint8_t* clientRfb;
+
+    /** The device to notify when we get key events */
+    VncKeyboard *keyboard;
+
+    /** The device to notify when we get mouse events */
+    VncMouse *mouse;
+
+    /** An update needs to be sent to the client. Without doing this the
+     * client will constantly request data that is pointless */
+    bool sendUpdate;
+
+    /** The one and only pixel format we support */
+    PixelFormat pixelFormat;
+
+    /** If the vnc client supports receiving raw data. It always should */
+    bool supportsRawEnc;
+
+    /** If the vnc client supports the desktop resize command */
+    bool supportsResizeEnc;
+
+    /** The mode of data we're getting frame buffer in */
+    VideoConvert::Mode videoMode;
+
+    /** The video converter that transforms data for us */
+    VideoConvert *vc;
+
+  protected:
+    /**
+     * vnc client Interface
+     */
+
+    /** Send an error message to the client
+     * @param error_msg text to send describing the error
+     */
+    void sendError(const char* error_msg);
+
+    /** Read some data from the client
+     * @param buf the data to read
+     * @param len the amount of data to read
+     * @return length read
+     */
+    size_t read(uint8_t *buf, size_t len);
+
+    /** Read len -1 bytes from the client into the buffer provided + 1
+     * assert that we read enough bytes. This function exists to handle
+     * reading all of the protocol structs above when we've already read
+     * the first byte which describes which one we're reading
+     * @param buf the address of the buffer to add one to and read data into
+     * @param len the amount of data  + 1 to read
+     * @return length read
+     */
+    size_t read1(uint8_t *buf, size_t len);
+
+
+    /** Templated version of the read function above to
+     * read simple data to the client
+     * @param val data to recv from the client
+     */
+    template <typename T> size_t read(T* val);
+
+
+    /** Write a buffer to the client.
+     * @param buf buffer to send
+     * @param len length of the buffer
+     * @return number of bytes sent
+     */
+    size_t write(const uint8_t *buf, size_t len);
+
+    /** Templated version of the write function above to
+     * write simple data to the client
+     * @param val data to send to the client
+     */
+    template <typename T> size_t write(T* val);
+
+    /** Send a string to the client
+     * @param str string to transmit
+     */
+    size_t write(const char* str);
+
+    /** Check the client's protocol verion for compatibility and send
+     * the security types we support
+     */
+    void checkProtocolVersion();
+
+    /** Check that the security exchange was successful
+     */
+    void checkSecurity();
+
+    /** Send client our idea about what the frame buffer looks like */
+    void sendServerInit();
+
+    /** Send an error message to the client when something goes wrong
+     * @param error_msg error to send
+     */
+    void sendError(std::string error_msg);
+
+    /** Send a updated frame buffer to the client.
+     * @todo this doesn't do anything smart and just sends the entire image
+     */
+    void sendFrameBufferUpdate();
+
+    /** Receive pixel foramt message from client and process it. */
+    void setPixelFormat();
+
+    /** Receive encodings message from client and process it. */
+    void setEncodings();
+
+    /** Receive message from client asking for updated frame buffer */
+    void requestFbUpdate();
+
+    /** Receive message from client providing new keyboard input */
+    void recvKeyboardInput();
+
+    /** Recv message from client providing new mouse movement or button click */
+    void recvPointerInput();
+
+    /**  Receive message from client that there is text in it's paste buffer.
+     * This is a no-op at the moment, but perhaps we would want to be able to
+     * paste it at some point.
+     */
+    void recvCutText();
+
+    /** Tell the client that the frame buffer resized. This happens when the
+     * simulated system changes video modes (E.g. X11 starts).
+     */
+    void sendFrameBufferResized();
+
+  public:
+    /** Set the address of the frame buffer we are going to show.
+     * To avoid copying, just have the display controller
+     * tell us where the data is instead of constanly copying it around
+     * @param rfb frame buffer that we're going to use
+     */
+    void
+    setFramebufferAddr(uint8_t* rfb)
+    {
+        clientRfb = rfb;
+    }
+
+    /** Set up the device that would like to receive notifications when keys are
+     * pressed in the vnc client keyboard
+     * @param _keyboard an object that derrives from VncKeyboard
+     */
+    void setKeyboard(VncKeyboard *_keyboard) { keyboard = _keyboard; }
+
+    /** Setup the device that would like to receive notifications when mouse
+     * movements or button presses are received from the vnc client.
+     * @param _mouse an object that derrives from VncMouse
+     */
+    void setMouse(VncMouse *_mouse) { mouse = _mouse; }
+
+    /** The frame buffer uses this call to notify the vnc server that
+     * the frame buffer has been updated and a new image needs to be sent to the
+     * client
+     */
+    void
+    setDirty()
+    {
+        sendUpdate = true;
+        sendFrameBufferUpdate();
+    }
+
+    /** What is the width of the screen we're displaying.
+     * This is used for pointer/tablet devices that need to know to calculate
+     * the correct value to send to the device driver.
+     * @return the width of the simulated screen
+     */
+    uint16_t videoWidth() { return _videoWidth; }
+
+    /** What is the height of the screen we're displaying.
+     * This is used for pointer/tablet devices that need to know to calculate
+     * the correct value to send to the device driver.
+     * @return the height of the simulated screen
+     */
+    uint16_t videoHeight() { return _videoHeight; }
+
+    /** Set the mode of the data the frame buffer will be sending us
+     * @param mode the mode
+     */
+    void setFrameBufferParams(VideoConvert::Mode mode, int width, int height);
+};
+
+#endif