//#define COSMOSDEBUG using System; using Cosmos.Core; using Cosmos.Core.IOGroup; namespace Cosmos.HAL.Drivers { /// /// VBEDriver class. Used to directly write registers values to the port. /// public class VBEDriver { private static readonly VBEIOGroup IO = Core.Global.BaseIOGroups.VBE; ManagedMemoryBlock lastbuffer; /// /// Register index. /// /// Avilable indexs: /// /// DisplayID. /// DisplayXResolution. /// DisplayYResolution. /// DisplayBPP. /// DisplayEnable. /// DisplayBankMode. /// DisplayVirtualWidth. /// DisplayVirtualHeight. /// DisplayXOffset. /// DisplayYOffset. /// /// /// private enum RegisterIndex { DisplayID = 0x00, DisplayXResolution, DisplayYResolution, DisplayBPP, DisplayEnable, DisplayBankMode, DisplayVirtualWidth, DisplayVirtualHeight, DisplayXOffset, DisplayYOffset }; /// /// Enable values. /// /// Avilable values: /// /// Disabled. /// Enabled. /// UseLinearFrameBuffer. /// NoClearMemory. /// /// /// [Flags] private enum EnableValues { Disabled = 0x00, Enabled, UseLinearFrameBuffer = 0x40, NoClearMemory = 0x80, }; /// /// Create new instance of the class. /// /// X resolution. /// Y resolution. /// BPP (color depth). public VBEDriver(ushort xres, ushort yres, ushort bpp) { PCIDevice videocard; if (VBE.IsAvailable()) //VBE VESA Enabled Mulitboot Parsing { Global.mDebugger.SendInternal($"Creating VBE VESA driver with Mode {xres}*{yres}@{bpp}"); IO.LinearFrameBuffer = new MemoryBlock(VBE.getLfbOffset(), (uint)xres * yres * (uint)(bpp / 8)); lastbuffer = new ManagedMemoryBlock((uint)xres * yres * (uint)(bpp / 8)); } else if (ISAModeAvailable()) //Bochs Graphics Adaptor ISA Mode { Global.mDebugger.SendInternal($"Creating VBE BGA driver with Mode {xres}*{yres}@{bpp}."); IO.LinearFrameBuffer = new MemoryBlock(0xE0000000, 1920 * 1200 * 4); lastbuffer = new ManagedMemoryBlock(1920 * 1200 * 4); VBESet(xres, yres, bpp); } else if (((videocard = HAL.PCI.GetDevice(VendorID.VirtualBox, DeviceID.VBVGA)) != null) || //VirtualBox Video Adapter PCI Mode ((videocard = HAL.PCI.GetDevice(VendorID.Bochs, DeviceID.BGA)) != null)) // Bochs Graphics Adaptor PCI Mode { Global.mDebugger.SendInternal($"Creating VBE BGA driver with Mode {xres}*{yres}@{bpp}. Framebuffer address=" + videocard.BAR0); IO.LinearFrameBuffer = new MemoryBlock(videocard.BAR0, 1920 * 1200 * 4); lastbuffer = new ManagedMemoryBlock(1920 * 1200 * 4); VBESet(xres, yres, bpp); } else { throw new Exception("No supported VBE device found."); } } /// /// Write value to VBE index. /// /// Register index. /// Value. private static void VBEWrite(RegisterIndex index, ushort value) { IO.VbeIndex.Word = (ushort) index; IO.VbeData.Word = value; } private static ushort VBERead(RegisterIndex index) { IO.VbeIndex.Word = (ushort)index; return IO.VbeData.Word; } public static bool ISAModeAvailable() { //This code wont work as long as Bochs uses BGA ISA, since it wont discover it in PCI #if false return HAL.PCI.GetDevice(VendorID.Bochs, DeviceID.BGA) != null; #endif return VBERead(RegisterIndex.DisplayID) == 0xB0C5; } /// /// Disable display. /// public void DisableDisplay() { Global.mDebugger.SendInternal($"Disabling VBE display"); VBEWrite(RegisterIndex.DisplayEnable, (ushort)EnableValues.Disabled); } /// /// Set X resolution. /// /// X resolution. private void SetXResolution(ushort xres) { Global.mDebugger.SendInternal($"VBE Setting X resolution to {xres}"); VBEWrite(RegisterIndex.DisplayXResolution, xres); } /// /// Set Y resolution. /// /// Y resolution. private void SetYResolution(ushort yres) { Global.mDebugger.SendInternal($"VBE Setting Y resolution to {yres}"); VBEWrite(RegisterIndex.DisplayYResolution, yres); } /// /// Set BPP. /// /// BPP (color depth). private void SetDisplayBPP(ushort bpp) { Global.mDebugger.SendInternal($"VBE Setting BPP to {bpp}"); VBEWrite(RegisterIndex.DisplayBPP, bpp); } /// /// Enable display. /// private void EnableDisplay(EnableValues EnableFlags) { //Global.mDebugger.SendInternal($"VBE Enabling display with EnableFlags (ushort){EnableFlags}"); VBEWrite(RegisterIndex.DisplayEnable, (ushort)EnableFlags); } /// /// Set VBE values. /// /// X resolution. /// Y resolution. /// BPP (color depth). public void VBESet(ushort xres, ushort yres, ushort bpp) { DisableDisplay(); SetXResolution(xres); SetYResolution(yres); SetDisplayBPP(bpp); /* * Re-enable the Display with LinearFrameBuffer and without clearing video memory of previous value * (this permits to change Mode without losing the previous datas) */ EnableDisplay(EnableValues.Enabled | EnableValues.UseLinearFrameBuffer | EnableValues.NoClearMemory); } /// /// Set VRAM. /// /// Index to set. /// Value to set. public void SetVRAM(uint index, byte value) { Global.mDebugger.SendInternal($"Writing to driver memory in position {index} value {value} (as byte)"); lastbuffer[index] = value; } /// /// Set VRAM. /// /// Index to set. /// Value to set. public void SetVRAM(uint index, ushort value) { //Global.mDebugger.SendInternal($"Writing to driver memory in position {index} value {value} (as ushort)"); lastbuffer[index] = (byte)((value >> 8) & 0xFF); lastbuffer[index + 1] = (byte)((value >> 0) & 0xFF); } /// /// Set VRAM. /// /// Index to set. /// Value to set. public void SetVRAM(uint index, uint value) { //Global.mDebugger.SendInternal($"Writing to driver memory in position {index} value {value} (as uint)"); lastbuffer[index] = (byte)((value >> 24) & 0xFF); lastbuffer[index + 1] = (byte)((value >> 16) & 0xFF); lastbuffer[index + 2] = (byte)((value >> 8) & 0xFF); lastbuffer[index + 3] = (byte)((value >> 0) & 0xFF); } /// /// Get VRAM. /// /// Index to get. /// byte value. public uint GetVRAM(uint index) { int pixel = (lastbuffer[index + 3] << 24) | (lastbuffer[index + 2] << 16) | (lastbuffer[index + 1] << 8) | lastbuffer[index]; return (uint)pixel; } /// /// Clear VRAM. /// /// Value of fill with. public void ClearVRAM(uint value) { lastbuffer.Fill(value); } /// /// Clear VRAM. /// /// A start. /// A count. /// A volum. public void ClearVRAM(int aStart, int aCount, int value) { lastbuffer.Fill(aStart, aCount, value); } /// /// Copy VRAM. /// /// A start. /// A data. /// A index. /// A count. public void CopyVRAM(int aStart, int[] aData, int aIndex, int aCount) { lastbuffer.Copy(aStart, aData, aIndex, aCount); } /// /// Swap back buffer to video memory /// public void Swap() { IO.LinearFrameBuffer.Copy(lastbuffer); } } }