summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Saidi <Ali.Saidi@ARM.com>2011-02-11 18:29:35 -0600
committerAli Saidi <Ali.Saidi@ARM.com>2011-02-11 18:29:35 -0600
commitd33c1d95929356682fb06083d1da2d66605649f4 (patch)
tree6e63b9aea75bd9cf213339fd643678925c096917
parentded4d319f275aa6e1518f760d67b9e0519b31565 (diff)
downloadgem5-d33c1d95929356682fb06083d1da2d66605649f4.tar.xz
VNC: Add VNC server to M5
-rw-r--r--configs/common/FSConfig.py1
-rw-r--r--src/base/SConscript1
-rw-r--r--src/base/bitmap.cc82
-rw-r--r--src/base/bitmap.hh114
-rw-r--r--src/base/compiler.hh2
-rw-r--r--src/base/vnc/SConscript48
-rw-r--r--src/base/vnc/VncServer.py45
-rw-r--r--src/base/vnc/convert.cc139
-rw-r--r--src/base/vnc/convert.hh141
-rw-r--r--src/base/vnc/vncserver.cc703
-rw-r--r--src/base/vnc/vncserver.hh475
11 files changed, 1751 insertions, 0 deletions
diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py
index 9e5fd3a0b..f58fd3d2e 100644
--- a/configs/common/FSConfig.py
+++ b/configs/common/FSConfig.py
@@ -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' + \
diff --git a/src/base/SConscript b/src/base/SConscript
index 2bb6b13ab..3f069bf9e 100644
--- a/src/base/SConscript
+++ b/src/base/SConscript
@@ -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
index 000000000..0d2a9302b
--- /dev/null
+++ b/src/base/bitmap.cc
@@ -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
index 000000000..9dfaa87a1
--- /dev/null
+++ b/src/base/bitmap.hh
@@ -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__
+
diff --git a/src/base/compiler.hh b/src/base/compiler.hh
index 2c655af60..3315fb2f7 100644
--- a/src/base/compiler.hh
+++ b/src/base/compiler.hh
@@ -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
index 000000000..c92676555
--- /dev/null
+++ b/src/base/vnc/SConscript
@@ -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
index 000000000..21eb3ed28
--- /dev/null
+++ b/src/base/vnc/VncServer.py
@@ -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
index 000000000..ea7a9b1c5
--- /dev/null
+++ b/src/base/vnc/convert.cc
@@ -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
index 000000000..68a21d677
--- /dev/null
+++ b/src/base/vnc/convert.hh
@@ -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
index 000000000..8936fa67b
--- /dev/null
+++ b/src/base/vnc/vncserver.cc
@@ -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
index 000000000..23b097b11
--- /dev/null
+++ b/src/base/vnc/vncserver.hh
@@ -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