The Pedigree Project  0.1
modules/drivers/x86/vmware-gfx/main.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "modules/Module.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/Service.h"
23 #include "pedigree/kernel/ServiceFeatures.h"
24 #include "pedigree/kernel/ServiceManager.h"
25 #include "pedigree/kernel/graphics/Graphics.h"
26 #include "pedigree/kernel/graphics/GraphicsService.h"
27 #include "pedigree/kernel/machine/Device.h"
28 #include "pedigree/kernel/machine/Display.h"
29 #include "pedigree/kernel/machine/Framebuffer.h"
30 #include "pedigree/kernel/machine/Machine.h"
31 #include "pedigree/kernel/machine/Vga.h"
32 #include "pedigree/kernel/processor/IoBase.h"
33 #include "pedigree/kernel/processor/MemoryMappedIo.h"
34 #include "pedigree/kernel/processor/types.h"
35 #include "pedigree/kernel/utilities/List.h"
36 #include "pedigree/kernel/utilities/String.h"
37 #include "pedigree/kernel/utilities/Vector.h"
38 #include "pedigree/kernel/utilities/new"
39 #include "svga_reg.h"
40 #include "vm_device_version.h"
41 
42 #define DEBUG_VMWARE_GFX 0
43 
44 static struct mode
45 {
46  size_t id;
47  size_t width;
48  size_t height;
49  Graphics::PixelFormat fmt;
50 } g_VbeIndexedModes[] = {
51  {0x117, 1024, 768,
52  Graphics::Bits16_Rgb555}, // Format is used only for byte count
53  {0, 80, 25, Graphics::Bits8_Idx}
54 };
55 
56 #define SUPPORTED_MODES_SIZE \
57  (sizeof(g_VbeIndexedModes) / sizeof(g_VbeIndexedModes[0]))
58 
59 // Can refer to
60 // http://sourceware.org/ml/ecos-devel/2006-10/msg00008/README.xfree86 for
61 // information about programming this device, as well as the Haiku driver.
62 
63 class VmwareGraphics : public Display
64 {
65  friend class VmwareFramebuffer;
66 
67  public:
68  VmwareGraphics(Device *pDev)
69  : Display(pDev), m_pIo(0), m_Framebuffer(0), m_CommandRegion(0),
70  m_pFramebufferRawAddress(0)
71  {
72  m_pIo = m_Addresses[0]->m_Io;
73 
74  // Support ID2, as we are expecting an SVGA2 functional device
75  writeRegister(SVGA_REG_ID, SVGA_MAKE_ID(2));
76  if (readRegister(SVGA_REG_ID) != SVGA_MAKE_ID(2))
77  {
78  WARNING("vmware-gfx not a compatible SVGA device");
79  return;
80  }
81 
82  // Read the framebuffer base (should match BAR1)
83  uintptr_t fbBase = readRegister(SVGA_REG_FB_START);
84  size_t fbSize = readRegister(SVGA_REG_VRAM_SIZE);
85 
86  // Read the command FIFO (should match BAR2)
87  uintptr_t cmdBase = readRegister(SVGA_REG_MEM_START);
88  size_t cmdSize = readRegister(SVGA_REG_MEM_SIZE);
89 
90  // Find the capabilities of the device
91  size_t caps = readRegister(SVGA_REG_CAPABILITIES);
92 
93  // Read maximum resolution
94  size_t maxWidth = readRegister(SVGA_REG_MAX_WIDTH);
95  size_t maxHeight = readRegister(SVGA_REG_MAX_HEIGHT);
96 
97  // Tell VMware what OS we are - "Other"
98  writeRegister(SVGA_REG_GUEST_ID, 0x500A);
99 
100  // Debug notification
101  NOTICE(
102  "vmware-gfx found, caps=" << Hex << caps
103  << ", maximum resolution is " << Dec
104  << maxWidth << "x" << maxHeight << Hex);
105  NOTICE(
106  "vmware-gfx framebuffer at "
107  << Hex << fbBase << " - " << (fbBase + fbSize)
108  << ", command FIFO at " << cmdBase);
109 
110  if (m_Addresses[1]->m_Address == fbBase)
111  {
112  m_Framebuffer = static_cast<MemoryMappedIo *>(m_Addresses[1]->m_Io);
113  m_CommandRegion =
114  static_cast<MemoryMappedIo *>(m_Addresses[2]->m_Io);
115  m_Addresses[2]->map();
116 
117  m_pFramebufferRawAddress = m_Addresses[1];
118  }
119  else
120  {
121  m_Framebuffer = static_cast<MemoryMappedIo *>(m_Addresses[2]->m_Io);
122  m_CommandRegion =
123  static_cast<MemoryMappedIo *>(m_Addresses[1]->m_Io);
124  m_Addresses[1]->map();
125 
126  m_pFramebufferRawAddress = m_Addresses[2];
127  }
128 
129  // Disable the command FIFO in case it was already enabled
130  writeRegister(SVGA_REG_CONFIG_DONE, 0);
131 
132  // Don't yet enable the SVGA.
133  writeRegister(SVGA_REG_ENABLE, 0);
134 
135  // Initialise the FIFO
136  volatile uint32_t *fifo = reinterpret_cast<volatile uint32_t *>(
137  m_CommandRegion->virtualAddress());
138 
139  if (caps & SVGA_CAP_EXTENDED_FIFO)
140  {
141  size_t numFifoRegs = readRegister(SVGA_REG_MEM_REGS);
142  size_t fifoExtendedBase = numFifoRegs * 4;
143 
144  fifo[SVGA_FIFO_MIN] =
145  fifoExtendedBase; // Start right after this information block
146  fifo[SVGA_FIFO_MAX] =
147  cmdSize & ~0x3; // Permit the full FIFO to be used
148  fifo[SVGA_FIFO_NEXT_CMD] = fifo[SVGA_FIFO_STOP] =
149  fifo[SVGA_FIFO_MIN]; // Empty FIFO
150 
151  NOTICE(
152  "vmware-gfx using extended fifo, caps="
153  << fifo[SVGA_FIFO_CAPABILITIES]
154  << ", flags=" << fifo[SVGA_FIFO_FLAGS]);
155  }
156  else
157  {
158  fifo[SVGA_FIFO_MIN] =
159  16; // Start right after this information block
160  fifo[SVGA_FIFO_MAX] =
161  cmdSize & ~0x3; // Permit the full FIFO to be used
162  fifo[SVGA_FIFO_NEXT_CMD] = fifo[SVGA_FIFO_STOP] = 16; // Empty FIFO
163  }
164 
165  m_pFramebuffer = new VmwareFramebuffer(
166  reinterpret_cast<uintptr_t>(m_Framebuffer->virtualAddress()), this);
167 
170  pProvider->pDisplay = this;
171  pProvider->pFramebuffer = m_pFramebuffer;
172  pProvider->maxWidth = maxWidth;
173  pProvider->maxHeight = maxHeight;
174  pProvider->maxTextWidth = 0;
175  pProvider->maxTextHeight = 0;
176  pProvider->maxDepth = 32;
177  pProvider->bHardwareAccel = true;
178  pProvider->bTextModes = false;
179 
180  // Register with the graphics service
181  ServiceFeatures *pFeatures =
182  ServiceManager::instance().enumerateOperations(String("graphics"));
183  Service *pService =
184  ServiceManager::instance().getService(String("graphics"));
185  bool bSuccess = false;
186  if (pFeatures && pFeatures->provides(ServiceFeatures::touch))
187  if (pService)
188  bSuccess = pService->serve(
189  ServiceFeatures::touch, reinterpret_cast<void *>(pProvider),
190  sizeof(*pProvider));
191 
192  if (!bSuccess)
193  {
194  delete pProvider;
195  }
196  }
197 
198  virtual ~VmwareGraphics();
199 
200  virtual void getName(String &str)
201  {
202  str = "vmware-gfx";
203  }
204 
205  virtual void dump(String &str)
206  {
207  str = "vmware guest tools, graphics card";
208  }
209 
213  {
214  sm.width = readRegister(SVGA_REG_WIDTH);
215  sm.height = readRegister(SVGA_REG_HEIGHT);
216  sm.pf.nBpp = readRegister(SVGA_REG_BITS_PER_PIXEL);
217 
218  size_t redMask = readRegister(SVGA_REG_RED_MASK);
219  size_t greenMask = readRegister(SVGA_REG_GREEN_MASK);
220  size_t blueMask = readRegister(SVGA_REG_BLUE_MASK);
221 
223  switch (sm.pf.nBpp)
224  {
225  case 24:
226  if (redMask > blueMask)
227  sm.pf2 = Graphics::Bits24_Rgb;
228  else
229  sm.pf2 = Graphics::Bits24_Bgr;
230  break;
231  case 16:
232  if ((redMask == greenMask) && (greenMask == blueMask))
233  {
234  if (blueMask == 0xF)
235  sm.pf2 = Graphics::Bits16_Argb;
236  else
237  sm.pf2 = Graphics::Bits16_Rgb555;
238  }
239  else
240  sm.pf2 = Graphics::Bits16_Rgb565;
241  break;
242  default:
243  sm.pf2 = Graphics::Bits32_Argb;
244  break;
245  }
246 
247  sm.bytesPerPixel = sm.pf.nBpp / 8;
248  sm.bytesPerLine = readRegister(SVGA_REG_BYTES_PER_LINE);
249 
250  return true;
251  }
252 
256  {
257  for (size_t i = 0; i < SUPPORTED_MODES_SIZE; i++)
258  {
260  pMode->id = g_VbeIndexedModes[i].id;
261  pMode->width = g_VbeIndexedModes[i].width;
262  pMode->height = g_VbeIndexedModes[i].height;
263  pMode->pf2 = g_VbeIndexedModes[i].fmt;
264 
265  sms.pushBack(pMode);
266  }
267 
268  // Add 'disable SVGA' mode.
270  pMode->id = 0;
271 
272  sms.pushBack(pMode);
273 
274  return true;
275  }
276 
280  {
281  if (sm.id == 0)
282  {
283  // Disable SVGA instead of setting a mode
284  writeRegister(SVGA_REG_ENABLE, 0);
285  }
286  else
287  {
288  setMode(sm.width, sm.height, Graphics::bitsPerPixel(sm.pf2));
289  Machine::instance().getVga(0)->setMode(
290  sm.id); // Remember this new mode
291  }
292  return true;
293  }
294 
295  virtual bool setScreenMode(size_t modeId)
296  {
297  return Display::setScreenMode(modeId);
298  }
299 
300  virtual bool setScreenMode(size_t nWidth, size_t nHeight, size_t nBpp)
301  {
302  // Read maximum resolution
303  size_t maxWidth = readRegister(SVGA_REG_MAX_WIDTH);
304  size_t maxHeight = readRegister(SVGA_REG_MAX_HEIGHT);
305 
306  // Check the passed resolution is within these boundaries: if not,
307  // modify it. Applications that use framebuffers from us should use
308  // their width/height methods in order to handle any potential
309  // screen resolution.
310  if (nWidth > maxWidth)
311  nWidth = maxWidth;
312  if (nHeight > maxHeight)
313  nHeight = maxHeight;
314 
315  setMode(nWidth, nHeight, nBpp);
316  return true;
317  }
318 
319  void setMode(size_t w, size_t h, size_t bpp)
320  {
321  // Enable the SVGA if not already enabled.
322  writeRegister(SVGA_REG_ENABLE, 1);
323 
324  // Set mode
325  writeRegister(SVGA_REG_WIDTH, w);
326  writeRegister(SVGA_REG_HEIGHT, h);
327  writeRegister(SVGA_REG_BITS_PER_PIXEL, bpp);
328 
329  size_t fbOffset = readRegister(SVGA_REG_FB_OFFSET);
330  size_t width = readRegister(SVGA_REG_WIDTH);
331  size_t height = readRegister(SVGA_REG_HEIGHT);
332  size_t depth = readRegister(SVGA_REG_DEPTH);
333  uintptr_t fbBase = readRegister(SVGA_REG_FB_START);
334 
335  size_t redMask = readRegister(SVGA_REG_RED_MASK);
336  size_t greenMask = readRegister(SVGA_REG_GREEN_MASK);
337  size_t blueMask = readRegister(SVGA_REG_BLUE_MASK);
338 
339  size_t bytesPerLine = readRegister(SVGA_REG_BYTES_PER_LINE);
340  size_t bytesPerPixel = bytesPerLine / w;
341 
342  m_pFramebuffer->setWidth(w);
343  m_pFramebuffer->setHeight(h);
344  m_pFramebuffer->setBytesPerPixel(bytesPerPixel);
345  m_pFramebuffer->setBytesPerLine(bytesPerLine);
346 
347  Graphics::PixelFormat pf;
348  switch (bpp)
349  {
350  case 24:
351  if (redMask > blueMask)
352  pf = Graphics::Bits24_Rgb;
353  else
354  pf = Graphics::Bits24_Bgr;
355  break;
356  case 16:
357  if ((redMask == greenMask) && (greenMask == blueMask))
358  {
359  if (blueMask == 0xF)
360  pf = Graphics::Bits16_Argb;
361  else
362  pf = Graphics::Bits16_Rgb555;
363  }
364  else
365  pf = Graphics::Bits16_Rgb565;
366  break;
367  default:
368  pf = Graphics::Bits32_Argb;
369  break;
370  }
371  m_pFramebuffer->setFormat(pf);
372  m_pFramebuffer->setXPos(0);
373  m_pFramebuffer->setYPos(0);
374  m_pFramebuffer->setParent(0);
375 
378  m_pFramebufferRawAddress->map(height * bytesPerLine, true, true);
379  m_pFramebuffer->setFramebuffer(
380  reinterpret_cast<uintptr_t>(m_Framebuffer->virtualAddress()));
381 
382  // Blank the framebuffer, new mode
383  m_pFramebuffer->rect(0, 0, w, h, 0);
384 
385  // Start running the FIFO
386  writeRegister(SVGA_REG_CONFIG_DONE, 1);
387 
388  NOTICE(
389  "vmware-gfx entered mode "
390  << Dec << width << "x" << height << "x" << depth << Hex
391  << ", mode framebuffer is " << (fbBase + fbOffset));
392  }
393 
394  void redraw(size_t x, size_t y, size_t w, size_t h)
395  {
396  // Disable the command FIFO while we link the command
397  writeRegister(SVGA_REG_CONFIG_DONE, 0);
398 
399  if (w > m_pFramebuffer->getWidth())
400  w = m_pFramebuffer->getWidth();
401  if (h > m_pFramebuffer->getHeight())
402  h = m_pFramebuffer->getHeight();
403 
404  writeFifo(SVGA_CMD_UPDATE);
405  writeFifo(x);
406  writeFifo(y);
407  writeFifo(w);
408  writeFifo(h);
409 
410  // Start running the FIFO
411  writeRegister(SVGA_REG_CONFIG_DONE, 1);
412  }
413 
414  void copy(size_t x1, size_t y1, size_t x2, size_t y2, size_t w, size_t h)
415  {
416  // Disable the command FIFO while we link the command
417  writeRegister(SVGA_REG_CONFIG_DONE, 0);
418 
419  writeFifo(SVGA_CMD_RECT_COPY); // RECT COPY
420  writeFifo(x1); // Source X
421  writeFifo(y1); // Source Y
422  writeFifo(x2); // Dest X
423  writeFifo(y2); // Dest Y
424  writeFifo(w); // Width
425  writeFifo(h); // Height
426 
427  // Start running the FIFO
428  writeRegister(SVGA_REG_CONFIG_DONE, 1);
429  }
430 
432  {
433  public:
435  {
436  }
437 
438  VmwareFramebuffer(uintptr_t fb, VmwareGraphics *pDisplay)
439  : Framebuffer(), m_pDisplay(pDisplay)
440  {
441  setFramebuffer(fb);
442  }
443 
444  virtual ~VmwareFramebuffer();
445 
446  virtual void hwRedraw(
447  size_t x = ~0UL, size_t y = ~0UL, size_t w = ~0UL, size_t h = ~0UL)
448  {
449  if (x == ~0UL)
450  x = 0;
451  if (y == ~0UL)
452  y = 0;
453  if (w == ~0UL)
454  w = getWidth();
455  if (h == ~0UL)
456  h = getHeight();
457  m_pDisplay->redraw(x, y, w, h);
458  }
459 
460  virtual inline void copy(
461  size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w,
462  size_t h, bool bLowestCall = true)
463  {
465  if (1)
466  m_pDisplay->copy(srcx, srcy, destx, desty, w, h);
467  // else
468  // swCopy(srcx, srcy, destx, desty, w, h);
469  }
470 
471  private:
472  VmwareGraphics *m_pDisplay;
473  };
474 
475  private:
476  IoBase *m_pIo;
477 
479 
480  size_t readRegister(size_t offset)
481  {
482  m_pIo->write32(offset, SVGA_INDEX_PORT);
483  return m_pIo->read32(SVGA_VALUE_PORT);
484  }
485 
486  void writeRegister(size_t offset, uint32_t value)
487  {
488  m_pIo->write32(offset, SVGA_INDEX_PORT);
489  m_pIo->write32(value, SVGA_VALUE_PORT);
490  }
491 
492  void writeFifo(uint32_t value)
493  {
494  volatile uint32_t *fifo = reinterpret_cast<volatile uint32_t *>(
495  m_CommandRegion->virtualAddress());
496 
497  // Check for sync conditions
498  if (((fifo[SVGA_FIFO_NEXT_CMD] + 4) == fifo[SVGA_FIFO_STOP]) ||
499  (fifo[SVGA_FIFO_NEXT_CMD] == (fifo[SVGA_FIFO_MAX] - 4)))
500  {
501 #if DEBUG_VMWARE_GFX
502  DEBUG_LOG("vmware-gfx synchronising full fifo");
503 #endif
504  syncFifo();
505  }
506 
507 #if DEBUG_VMWARE_GFX
508  DEBUG_LOG(
509  "vmware-gfx fifo write at " << fifo[SVGA_FIFO_NEXT_CMD]
510  << " val=" << value);
511  DEBUG_LOG(
512  "vmware-gfx min is at " << fifo[SVGA_FIFO_MIN]
513  << " and current position is "
514  << fifo[SVGA_FIFO_STOP]);
515 #endif
516 
517  // Load the new item into the FIFO
518  fifo[fifo[SVGA_FIFO_NEXT_CMD] / 4] = value;
519  if (fifo[SVGA_FIFO_NEXT_CMD] == (fifo[SVGA_FIFO_MAX] - 4))
520  fifo[SVGA_FIFO_NEXT_CMD] = fifo[SVGA_FIFO_MIN];
521  else
522  fifo[SVGA_FIFO_NEXT_CMD] += 4;
523 
524  asm volatile("" : : : "memory");
525  }
526 
527  void syncFifo()
528  {
529  writeRegister(SVGA_REG_SYNC, 1);
530  while (readRegister(SVGA_REG_BUSY))
531  ;
532  }
533 
534  MemoryMappedIo *m_Framebuffer;
535  MemoryMappedIo *m_CommandRegion;
536 
537  VmwareFramebuffer *m_pFramebuffer;
538 
539  Device::Address *m_pFramebufferRawAddress;
540 };
541 
542 static bool bFound = false;
543 
544 static void callback(Device *pDevice)
545 {
547  new VmwareGraphics(pDevice);
548  bFound = true;
549 }
550 
551 static bool entry()
552 {
553  // Don't care about non-SVGA2 devices, just use VBE for them.
554  Device::searchByVendorIdAndDeviceId(
555  PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_SVGA2, callback);
556 
557  return bFound;
558 }
559 
560 static void exit()
561 {
562 }
563 
564 MODULE_INFO("vmware-gfx", &entry, &exit, "pci", "config");
565 
566 VmwareGraphics::~VmwareGraphics() = default;
567 VmwareGraphics::VmwareFramebuffer::~VmwareFramebuffer() = default;
void pushBack(const T &value)
Definition: List.h:232
virtual void copy(size_t srcx, size_t srcy, size_t destx, size_t desty, size_t w, size_t h, bool bLowestCall=true)
virtual bool getScreenModes(List< Display::ScreenMode * > &sms)
Memory mapped I/O range.
void setMode(size_t w, size_t h, size_t bpp)
Definition: String.h:49
virtual bool provides(Type service)
virtual Vga * getVga(size_t n)=0
Abstrace base class for hardware I/O capabilities.
Definition: IoBase.h:31
virtual void dump(String &str)
Definition: Device.h:43
uint8_t nBpp
Bits per pixel (total).
Definition: Display.h:65
virtual bool setMode(int mode)=0
virtual bool getCurrentScreenMode(Display::ScreenMode &sm)
#define WARNING(text)
Definition: Log.h:78
virtual bool setScreenMode(size_t nWidth, size_t nHeight, size_t nBpp)
virtual uint32_t read32(size_t offset=0)=0
#define NOTICE(text)
Definition: Log.h:74
virtual void hwRedraw(size_t x=~0UL, size_t y=~0UL, size_t w=~0UL, size_t h=~0UL)
Inherited by drivers that provide a hardware redraw function.
Definition: Log.h:136
Abstracts the system&#39;s framebuffer offering.
Service * getService(const String &serviceName)
virtual bool serve(ServiceFeatures::Type type, void *pData, size_t dataLen)=0
virtual bool setScreenMode(Display::ScreenMode sm)
Definition: Log.h:138
virtual bool setScreenMode(size_t modeId)
#define DEBUG_LOG(text)
Definition: Log.h:69
ServiceFeatures * enumerateOperations(const String &serviceName)
virtual void write32(uint32_t value, size_t offset=0)=0
virtual void getName(String &str)
virtual bool setScreenMode(ScreenMode sm)
Definition: Display.cc:110