diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/pl111.hh --- a/src/dev/arm/pl111.hh Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/pl111.hh Tue Jan 18 16:36:11 2011 -0600 @@ -35,6 +35,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: William Wang + * Ali Saidi */ @@ -55,6 +56,8 @@ using namespace std; class Gic; +class VncServer; +class Bitmap; class Pl111: public AmbaDmaDevice { @@ -96,11 +99,22 @@ static const int dmaSize = 8; // 64 bits static const int maxOutstandingDma = 16; // 16 deep FIFO of 64 bits + enum LcdMode { + bpp1 = 0, + bpp2, + bpp4, + bpp8, + bpp16, + bpp24, + bpp16m565, + bpp12 + }; + BitUnion8(InterruptReg) - Bitfield<1> ffufie; - Bitfield<2> nbupie; - Bitfield<3> vtcpie; - Bitfield<4> ahmeie; + Bitfield<1> underflow; + Bitfield<2> baseaddr; + Bitfield<3> vcomp; + Bitfield<4> ahbmaster; EndBitUnion(InterruptReg) BitUnion32(TimingReg0) @@ -180,15 +194,6 @@ /** Masked interrupt status register */ InterruptReg lcdMis; - /** Interrupt clear register */ - InterruptReg lcdIcr; - - /** Upper panel current address value register - ro */ - int lcdUpcurr; - - /** Lower panel current address value register - ro */ - int lcdLpcurr; - /** 256x16-bit color palette registers * 256 palette entries organized as 128 locations of two entries per word */ int lcdPalette[LcdPaletteSize]; @@ -228,17 +233,26 @@ /** Clock speed */ Tick clock; - /** Frame buffer height - lines per panel */ - uint16_t height; + /** VNC server */ + VncServer *vncserver; + + /** Helper to write out bitmaps */ + Bitmap *bmp; + + /** Picture of what the current frame buffer lookcs like */ + std::ostream *pic; /** Frame buffer width - pixels per line */ uint16_t width; + /** Frame buffer height - lines per panel */ + uint16_t height; + + /** Bytes per pixel */ + uint8_t bytesPerPixel; + /** CLCDC supports up to 1024x768 */ - uint8_t dmaBuffer[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)]; - - /** Double buffering */ - uint32_t frameBuffer[LcdMaxWidth * LcdMaxHeight]; + uint8_t *dmaBuffer; /** Start time for frame buffer dma read */ Tick startTime; @@ -258,12 +272,12 @@ /** Number of pending dma reads */ int dmaPendingNum; + /** Send updated parameters to the vnc server */ + void updateVideoParams(); + /** DMA framebuffer read */ void readFramebuffer(); - /** Write framebuffer to a bmp file */ - void writeBMP(uint32_t*); - /** Generate dma framebuffer read event */ void generateReadEvent(); @@ -273,6 +287,9 @@ /** fillFIFO event */ void fillFifo(); + /** start the dmas off after power is enabled */ + void startDma(); + /** DMA done event */ void dmaDone(); @@ -289,7 +306,7 @@ /** DMA done event */ vector > dmaDoneEvent; - /** Wrapper to create an event out of the thing */ + /** Wrapper to create an event out of the interrupt */ EventWrapper intEvent; public: @@ -312,57 +329,6 @@ * @param range_list range list to populate with ranges */ void addressRanges(AddrRangeList &range_list); - - /** - * Return if we have an interrupt pending - * @return interrupt status - * @todo fix me when implementation improves - */ - virtual bool intStatus() { return false; } -}; - -// write frame buffer into a bitmap picture -class Bitmap -{ - public: - Bitmap(std::fstream& bmp, uint16_t h, uint16_t w); - - private: - struct Magic - { - unsigned char magic_number[2]; - } magic; - - struct Header - { - uint32_t size; - uint16_t reserved1; - uint16_t reserved2; - uint32_t offset; - } header; - - 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; - } info; - - struct Color - { - unsigned char b; - unsigned char g; - unsigned char r; - unsigned char a; - } color; }; #endif diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/kmi.cc --- a/src/dev/arm/kmi.cc Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/kmi.cc Tue Jan 18 16:36:11 2011 -0600 @@ -37,21 +37,31 @@ * (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 + * Authors: Ali Saidi + * William Wang */ #include "base/trace.hh" +#include "base/vnc/vncserver.hh" #include "dev/arm/amba_device.hh" #include "dev/arm/kmi.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" +#include "dev/ps2.hh" Pl050::Pl050(const Params *p) - : AmbaDevice(p), control(0x00), status(0x43), kmidata(0x00), clkdiv(0x00), - intreg(0x00), intNum(p->int_num), gic(p->gic), intDelay(p->int_delay), + : AmbaIntDevice(p), control(0), status(0x43), clkdiv(0), interrupts(0), + rawInterrupts(0), ackNext(false), shiftDown(false), curX(-1), curY(-1), intEvent(this) { pioSize = 0xfff; + + if (p->vnc) { + if (!p->is_mouse) + p->vnc->setKeyboard(this); + else + p->vnc->setMouse(this); + } } Tick @@ -62,28 +72,39 @@ Addr daddr = pkt->getAddr() - pioAddr; pkt->allocate(); - DPRINTF(Pl050, " read register %#x size=%d\n", daddr, pkt->getSize()); - // use a temporary data since the KMI registers are read/written with - // different size operations - // uint32_t data = 0; switch (daddr) { case kmiCr: + DPRINTF(Pl050, "Read Commmand: %#x\n", (uint32_t)control); data = control; break; case kmiStat: + if (rxQueue.empty()) + status.rxfull = 0; + else + status.rxfull = 1; + + DPRINTF(Pl050, "Read Status: %#x\n", (uint32_t)status); data = status; break; case kmiData: - data = kmidata; + if (rxQueue.empty()) { + data = 0; + } else { + data = rxQueue.front(); + rxQueue.pop_front(); + } + DPRINTF(Pl050, "Read Data: %#x\n", (uint32_t)data); + updateIntStatus(); break; case kmiClkDiv: data = clkdiv; break; case kmiISR: - data = intreg; + data = interrupts; + DPRINTF(Pl050, "Read Interrupts: %#x\n", (uint32_t)interrupts); break; default: if (AmbaDev::readId(pkt, ambaId, pioAddr)) { @@ -123,47 +144,22 @@ Addr daddr = pkt->getAddr() - pioAddr; - DPRINTF(Pl050, " write register %#x value %#x size=%d\n", daddr, - pkt->get(), pkt->getSize()); - - // use a temporary data since the KMI registers are read/written with - // different size operations - // - uint32_t data = 0; - - switch (pkt->getSize()) { - case 1: - data = pkt->get(); - break; - case 2: - data = pkt->get(); - break; - case 4: - data = pkt->get(); - break; - default: - panic("KMI write size too big?\n"); - break; - } + assert(pkt->getSize() == sizeof(uint8_t)); switch (daddr) { case kmiCr: - control = data; - break; - case kmiStat: - panic("Tried to write PL050 register(read only) at offset %#x\n", - daddr); + DPRINTF(Pl050, "Write Commmand: %#x\n", (uint32_t)pkt->get()); + control = pkt->get(); + updateIntStatus(); break; case kmiData: - kmidata = data; + DPRINTF(Pl050, "Write Data: %#x\n", (uint32_t)pkt->get()); + processCommand(pkt->get()); + updateIntStatus(); break; case kmiClkDiv: - clkdiv = data; - break; - case kmiISR: - panic("Tried to write PL050 register(read only) at offset %#x\n", - daddr); + clkdiv = pkt->get(); break; default: warn("Tried to write PL050 at offset %#x that doesn't exist\n", daddr); @@ -174,14 +170,209 @@ } void +Pl050::processCommand(uint8_t byte) +{ + using namespace Ps2; + + if (ackNext) { + ackNext = false; + rxQueue.push_back(Ack); + updateIntStatus(); + return; + } + + switch (byte) { + case Ps2Reset: + rxQueue.push_back(Ack); + rxQueue.push_back(SelfTestPass); + break; + case SetResolution: + case SetRate: + case SetStatusLed: + case SetScaling1_1: + case SetScaling1_2: + rxQueue.push_back(Ack); + ackNext = true; + break; + case ReadId: + rxQueue.push_back(Ack); + if (params()->is_mouse) + rxQueue.push_back(MouseId); + else + rxQueue.push_back(KeyboardId); + break; + case TpReadId: + if (!params()->is_mouse) + break; + // We're not a trackpoint device, this should make the probe go away + rxQueue.push_back(Ack); + rxQueue.push_back(0); + rxQueue.push_back(0); + case Disable: + case Enable: + rxQueue.push_back(Ack); + break; + case StatusRequest: + rxQueue.push_back(Ack); + rxQueue.push_back(0); + rxQueue.push_back(2); // default resolution + rxQueue.push_back(100); // default sample rate + break; + default: + panic("Unknown byte received: %d\n", byte); + } + + updateIntStatus(); +} + + +void +Pl050::updateIntStatus() +{ + if (!rxQueue.empty()) + rawInterrupts.rx = 1; + else + rawInterrupts.rx = 0; + + interrupts.tx = rawInterrupts.tx & control.txint_enable; + interrupts.rx = rawInterrupts.rx & control.rxint_enable; + + DPRINTF(Pl050, "rawInterupts=%#x control=%#x interrupts=%#x\n", + (uint32_t)rawInterrupts, (uint32_t)control, (uint32_t)interrupts); + + if (interrupts && !intEvent.scheduled()) + schedule(intEvent, curTick() + intDelay); +} + +void Pl050::generateInterrupt() { - if (intreg.rxintr || intreg.txintr) { + + if (interrupts) { gic->sendInt(intNum); - DPRINTF(Pl050, " -- Generated\n"); + DPRINTF(Pl050, "Generated interrupt\n"); } } +void +Pl050::mouseAt(uint16_t x, uint16_t y, uint8_t buttons) +{ + using namespace Ps2; + + if (curX == -1) { + curX = x; + curY = y; + return; + } + + Ps2MouseMovement move; + + int delta_x = curX - x; + int delta_y = curY - y; + + move.leftButton = buttons & VncServer::MouseLeftButton; + move.rightButton = buttons & VncServer::MouseRightButton; + move.middleButton = buttons & VncServer::MouseMiddleButton; + move.one = 1; + move.xSign = (delta_x < 0); + move.ySign = (delta_y < 0); + + delta_x = abs(delta_x); + delta_y = abs(delta_y); + + move.xOverflow = (delta_x > 255); + move.yOverflow = (delta_y > 255); + + rxQueue.push_back(move); + + if (delta_x > 255) + rxQueue.push_back(255); + else + rxQueue.push_back(delta_x); + + if (delta_y > 255) + rxQueue.push_back(255); + else + rxQueue.push_back(delta_y); + + updateIntStatus(); +} + + +void +Pl050::keyPress(uint32_t key, bool down) +{ + // a little hack for now to see if we can make something work + DPRINTF(Pl050, "Received keypress %#x down=%d\n", key, down); + + + using namespace Ps2; + + std::list keys; + + // convert the X11 keysym into ps2 codes + keySymToPs2(key, down, shiftDown, keys); + + // Insert into our queue of charecters + rxQueue.splice(rxQueue.end(), keys); + updateIntStatus(); +} + +void +Pl050::serialize(std::ostream &os) +{ + uint8_t ctrlreg = control; + SERIALIZE_SCALAR(ctrlreg); + + uint8_t stsreg = status; + SERIALIZE_SCALAR(stsreg); + SERIALIZE_SCALAR(clkdiv); + + uint8_t ints = interrupts; + SERIALIZE_SCALAR(ints); + + uint8_t raw_ints = rawInterrupts; + SERIALIZE_SCALAR(raw_ints); + + SERIALIZE_SCALAR(ackNext); + SERIALIZE_SCALAR(shiftDown); + SERIALIZE_SCALAR(curX); + SERIALIZE_SCALAR(curY); + + arrayParamOut(os, "rxQueue", rxQueue); +} + +void +Pl050::unserialize(Checkpoint *cp, const std::string §ion) +{ + uint8_t ctrlreg; + UNSERIALIZE_SCALAR(ctrlreg); + control = ctrlreg; + + uint8_t stsreg; + UNSERIALIZE_SCALAR(stsreg); + status = stsreg; + + UNSERIALIZE_SCALAR(clkdiv); + + uint8_t ints; + UNSERIALIZE_SCALAR(ints); + interrupts = ints; + + uint8_t raw_ints; + UNSERIALIZE_SCALAR(raw_ints); + rawInterrupts = raw_ints; + + UNSERIALIZE_SCALAR(ackNext); + UNSERIALIZE_SCALAR(shiftDown); + UNSERIALIZE_SCALAR(curX); + UNSERIALIZE_SCALAR(curY); + + arrayParamIn(cp, section, "rxQueue", rxQueue); +} + + + Pl050 * Pl050Params::create() { diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/amba_device.hh --- a/src/dev/arm/amba_device.hh Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/amba_device.hh Tue Jan 18 16:36:11 2011 -0600 @@ -55,6 +55,7 @@ #include "mem/packet.hh" #include "mem/packet_access.hh" #include "params/AmbaDevice.hh" +#include "params/AmbaIntDevice.hh" #include "params/AmbaDmaDevice.hh" namespace AmbaDev { @@ -81,6 +82,18 @@ AmbaDevice(const Params *p); }; +class AmbaIntDevice : public AmbaDevice +{ + protected: + int intNum; + Gic *gic; + Tick intDelay; + + public: + typedef AmbaIntDeviceParams Params; + AmbaIntDevice(const Params *p); +}; + class AmbaDmaDevice : public DmaDevice { protected: diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/amba_device.cc --- a/src/dev/arm/amba_device.cc Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/amba_device.cc Tue Jan 18 16:36:11 2011 -0600 @@ -47,11 +47,19 @@ #include "mem/packet_access.hh" const uint64_t AmbaVendor = ULL(0xb105f00d00000000); + AmbaDevice::AmbaDevice(const Params *p) : BasicPioDevice(p), ambaId(AmbaVendor | p->amba_id) { } +AmbaIntDevice::AmbaIntDevice(const Params *p) + : AmbaDevice(p), intNum(p->int_num), gic(p->gic), intDelay(p->int_delay) +{ +} + + + AmbaDmaDevice::AmbaDmaDevice(const Params *p) : DmaDevice(p), ambaId(AmbaVendor | p->amba_id), pioAddr(p->pio_addr), pioSize(0), diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/kmi.hh --- a/src/dev/arm/kmi.hh Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/kmi.hh Tue Jan 18 16:36:11 2011 -0600 @@ -48,13 +48,16 @@ #ifndef __DEV_ARM_PL050_HH__ #define __DEV_ARM_PL050_HH__ +#include + #include "base/range.hh" -#include "dev/io_device.hh" +#include "base/vnc/vncserver.hh" +#include "dev/arm/amba_device.hh" #include "params/Pl050.hh" class Gic; -class Pl050 : public AmbaDevice +class Pl050 : public AmbaIntDevice, public VncKeyboard, public VncMouse { protected: static const int kmiCr = 0x000; @@ -63,34 +66,67 @@ static const int kmiClkDiv = 0x00C; static const int kmiISR = 0x010; - // control register - uint8_t control; + BitUnion8(ControlReg) + Bitfield<0> force_clock_low; + Bitfield<1> force_data_low; + Bitfield<2> enable; + Bitfield<3> txint_enable; + Bitfield<4> rxint_enable; + Bitfield<5> type; + EndBitUnion(ControlReg) - // status register - uint8_t status; + /** control register + */ + ControlReg control; - // received data (read) or data to be transmitted (write) - uint8_t kmidata; + /** KMI status register */ + BitUnion8(StatusReg) + Bitfield<0> data_in; + Bitfield<1> clk_in; + Bitfield<2> rxparity; + Bitfield<3> rxbusy; + Bitfield<4> rxfull; + Bitfield<5> txbusy; + Bitfield<6> txempty; + EndBitUnion(StatusReg) - // clock divisor register + StatusReg status; + + /** clock divisor register + * This register is just kept around to satisfy reads after driver does + * writes. The divsor does nothing, as we're not actually signaling ps2 + * serial commands to anything. + */ uint8_t clkdiv; - BitUnion8(IntReg) - Bitfield<0> txintr; - Bitfield<1> rxintr; - EndBitUnion(IntReg) + BitUnion8(InterruptReg) + Bitfield<0> rx; + Bitfield<1> tx; + EndBitUnion(InterruptReg) - /** interrupt mask register. */ - IntReg intreg; + /** interrupt status register. */ + InterruptReg interrupts; - /** Interrupt number to generate */ - int intNum; + /** raw interrupt register (unmasked) */ + InterruptReg rawInterrupts; - /** Gic to use for interrupting */ - Gic *gic; + /** If the controller should ignore the next data byte and acknowledge it. + * The driver is attempting to setup some feature we don't care about + */ + bool ackNext; - /** Delay before interrupting */ - Tick intDelay; + /** is the shift key currently down */ + bool shiftDown; + + /** The last X position we received for the mouse */ + int curX; + + /** The last Y position we received for the mouse */ + int curY; + + /** Update the status of the interrupt registers and schedule an interrupt + * if required */ + void updateIntStatus(); /** Function to generate interrupt */ void generateInterrupt(); @@ -98,6 +134,15 @@ /** Wrapper to create an event out of the thing */ EventWrapper intEvent; + /** Receive queue. This list contains all the pending commands that + * need to be sent to the driver + */ + std::list rxQueue; + + /** Handle a command sent to the kmi and respond appropriately + */ + void processCommand(uint8_t byte); + public: typedef Pl050Params Params; const Params * @@ -111,12 +156,11 @@ virtual Tick read(PacketPtr pkt); virtual Tick write(PacketPtr pkt); - /** - * Return if we have an interrupt pending - * @return interrupt status - * @todo fix me when implementation improves - */ - virtual bool intStatus() { return false; } + virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons); + virtual void keyPress(uint32_t key, bool down); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); }; #endif diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/RealView.py --- a/src/dev/arm/RealView.py Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/RealView.py Tue Jan 18 16:36:11 2011 -0600 @@ -52,6 +52,13 @@ abstract = True amba_id = Param.UInt32("ID of AMBA device for kernel detection") +class AmbaIntDevice(AmbaDevice): + type = 'AmbaIntDevice' + abstract = True + gic = Param.Gic(Parent.any, "Gic to use for interrupting") + int_num = Param.UInt32("Interrupt number that connects to GIC") + int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART") + class AmbaDmaDevice(DmaDevice): type = 'AmbaDmaDevice' abstract = True @@ -94,16 +101,17 @@ clock1 = Param.Clock('1MHz', "Clock speed of the input") amba_id = 0x00141804 -class Pl050(AmbaDevice): +class Pl050(AmbaIntDevice): type = 'Pl050' - gic = Param.Gic(Parent.any, "Gic to use for interrupting") - int_num = Param.UInt32("Interrupt number that connects to GIC") - int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART") + vnc = Param.VncServer(Parent.any, "Vnc server for remote frame buffer display") + is_mouse = Param.Bool(False, "Is this interface a mouse, if not a keyboard") + int_delay = '1us' amba_id = 0x00141050 class Pl111(AmbaDmaDevice): type = 'Pl111' clock = Param.Clock('24MHz', "Clock speed of the input") + vnc = Param.VncServer(Parent.any, "Vnc server for remote frame buffer display") amba_id = 0x00141111 class RealView(Platform): @@ -121,7 +129,7 @@ timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000) clcd = Pl111(pio_addr=0x10020000, int_num=55) kmi0 = Pl050(pio_addr=0x10006000, int_num=52) - kmi1 = Pl050(pio_addr=0x10007000, int_num=53) + kmi1 = Pl050(pio_addr=0x10007000, int_num=53, is_mouse=True) l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff) flash_fake = IsaFake(pio_addr=0x40000000, pio_size=0x4000000) @@ -140,7 +148,7 @@ aaci_fake = AmbaFake(pio_addr=0x10004000) mmc_fake = AmbaFake(pio_addr=0x10005000) rtc_fake = AmbaFake(pio_addr=0x10017000, amba_id=0x41031) - + cf0_fake = IsaFake(pio_addr=0x18000000, pio_size=0xfff) # Attach I/O devices that are on chip @@ -175,6 +183,7 @@ self.mmc_fake.pio = bus.port self.rtc_fake.pio = bus.port self.flash_fake.pio = bus.port + self.cf0_fake.pio = bus.port # Reference for memory map and interrupt number # RealView Emulation Baseboard User Guide (ARM DUI 0143B) @@ -187,7 +196,7 @@ timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000) clcd = Pl111(pio_addr=0x10020000, int_num=23) kmi0 = Pl050(pio_addr=0x10006000, int_num=20) - kmi1 = Pl050(pio_addr=0x10007000, int_num=21) + kmi1 = Pl050(pio_addr=0x10007000, int_num=21, is_mouse=True) l2x0_fake = IsaFake(pio_addr=0x1f002000, pio_size=0xfff, warn_access="1") dmac_fake = AmbaFake(pio_addr=0x10030000) diff -r 6896b2300693 -r e3c773d07601 src/dev/SConscript --- a/src/dev/SConscript Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/SConscript Tue Jan 18 16:36:11 2011 -0600 @@ -69,6 +69,7 @@ Source('pcidev.cc') Source('pktfifo.cc') Source('platform.cc') + Source('ps2.cc') Source('simple_disk.cc') Source('sinic.cc') Source('terminal.cc') diff -r 6896b2300693 -r e3c773d07601 src/base/vnc/vncserver.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/vnc/vncserver.cc Tue Jan 18 16:36:11 2011 -0600 @@ -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 +#include +#include +#include +#include + +#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; +} + +template +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; + do { + ret = atomic_write(dataFd, buf, len); + } while (ret == -1 && errno == EINTR); + + if (ret < len) + detach(); + + return ret; +} + +template +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; + size_t len M5_VAR_USED; + len = read(((uint8_t*)&pfm) + 1, sizeof(PixelFormatMessage) - 1); + assert(len == sizeof(PixelFormatMessage) - 1); + + 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; + size_t len M5_VAR_USED; + len = read(((uint8_t*)&pem) + 1, sizeof(PixelEncodingsMessage) - 1); + assert(len == sizeof(PixelEncodingsMessage) - 1); + 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; + len = read(&encoding); + assert(len == sizeof(int32_t)); + 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; + size_t len M5_VAR_USED; + len = read(((uint8_t*)&fbr) + 1, sizeof(FrameBufferUpdateReq) - 1); + assert(len == sizeof(FrameBufferUpdateReq) - 1); + + 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; + size_t len M5_VAR_USED; + len = read(((uint8_t*)&kem) + 1, sizeof(KeyEventMessage) - 1); + assert(len == sizeof(KeyEventMessage) - 1); + + 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; + + size_t len M5_VAR_USED; + len = read(((uint8_t*)&pem) + 1, sizeof(PointerEventMessage) - 1); + assert(len == sizeof(PointerEventMessage) - 1); + + 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; + size_t len M5_VAR_USED; + len = read(((uint8_t*)&cct) + 1, sizeof(ClientCutTextMessage) - 1); + assert(len == sizeof(ClientCutTextMessage) - 1); + + char str[1025]; + size_t data_len = betoh(cct.length); + DPRINTF(VNC, "String length %d\n", data_len); + while (data_len > 0) { + str[1024] = 0; + len = read((uint8_t*)&str, data_len > 1024 ? 1024 : data_len); + 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 -r 6896b2300693 -r e3c773d07601 src/base/vnc/vncserver.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/vnc/vncserver.hh Tue Jan 18 16:36:11 2011 -0600 @@ -0,0 +1,445 @@ +/* + * 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 + +#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() + { + 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]; + } __attribute__((__packed__)); + + struct ServerInitMsg { + uint16_t fbWidth; + uint16_t fbHeight; + PixelFormat px; + uint32_t namelen; + char name[2]; // just to put M5 in here + } __attribute__((__packed__)); + + struct PixelFormatMessage { + uint8_t type; + uint8_t padding[3]; + PixelFormat px; + } __attribute__ ((__packed__)); + + struct PixelEncodingsMessage { + uint8_t type; + uint8_t padding; + uint16_t num_encodings; + } __attribute__ ((__packed__)); + + struct FrameBufferUpdateReq { + uint8_t type; + uint8_t incremental; + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + } __attribute__ ((__packed__)); + + struct KeyEventMessage { + uint8_t type; + uint8_t down_flag; + uint8_t padding[2]; + uint32_t key; + } __attribute__ ((__packed__)); + + struct PointerEventMessage { + uint8_t type; + uint8_t button_mask; + uint16_t x; + uint16_t y; + } __attribute__ ((__packed__)); + + struct ClientCutTextMessage { + uint8_t type; + uint8_t padding[3]; + uint32_t length; + } __attribute__ ((__packed__)); + + struct FrameBufferUpdate { + uint8_t type; + uint8_t padding; + uint16_t num_rects; + } __attribute__ ((__packed__)); + + struct FrameBufferRect { + uint16_t x; + uint16_t y; + uint16_t width; + uint16_t height; + int32_t encoding; + } __attribute__ ((__packed__)); + + struct ServerCutText { + uint8_t type; + uint8_t padding[3]; + uint32_t length; + } __attribute__ ((__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 size of the frame buffer we are sending to the client */ + uint16_t videoWidth, 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); + + /** Templated version of the read function above to + * read simple data to the client + * @param val data to recv from the client + */ + template 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 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(); + } + + /** 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 diff -r 6896b2300693 -r e3c773d07601 src/base/vnc/convert.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/vnc/convert.cc Tue Jan 18 16:36:11 2011 -0600 @@ -0,0 +1,142 @@ +/* + * 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 + +#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) + panic("Only support converting from bgr565, rdb565, and bgr8888\n"); + + if (outputMode != rgb8888) + panic("Only support converting to rgb8888\n"); + + assert(width < 4000 && height < 4000 && width && height); + +} + +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[width * height * sizeof(uint32_t)]; + uint32_t *out32 = (uint32_t*)out; + + uint16_t *in16 = (uint16_t*)fb; + + for (int x = 0; x < width * height; 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[width * height * sizeof(uint32_t)]; + uint32_t *out32 = (uint32_t*)out; + + uint32_t *in32 = (uint32_t*)fb; + + for (int x = 0; x < width * height; 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 -r 6896b2300693 -r e3c773d07601 src/base/vnc/convert.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/vnc/convert.hh Tue Jan 18 16:36:11 2011 -0600 @@ -0,0 +1,135 @@ +/* + * 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); + + 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 -r 6896b2300693 -r e3c773d07601 src/base/vnc/VncServer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/vnc/VncServer.py Tue Jan 18 16:36:11 2011 -0600 @@ -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 -r 6896b2300693 -r e3c773d07601 src/base/vnc/SConscript --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/vnc/SConscript Tue Jan 18 16:36:11 2011 -0600 @@ -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 -r 6896b2300693 -r e3c773d07601 configs/common/FSConfig.py --- a/configs/common/FSConfig.py Tue Jan 18 16:36:10 2011 -0600 +++ b/configs/common/FSConfig.py Tue Jan 18 16:36:11 2011 -0600 @@ -241,6 +241,7 @@ 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 -r 6896b2300693 -r e3c773d07601 src/base/SConscript --- a/src/base/SConscript Tue Jan 18 16:36:10 2011 -0600 +++ b/src/base/SConscript Tue Jan 18 16:36:11 2011 -0600 @@ -35,6 +35,7 @@ Source('cp_annotate.cc') Source('atomicio.cc') Source('bigint.cc') +Source('bitmap.cc') Source('callback.cc') Source('circlebuf.cc') Source('cprintf.cc') diff -r 6896b2300693 -r e3c773d07601 src/base/bitmap.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/bitmap.hh Tue Jan 18 16:36:11 2011 -0600 @@ -0,0 +1,111 @@ +/* + * 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 + +#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; + }; +}; + + diff -r 6896b2300693 -r e3c773d07601 src/base/bitmap.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/base/bitmap.cc Tue Jan 18 16:36:11 2011 -0600 @@ -0,0 +1,81 @@ +/* + * 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 + +#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); + + 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(&magic), sizeof(magic)); + bmp->write(reinterpret_cast(&header), sizeof(header)); + bmp->write(reinterpret_cast(&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 -r 6896b2300693 -r e3c773d07601 src/dev/arm/pl111.cc --- a/src/dev/arm/pl111.cc Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/pl111.cc Tue Jan 18 16:36:11 2011 -0600 @@ -35,9 +35,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: William Wang + * Ali Saidi */ +#include "base/bitmap.hh" +#include "base/output.hh" #include "base/trace.hh" +#include "base/vnc/vncserver.hh" #include "dev/arm/amba_device.hh" #include "dev/arm/gic.hh" #include "dev/arm/pl111.hh" @@ -50,20 +54,27 @@ Pl111::Pl111(const Params *p) : AmbaDmaDevice(p), lcdTiming0(0), lcdTiming1(0), lcdTiming2(0), lcdTiming3(0), lcdUpbase(0), lcdLpbase(0), lcdControl(0), lcdImsc(0), - lcdRis(0), lcdMis(0), lcdIcr(0), lcdUpcurr(0), lcdLpcurr(0), + lcdRis(0), lcdMis(0), clcdCrsrCtrl(0), clcdCrsrConfig(0), clcdCrsrPalette0(0), clcdCrsrPalette1(0), clcdCrsrXY(0), clcdCrsrClip(0), clcdCrsrImsc(0), clcdCrsrIcr(0), clcdCrsrRis(0), clcdCrsrMis(0), clock(p->clock), - height(0), width(0), startTime(0), startAddr(0), maxAddr(0), curAddr(0), + vncserver(p->vnc), bmp(NULL), width(LcdMaxWidth), height(LcdMaxHeight), + bytesPerPixel(4), startTime(0), startAddr(0), maxAddr(0), curAddr(0), waterMark(0), dmaPendingNum(0), readEvent(this), fillFifoEvent(this), dmaDoneEvent(maxOutstandingDma, this), intEvent(this) { pioSize = 0xFFFF; + pic = simout.create("framebuffer.bmp", true); + + dmaBuffer = new uint8_t[LcdMaxWidth * LcdMaxHeight * sizeof(uint32_t)]; + memset(lcdPalette, 0, sizeof(lcdPalette)); memset(cursorImage, 0, sizeof(cursorImage)); memset(dmaBuffer, 0, sizeof(dmaBuffer)); - memset(frameBuffer, 0, sizeof(frameBuffer)); + + if (vncserver) + vncserver->setFramebufferAddr(dmaBuffer); } // read registers and frame buffer @@ -75,111 +86,105 @@ uint32_t data = 0; - if ((pkt->getAddr()& 0xffff0000) == pioAddr) { + assert(pkt->getAddr() >= pioAddr && + pkt->getAddr() < pioAddr + pioSize); - assert(pkt->getAddr() >= pioAddr && - pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; + pkt->allocate(); - Addr daddr = pkt->getAddr()&0xFFFF; - pkt->allocate(); + DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize()); - DPRINTF(PL111, " read register %#x size=%d\n", daddr, pkt->getSize()); - - switch (daddr) { - case LcdTiming0: - data = lcdTiming0; + switch (daddr) { + case LcdTiming0: + data = lcdTiming0; + break; + case LcdTiming1: + data = lcdTiming1; + break; + case LcdTiming2: + data = lcdTiming2; + break; + case LcdTiming3: + data = lcdTiming3; + break; + case LcdUpBase: + data = lcdUpbase; + break; + case LcdLpBase: + data = lcdLpbase; + break; + case LcdControl: + data = lcdControl; + break; + case LcdImsc: + data = lcdImsc; + break; + case LcdRis: + data = lcdRis; + break; + case LcdMis: + data = lcdMis; + break; + case LcdIcr: + panic("LCD register at offset %#x is Write-Only\n", daddr); + break; + case LcdUpCurr: + data = curAddr; + break; + case LcdLpCurr: + data = curAddr; + break; + case ClcdCrsrCtrl: + data = clcdCrsrCtrl; + break; + case ClcdCrsrConfig: + data = clcdCrsrConfig; + break; + case ClcdCrsrPalette0: + data = clcdCrsrPalette0; + break; + case ClcdCrsrPalette1: + data = clcdCrsrPalette1; + break; + case ClcdCrsrXY: + data = clcdCrsrXY; + break; + case ClcdCrsrClip: + data = clcdCrsrClip; + break; + case ClcdCrsrImsc: + data = clcdCrsrImsc; + break; + case ClcdCrsrIcr: + panic("CLCD register at offset %#x is Write-Only\n", daddr); + break; + case ClcdCrsrRis: + data = clcdCrsrRis; + break; + case ClcdCrsrMis: + data = clcdCrsrMis; + break; + default: + if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) { + // Hack for variable size accesses + data = pkt->get(); break; - case LcdTiming1: - data = lcdTiming1; + } else if (daddr >= CrsrImage && daddr <= 0xBFC) { + // CURSOR IMAGE + int index; + index = (daddr - CrsrImage) >> 2; + data= cursorImage[index]; break; - case LcdTiming2: - data = lcdTiming2; + } else if (daddr >= LcdPalette && daddr <= 0x3FC) { + // LCD Palette + int index; + index = (daddr - LcdPalette) >> 2; + data = lcdPalette[index]; break; - case LcdTiming3: - data = lcdTiming3; + } else { + panic("Tried to read CLCD register at offset %#x that \ + doesn't exist\n", daddr); break; - case LcdUpBase: - data = lcdUpbase; - break; - case LcdLpBase: - data = lcdLpbase; - break; - case LcdControl: - data = lcdControl; - break; - case LcdImsc: - warn("LCD interrupt set/clear function not supported\n"); - data = lcdImsc; - break; - case LcdRis: - warn("LCD Raw interrupt status function not supported\n"); - data = lcdRis; - break; - case LcdMis: - warn("LCD Masked interrupt status function not supported\n"); - data = lcdMis; - break; - case LcdIcr: - panic("LCD register at offset %#x is Write-Only\n", daddr); - break; - case LcdUpCurr: - data = lcdUpcurr; - break; - case LcdLpCurr: - data = lcdLpcurr; - break; - case ClcdCrsrCtrl: - data = clcdCrsrCtrl; - break; - case ClcdCrsrConfig: - data = clcdCrsrConfig; - break; - case ClcdCrsrPalette0: - data = clcdCrsrPalette0; - break; - case ClcdCrsrPalette1: - data = clcdCrsrPalette1; - break; - case ClcdCrsrXY: - data = clcdCrsrXY; - break; - case ClcdCrsrClip: - data = clcdCrsrClip; - break; - case ClcdCrsrImsc: - data = clcdCrsrImsc; - break; - case ClcdCrsrIcr: - panic("CLCD register at offset %#x is Write-Only\n", daddr); - break; - case ClcdCrsrRis: - data = clcdCrsrRis; - break; - case ClcdCrsrMis: - data = clcdCrsrMis; - break; - default: - if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) { - // Hack for variable size accesses - data = pkt->get(); - break; - } else if (daddr >= CrsrImage && daddr <= 0xBFC) { - // CURSOR IMAGE - int index; - index = (daddr - CrsrImage) >> 2; - data= cursorImage[index]; - break; - } else if (daddr >= LcdPalette && daddr <= 0x3FC) { - // LCD Palette - int index; - index = (daddr - LcdPalette) >> 2; - data = lcdPalette[index]; - break; - } else { - panic("Tried to read CLCD register at offset %#x that \ - doesn't exist\n", daddr); - break; - } } } @@ -226,119 +231,133 @@ break; } - if ((pkt->getAddr()& 0xffff0000) == pioAddr) { + assert(pkt->getAddr() >= pioAddr && + pkt->getAddr() < pioAddr + pioSize); - assert(pkt->getAddr() >= pioAddr && - pkt->getAddr() < pioAddr + pioSize); + Addr daddr = pkt->getAddr() - pioAddr; - Addr daddr = pkt->getAddr() - pioAddr; + DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr, + pkt->get(), pkt->getSize()); - DPRINTF(PL111, " write register %#x value %#x size=%d\n", daddr, - pkt->get(), pkt->getSize()); + switch (daddr) { + case LcdTiming0: + lcdTiming0 = data; + // width = 16 * (PPL+1) + width = (lcdTiming0.ppl + 1) << 4; + break; + case LcdTiming1: + lcdTiming1 = data; + // height = LPP + 1 + height = (lcdTiming1.lpp) + 1; + break; + case LcdTiming2: + lcdTiming2 = data; + break; + case LcdTiming3: + lcdTiming3 = data; + break; + case LcdUpBase: + lcdUpbase = data; + DPRINTF(PL111, "####### Upper panel base set to: %#x #######\n", lcdUpbase); + break; + case LcdLpBase: + warn("LCD dual screen mode not supported\n"); + lcdLpbase = data; + DPRINTF(PL111, "###### Lower panel base set to: %#x #######\n", lcdLpbase); + break; + case LcdControl: + int old_lcdpwr; + old_lcdpwr = lcdControl.lcdpwr; + lcdControl = data; - switch (daddr) { - case LcdTiming0: - lcdTiming0 = data; - // width = 16 * (PPL+1) - width = (lcdTiming0.ppl + 1) << 4; + DPRINTF(PL111, "LCD power is:%d\n", lcdControl.lcdpwr); + + // LCD power enable + if (lcdControl.lcdpwr && !old_lcdpwr) { + updateVideoParams(); + DPRINTF(PL111, " lcd size: height %d width %d\n", height, width); + waterMark = lcdControl.watermark ? 8 : 4; + startDma(); + } + break; + case LcdImsc: + lcdImsc = data; + if (lcdImsc.vcomp) + panic("Interrupting on vcomp not supported\n"); + + lcdMis = lcdImsc & lcdRis; + + if (!lcdMis) + gic->clearInt(intNum); + + break; + case LcdRis: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case LcdMis: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case LcdIcr: + lcdRis = lcdRis & ~data; + lcdMis = lcdImsc & lcdRis; + + if (!lcdMis) + gic->clearInt(intNum); + + break; + case LcdUpCurr: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case LcdLpCurr: + panic("LCD register at offset %#x is Read-Only\n", daddr); + break; + case ClcdCrsrCtrl: + clcdCrsrCtrl = data; + break; + case ClcdCrsrConfig: + clcdCrsrConfig = data; + break; + case ClcdCrsrPalette0: + clcdCrsrPalette0 = data; + break; + case ClcdCrsrPalette1: + clcdCrsrPalette1 = data; + break; + case ClcdCrsrXY: + clcdCrsrXY = data; + break; + case ClcdCrsrClip: + clcdCrsrClip = data; + break; + case ClcdCrsrImsc: + clcdCrsrImsc = data; + break; + case ClcdCrsrIcr: + clcdCrsrIcr = data; + break; + case ClcdCrsrRis: + panic("CLCD register at offset %#x is Read-Only\n", daddr); + break; + case ClcdCrsrMis: + panic("CLCD register at offset %#x is Read-Only\n", daddr); + break; + default: + if (daddr >= CrsrImage && daddr <= 0xBFC) { + // CURSOR IMAGE + int index; + index = (daddr - CrsrImage) >> 2; + cursorImage[index] = data; break; - case LcdTiming1: - lcdTiming1 = data; - // height = LPP + 1 - height = (lcdTiming1.lpp) + 1; + } else if (daddr >= LcdPalette && daddr <= 0x3FC) { + // LCD Palette + int index; + index = (daddr - LcdPalette) >> 2; + lcdPalette[index] = data; break; - case LcdTiming2: - lcdTiming2 = data; + } else { + panic("Tried to write PL111 register at offset %#x that \ + doesn't exist\n", daddr); break; - case LcdTiming3: - lcdTiming3 = data; - break; - case LcdUpBase: - lcdUpbase = data; - break; - case LcdLpBase: - warn("LCD dual screen mode not supported\n"); - lcdLpbase = data; - break; - case LcdControl: - int old_lcdpwr; - old_lcdpwr = lcdControl.lcdpwr; - lcdControl = data; - // LCD power enable - if (lcdControl.lcdpwr&&!old_lcdpwr) { - DPRINTF(PL111, " lcd size: height %d width %d\n", height, width); - waterMark = lcdControl.watermark ? 8 : 4; - readFramebuffer(); - } - break; - case LcdImsc: - warn("LCD interrupt mask set/clear not supported\n"); - lcdImsc = data; - break; - case LcdRis: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case LcdMis: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case LcdIcr: - warn("LCD interrupt clear not supported\n"); - lcdIcr = data; - break; - case LcdUpCurr: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case LcdLpCurr: - warn("LCD register at offset %#x is Read-Only\n", daddr); - break; - case ClcdCrsrCtrl: - clcdCrsrCtrl = data; - break; - case ClcdCrsrConfig: - clcdCrsrConfig = data; - break; - case ClcdCrsrPalette0: - clcdCrsrPalette0 = data; - break; - case ClcdCrsrPalette1: - clcdCrsrPalette1 = data; - break; - case ClcdCrsrXY: - clcdCrsrXY = data; - break; - case ClcdCrsrClip: - clcdCrsrClip = data; - break; - case ClcdCrsrImsc: - clcdCrsrImsc = data; - break; - case ClcdCrsrIcr: - clcdCrsrIcr = data; - break; - case ClcdCrsrRis: - warn("CLCD register at offset %#x is Read-Only\n", daddr); - break; - case ClcdCrsrMis: - warn("CLCD register at offset %#x is Read-Only\n", daddr); - break; - default: - if (daddr >= CrsrImage && daddr <= 0xBFC) { - // CURSOR IMAGE - int index; - index = (daddr - CrsrImage) >> 2; - cursorImage[index] = data; - break; - } else if (daddr >= LcdPalette && daddr <= 0x3FC) { - // LCD Palette - int index; - index = (daddr - LcdPalette) >> 2; - lcdPalette[index] = data; - break; - } else { - panic("Tried to write PL111 register at offset %#x that \ - doesn't exist\n", daddr); - break; - } } } @@ -347,17 +366,75 @@ } void +Pl111::updateVideoParams() +{ + if (lcdControl.lcdbpp == bpp24) { + bytesPerPixel = 4; + } else if (lcdControl.lcdbpp == bpp16m565) { + bytesPerPixel = 2; + } + + if (vncserver) { + if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::bgr8888, width, + height); + else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::rgb8888, width, + height); + else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::bgr565, width, + height); + else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr) + vncserver->setFrameBufferParams(VideoConvert::rgb565, width, + height); + else + panic("Unimplemented video mode\n"); + } + + if (bmp) + delete bmp; + + if (lcdControl.lcdbpp == bpp24 && lcdControl.bgr) + bmp = new Bitmap(VideoConvert::bgr8888, width, height, dmaBuffer); + else if (lcdControl.lcdbpp == bpp24 && !lcdControl.bgr) + bmp = new Bitmap(VideoConvert::rgb8888, width, height, dmaBuffer); + else if (lcdControl.lcdbpp == bpp16m565 && lcdControl.bgr) + bmp = new Bitmap(VideoConvert::bgr565, width, height, dmaBuffer); + else if (lcdControl.lcdbpp == bpp16m565 && !lcdControl.bgr) + bmp = new Bitmap(VideoConvert::rgb565, width, height, dmaBuffer); + else + panic("Unimplemented video mode\n"); +} + +void +Pl111::startDma() +{ + if (dmaPendingNum != 0 || readEvent.scheduled()) + return; + readFramebuffer(); +} + +void Pl111::readFramebuffer() { // initialization for dma read from frame buffer to dma buffer - uint32_t length = height*width; - if (startAddr != lcdUpbase) { + uint32_t length = height * width; + if (startAddr != lcdUpbase) startAddr = lcdUpbase; - } + + // Updating base address, interrupt if we're supposed to + lcdRis.baseaddr = 1; + if (!intEvent.scheduled()) + schedule(intEvent, nextCycle()); + curAddr = 0; startTime = curTick(); - maxAddr = static_cast(length*sizeof(uint32_t)); - dmaPendingNum =0 ; + + maxAddr = static_cast(length * bytesPerPixel); + + DPRINTF(PL111, " lcd frame buffer size of %d bytes \n", maxAddr); + + dmaPendingNum = 0; fillFifo(); } @@ -369,11 +446,16 @@ // concurrent dma reads need different dma done events // due to assertion in scheduling state ++dmaPendingNum; - DPRINTF(PL111, " ++ DMA pending number %d read addr %#x\n", - dmaPendingNum, curAddr); + assert(!dmaDoneEvent[dmaPendingNum-1].scheduled()); - dmaRead(curAddr + startAddr, dmaSize, &dmaDoneEvent[dmaPendingNum-1], - curAddr + dmaBuffer); + + // We use a uncachable request here because the requests from the CPU + // will be uncacheable as well. If we have uncacheable and cacheable + // requests in the memory system for the same address it won't be + // please + dmaPort->dmaAction(MemCmd::ReadReq, curAddr + startAddr, dmaSize, + &dmaDoneEvent[dmaPendingNum-1], curAddr + dmaBuffer, 0, + Request::UNCACHEABLE); curAddr += dmaSize; } } @@ -381,27 +463,34 @@ void Pl111::dmaDone() { - Tick maxFrameTime = lcdTiming2.cpl*height*clock; + Tick maxFrameTime = lcdTiming2.cpl * height * clock; --dmaPendingNum; - DPRINTF(PL111, " -- DMA pending number %d\n", dmaPendingNum); - if (maxAddr == curAddr && !dmaPendingNum) { - if ((curTick() - startTime) > maxFrameTime) + if ((curTick() - startTime) > maxFrameTime) { warn("CLCD controller buffer underrun, took %d cycles when should" " have taken %d\n", curTick() - startTime, maxFrameTime); + lcdRis.underflow = 1; + if (!intEvent.scheduled()) + schedule(intEvent, nextCycle()); + } - // double buffering so the vnc server doesn't see a tear in the screen - memcpy(frameBuffer, dmaBuffer, maxAddr); assert(!readEvent.scheduled()); + if (vncserver) + vncserver->setDirty(); DPRINTF(PL111, "-- write out frame buffer into bmp\n"); - writeBMP(frameBuffer); + + assert(bmp); + pic->seekp(0); + bmp->write(pic); DPRINTF(PL111, "-- schedule next dma read event at %d tick \n", maxFrameTime + curTick()); - schedule(readEvent, nextCycle(startTime + maxFrameTime)); + + if (lcdControl.lcden) + schedule(readEvent, nextCycle(startTime + maxFrameTime)); } if (dmaPendingNum > (maxOutstandingDma - waterMark)) @@ -409,8 +498,8 @@ if (!fillFifoEvent.scheduled()) schedule(fillFifoEvent, nextCycle()); +} -} Tick Pl111::nextCycle() @@ -431,33 +520,6 @@ return nextTick; } -// write out the frame buffer into a bitmap file -void -Pl111::writeBMP(uint32_t* frameBuffer) -{ - fstream pic; - - // write out bmp head - std::string filename = "./m5out/frameBuffer.bmp"; - pic.open(filename.c_str(), ios::out|ios::binary); - Bitmap bm(pic, height, width); - - DPRINTF(PL111, "-- write out data into bmp\n"); - - // write out frame buffer data - for (int i = height -1; i >= 0; --i) { - for (int j = 0; j< width; ++j) { - uint32_t pixel = frameBuffer[i*width + j]; - pic.write(reinterpret_cast(&pixel), - sizeof(uint32_t)); - DPRINTF(PL111, " write pixel data %#x at addr %#x\n", - pixel, i*width + j); - } - } - - pic.close(); -} - void Pl111::serialize(std::ostream &os) { @@ -490,9 +552,6 @@ uint8_t lcdMis_serial = lcdMis; SERIALIZE_SCALAR(lcdMis_serial); - uint8_t lcdIcr_serial = lcdIcr; - SERIALIZE_SCALAR(lcdIcr_serial); - SERIALIZE_ARRAY(lcdPalette, LcdPaletteSize); SERIALIZE_ARRAY(cursorImage, CrsrImageSize); @@ -518,9 +577,9 @@ SERIALIZE_SCALAR(clock); SERIALIZE_SCALAR(height); SERIALIZE_SCALAR(width); + SERIALIZE_SCALAR(bytesPerPixel); - SERIALIZE_ARRAY(dmaBuffer, height*width); - SERIALIZE_ARRAY(frameBuffer, height*width); + SERIALIZE_ARRAY(dmaBuffer, height * width); SERIALIZE_SCALAR(startTime); SERIALIZE_SCALAR(startAddr); SERIALIZE_SCALAR(maxAddr); @@ -569,10 +628,6 @@ UNSERIALIZE_SCALAR(lcdMis_serial); lcdMis = lcdMis_serial; - uint8_t lcdIcr_serial; - UNSERIALIZE_SCALAR(lcdIcr_serial); - lcdIcr = lcdIcr_serial; - UNSERIALIZE_ARRAY(lcdPalette, LcdPaletteSize); UNSERIALIZE_ARRAY(cursorImage, CrsrImageSize); @@ -602,25 +657,27 @@ UNSERIALIZE_SCALAR(clock); UNSERIALIZE_SCALAR(height); UNSERIALIZE_SCALAR(width); + UNSERIALIZE_SCALAR(bytesPerPixel); - UNSERIALIZE_ARRAY(dmaBuffer, height*width); - UNSERIALIZE_ARRAY(frameBuffer, height*width); + UNSERIALIZE_ARRAY(dmaBuffer, height * width); UNSERIALIZE_SCALAR(startTime); UNSERIALIZE_SCALAR(startAddr); UNSERIALIZE_SCALAR(maxAddr); UNSERIALIZE_SCALAR(curAddr); UNSERIALIZE_SCALAR(waterMark); UNSERIALIZE_SCALAR(dmaPendingNum); + + updateVideoParams(); } void Pl111::generateInterrupt() { DPRINTF(PL111, "Generate Interrupt: lcdImsc=0x%x lcdRis=0x%x lcdMis=0x%x\n", - lcdImsc, lcdRis, lcdMis); + (uint32_t)lcdImsc, (uint32_t)lcdRis, (uint32_t)lcdMis); lcdMis = lcdImsc & lcdRis; - if (lcdMis.ffufie || lcdMis.nbupie || lcdMis.vtcpie || lcdMis.ahmeie) { + if (lcdMis.underflow || lcdMis.baseaddr || lcdMis.vcomp || lcdMis.ahbmaster) { gic->sendInt(intNum); DPRINTF(PL111, " -- Generated\n"); } @@ -639,15 +696,4 @@ return new Pl111(this); } -// bitmap class ctor -Bitmap::Bitmap(std::fstream& bmp, uint16_t h, uint16_t w) -{ - Magic magic = {{'B','M'}}; - Header header = {sizeof(Color)*w*h , 0, 0, 54}; - Info info = {sizeof(Info), w, h, 1, sizeof(Color)*8, 0, - ( sizeof(Color) *(w*h) ), 1, 1, 0, 0}; - bmp.write(reinterpret_cast(&magic), sizeof(magic)); - bmp.write(reinterpret_cast(&header), sizeof(header)); - bmp.write(reinterpret_cast(&info), sizeof(info)); -} diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/rv_ctrl.hh --- a/src/dev/arm/rv_ctrl.hh Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/rv_ctrl.hh Tue Jan 18 16:36:11 2011 -0600 @@ -40,6 +40,7 @@ #ifndef __DEV_ARM_RV_HH__ #define __DEV_ARM_RV_HH__ +#include "base/bitunion.hh" #include "base/range.hh" #include "dev/io_device.hh" #include "params/RealViewCtrl.hh" @@ -86,6 +87,14 @@ TestOsc4 = 0xD0 }; + // system lock value + BitUnion32(SysLockReg) + Bitfield<15,0> lockVal; + Bitfield<16> locked; + EndBitUnion(SysLockReg) + + SysLockReg sysLock; + public: typedef RealViewCtrlParams Params; const Params * @@ -120,4 +129,3 @@ #endif // __DEV_ARM_RV_HH__ - diff -r 6896b2300693 -r e3c773d07601 src/dev/arm/rv_ctrl.cc --- a/src/dev/arm/rv_ctrl.cc Tue Jan 18 16:36:10 2011 -0600 +++ b/src/dev/arm/rv_ctrl.cc Tue Jan 18 16:36:11 2011 -0600 @@ -68,6 +68,27 @@ case Flash: pkt->set(0); break; + case Clcd: + pkt->set(0x00001F00); + break; + case Osc0: + pkt->set(0x00012C5C); + break; + case Osc1: + pkt->set(0x00002CC0); + break; + case Osc2: + pkt->set(0x00002C75); + break; + case Osc3: + pkt->set(0x00020211); + break; + case Osc4: + pkt->set(0x00002C75); + break; + case Lock: + pkt->set(sysLock); + break; default: panic("Tried to read RealView I/O at offset %#x that doesn't exist\n", daddr); break; @@ -86,6 +107,21 @@ switch (daddr) { case Flash: break; + case Clcd: + break; + case Osc0: + break; + case Osc1: + break; + case Osc2: + break; + case Osc3: + break; + case Osc4: + break; + case Lock: + sysLock.lockVal = pkt->get(); + break; default: panic("Tried to write RVIO at offset %#x that doesn't exist\n", daddr); break; diff -r 6896b2300693 -r e3c773d07601 src/dev/ps2.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dev/ps2.hh Tue Jan 18 16:36:11 2011 -0600 @@ -0,0 +1,93 @@ +/* + * 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 + */ + +#ifndef __DEV_PS2_HH__ +#define __DEV_PS2_HH__ + +#include + +#include "base/bitunion.hh" + +/** @file misc functions and constants required to interface with or emulate ps2 + * devices + */ + +namespace Ps2 { +enum { + Ps2Reset = 0xff, + SelfTestPass = 0xAA, + SetStatusLed = 0xed, + SetResolution = 0xe8, + StatusRequest = 0xe9, + SetScaling1_2 = 0xe7, + SetScaling1_1 = 0xe6, + ReadId = 0xf2, + TpReadId = 0xe1, + Ack = 0xfa, + SetRate = 0xf3, + Enable = 0xf4, + Disable = 0xf6, + KeyboardId = 0xab, + MouseId = 0x00, +}; + +/** A bitfield that represents the first byte of a mouse movement packet + */ +BitUnion8(Ps2MouseMovement) +Bitfield<0> leftButton; +Bitfield<1> rightButton; +Bitfield<2> middleButton; +Bitfield<3> one; +Bitfield<4> xSign; +Bitfield<5> ySign; +Bitfield<6> xOverflow; +Bitfield<7> yOverflow; +EndBitUnion(Ps2MouseMovement) + +/** Convert an x11 key symbol into a set of ps2 charecters. + * @param key x11 key symbol + * @param down if the key is being pressed or released + * @param cur_shift if device has already sent a shift + * @param keys list of keys command to send to emulate the x11 key symbol + */ +void keySymToPs2(uint32_t key, bool down, bool &cur_shift, + std::list &keys); + +} /* namespace Ps2 */ +#endif // __DEV_PS2_HH__ diff -r 6896b2300693 -r e3c773d07601 src/dev/ps2.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dev/ps2.cc Tue Jan 18 16:36:11 2011 -0600 @@ -0,0 +1,198 @@ +/* + * 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 + */ + +#include +#include + +#include "base/misc.hh" +#include "dev/ps2.hh" + + +namespace Ps2 { + +/** Table to convert simple key symbols (0x00XX) into ps2 bytes. Lower byte + * is the scan code to send and upper byte is if a modifier is required to + * generate it. The table generates us keyboard codes, (e.g. the guest is + * supposed to recognize the keyboard as en_US). A new table would be required + * for another local. + */ + +static const uint16_t keySymToPs2Byte[128] = { +// 0 / 8 1 / 9 2 / A 3 / B 4 / C 5 / D 6 / E 7 / F + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00-0x07 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x08-0x0f + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x10-0x17 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x18-0x1f + 0x0029, 0x0116, 0x0152, 0x0126, 0x0125, 0x012e, 0x013d, 0x0052, // 0x20-0x27 + 0x0146, 0x0145, 0x013e, 0x0155, 0x0041, 0x004e, 0x0049, 0x004a, // 0x28-0x2f + 0x0045, 0x0016, 0x001e, 0x0026, 0x0025, 0x002e, 0x0036, 0x003d, // 0x30-0x37 + 0x003e, 0x0046, 0x014c, 0x004c, 0x0141, 0x0055, 0x0149, 0x014a, // 0x38-0x3f + 0x011e, 0x011c, 0x0132, 0x0121, 0x0123, 0x0124, 0x012b, 0x0134, // 0x40-0x47 + 0x0133, 0x0143, 0x013b, 0x0142, 0x014b, 0x013a, 0x0131, 0x0144, // 0x48-0x4f + 0x014d, 0x0115, 0x012d, 0x011b, 0x012c, 0x013c, 0x012a, 0x011d, // 0x50-0x57 + 0x0122, 0x0135, 0x011a, 0x0054, 0x005d, 0x005b, 0x0136, 0x014e, // 0x58-0x5f + 0x000e, 0x001c, 0x0032, 0x0021, 0x0023, 0x0024, 0x002b, 0x0034, // 0x60-0x67 + 0x0033, 0x0043, 0x003b, 0x0042, 0x004b, 0x003a, 0x0031, 0x0044, // 0x68-0x6f + 0x004d, 0x0015, 0x002d, 0x001b, 0x002c, 0x003c, 0x002a, 0x001d, // 0x70-0x77 + 0x0022, 0x0035, 0x001a, 0x0154, 0x015d, 0x015b, 0x010e, 0x0000 // 0x78-0x7f +}; + +const uint8_t ShiftKey = 0x12; +const uint8_t BreakKey = 0xf0; +const uint8_t ExtendedKey = 0xe0; +const uint32_t UpperKeys = 0xff00; + +void keySymToPs2(uint32_t key, bool down, bool &cur_shift, + std::list &keys) +{ + if (key <= XK_asciitilde) { + uint16_t tmp = keySymToPs2Byte[key]; + uint8_t code = tmp & 0xff; + bool shift = tmp >> 8; + + if (down) { + if (!cur_shift && shift) { + keys.push_back(ShiftKey); + cur_shift = true; + } + keys.push_back(code); + } else { + if (cur_shift && !shift) { + keys.push_back(BreakKey); + keys.push_back(ShiftKey); + cur_shift = false; + } + keys.push_back(BreakKey); + keys.push_back(code); + } + } else { + if ((key & UpperKeys) == UpperKeys) { + bool extended = false; + switch (key) { + case XK_BackSpace: + keys.push_back(0x66); + break; + case XK_Tab: + keys.push_back(0x0d); + break; + case XK_Return: + keys.push_back(0x5a); + break; + case XK_Escape: + keys.push_back(0x76); + break; + case XK_Delete: + extended = true; + keys.push_back(0x71); + break; + case XK_Home: + extended = true; + keys.push_back(0x6c); + break; + case XK_Left: + extended = true; + keys.push_back(0x6b); + break; + case XK_Right: + extended = true; + keys.push_back(0x74); + break; + case XK_Down: + extended = true; + keys.push_back(0x72); + break; + case XK_Up: + extended = true; + keys.push_back(0x75); + break; + case XK_Page_Up: + extended = true; + keys.push_back(0x7d); + break; + case XK_Page_Down: + extended = true; + keys.push_back(0x7a); + break; + case XK_End: + extended = true; + keys.push_back(0x69); + break; + case XK_Shift_L: + keys.push_back(0x12); + if (down) + cur_shift = true; + else + cur_shift = false; + break; + case XK_Shift_R: + keys.push_back(0x59); + if (down) + cur_shift = true; + else + cur_shift = false; + break; + case XK_Control_L: + keys.push_back(0x14); + break; + case XK_Control_R: + extended = true; + keys.push_back(0x14); + break; + default: + warn("Unknown extended key %#x\n", key); + return; + } + + if (extended) { + if (down) { + keys.push_front(ExtendedKey); + } else { + keys.push_front(BreakKey); + keys.push_front(ExtendedKey); + } + } else { + if (!down) + keys.push_front(BreakKey); + } + } // upper keys + } // extended keys + return; +} + +}; diff -r 6896b2300693 -r e3c773d07601 src/sim/serialize.hh --- a/src/sim/serialize.hh Tue Jan 18 16:36:10 2011 -0600 +++ b/src/sim/serialize.hh Tue Jan 18 16:36:11 2011 -0600 @@ -70,6 +70,10 @@ const std::vector ¶m); template +void arrayParamOut(std::ostream &os, const std::string &name, + const std::list ¶m); + +template void arrayParamIn(Checkpoint *cp, const std::string §ion, const std::string &name, T *param, unsigned size); @@ -77,6 +81,10 @@ void arrayParamIn(Checkpoint *cp, const std::string §ion, const std::string &name, std::vector ¶m); +template +void arrayParamIn(Checkpoint *cp, const std::string §ion, + const std::string &name, std::list ¶m); + void objParamIn(Checkpoint *cp, const std::string §ion, const std::string &name, SimObject * ¶m); diff -r 6896b2300693 -r e3c773d07601 src/sim/serialize.cc --- a/src/sim/serialize.cc Tue Jan 18 16:36:10 2011 -0600 +++ b/src/sim/serialize.cc Tue Jan 18 16:36:11 2011 -0600 @@ -201,6 +201,23 @@ os << "\n"; } +template +void +arrayParamOut(ostream &os, const string &name, const list ¶m) +{ + typename list::const_iterator it = param.begin(); + + os << name << "="; + if (param.size() > 0) + showParam(os, *it); + it++; + while (it != param.end()) { + os << " "; + showParam(os, *it); + it++; + } + os << "\n"; +} template void @@ -326,6 +343,37 @@ } } +template +void +arrayParamIn(Checkpoint *cp, const string §ion, + const string &name, list ¶m) +{ + string str; + if (!cp->find(section, name, str)) { + fatal("Can't unserialize '%s:%s'\n", section, name); + } + param.clear(); + + vector tokens; + tokenize(tokens, str, ' '); + + for (vector::size_type i = 0; i < tokens.size(); i++) { + T scalar_value = 0; + if (!parseParam(tokens[i], scalar_value)) { + string err("could not parse \""); + + err += str; + err += "\""; + + fatal(err); + } + + // assign parsed value to vector + param.push_back(scalar_value); + } +} + + void objParamIn(Checkpoint *cp, const string §ion, const string &name, SimObject * ¶m) @@ -356,7 +404,13 @@ const vector ¶m); \ template void \ arrayParamIn(Checkpoint *cp, const string §ion, \ - const string &name, vector ¶m); + const string &name, vector ¶m); \ +template void \ +arrayParamOut(ostream &os, const string &name, \ + const list ¶m); \ +template void \ +arrayParamIn(Checkpoint *cp, const string §ion, \ + const string &name, list ¶m); INSTANTIATE_PARAM_TEMPLATES(char) INSTANTIATE_PARAM_TEMPLATES(signed char)