diff --git a/source/Cosmos.Core/ACPI.cs b/source/Cosmos.Core/ACPI.cs
index 20e4ef9fd8..4195eef93c 100644
--- a/source/Cosmos.Core/ACPI.cs
+++ b/source/Cosmos.Core/ACPI.cs
@@ -1,484 +1,354 @@
-using System;
+using Cosmos.Core;
+using System;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Cosmos.Core
{
- ///
- /// ACPI (Advanced Configuration and Power Interface) class.
- ///
public unsafe class ACPI
{
- ///
- /// RSD table struct.
- ///
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public unsafe struct RSDPtr
- {
- ///
- /// Signature.
- ///
- public fixed byte Signature[8];
- ///
- /// CheckSum
- ///
- public byte CheckSum;
- ///
- /// OemID
- ///
- public fixed byte OemID[6];
- ///
- /// Revision
- ///
- public byte Revision;
- ///
- /// RSDT Address
- ///
- public int RsdtAddress;
- };
-
- // New Port I/O
- ///
- /// IO port.
- ///
- private static ushort smiIO, pm1aIO, pm1bIO;
-
- // ACPI variables
- ///
- /// SMI CMD.
- ///
- private static int* SMI_CMD;
- ///
- /// ACPI ENABLE.
- ///
- private static byte ACPI_ENABLE;
- ///
- /// ACPI DISABLE.
- ///
- private static byte ACPI_DISABLE;
- ///
- /// PM1a CNT
- ///
- private static int* PM1a_CNT;
- ///
- /// PM1b CNT
- ///
- private static int* PM1b_CNT;
- ///
- /// SLP TYPa
- ///
private static short SLP_TYPa;
- ///
- /// SLP TYPb
- ///
private static short SLP_TYPb;
- ///
- /// SLP EN.
- ///
private static short SLP_EN;
- ///
- /// PM1 CNT LEN1
- ///
- private static byte PM1_CNT_LEN;
-
- ///
- /// Check ACPI header.
- ///
- ///
- ///
- ///
- static int acpiCheckHeader(byte* ptr, string sig)
+
+ public static ACPI_FADT* FADT;
+ public static ACPI_MADT* MADT;
+ public static APIC_IO_APIC* IO_APIC;
+ public static ACPI_HPET* HPET;
+ public static MCFGHeader* MCFG;
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ private struct ACPI_RSDP
{
- return Compare(sig, ptr);
- }
+ public fixed sbyte Signature[8];
+ public byte Checksum;
+ public fixed sbyte OEMID[6];
+ public byte Revision;
+ public uint RsdtAddress;
+ };
- ///
- /// FACP.
- ///
- private static byte* Facp = null;
- ///
- /// FACP struct.
- ///
[StructLayout(LayoutKind.Sequential, Pack = 1)]
- struct FACP
+ public struct ACPI_HEADER
{
- ///
- /// Signature.
- ///
- public fixed byte Signature[4];
- ///
- /// Length.
- ///
- public int Length;
-
- ///
- /// Unused.
- ///
- public fixed byte unneded1[40 - 8];
- ///
- /// DSDT.
- ///
- public int* DSDT;
- ///
- /// Unused.
- ///
- public fixed byte unneded2[48 - 44];
- ///
- /// SMI CMD.
- ///
- public int* SMI_CMD;
- ///
- /// ACPI ENABLE.
- ///
- public byte ACPI_ENABLE;
- ///
- /// ACPI DISABLE.
- ///
- public byte ACPI_DISABLE;
- ///
- /// Unused.
- ///
- public fixed byte unneded3[64 - 54];
- ///
- /// PM1a CNT BLK.
- ///
- public int* PM1a_CNT_BLK;
- ///
- /// PM1b CNT BLK.
- ///
- public int* PM1b_CNT_BLK;
- ///
- /// Unused.
- ///
- public fixed byte unneded4[89 - 72];
- ///
- /// PM1 CNT LEN.
- ///
- public byte PM1_CNT_LEN;
+ public fixed sbyte Signature[4];
+ public uint Length;
+ public byte Revision;
+ public byte Checksum;
+ public fixed byte OEMID[6];
+ public fixed sbyte OEMTableID[8];
+ public uint OEMRevision;
+ public uint CreatorID;
+ public uint CreatorRevision;
};
- ///
- /// Compare string to byte array.
- ///
- /// String.
- /// Pointer to the head of the byte array.
- /// 0 - identical, -1 different.
- static int Compare(string c1, byte* c2)
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct APIC_HEADER
{
- for (int i = 0; i < c1.Length; i++)
- {
- if (c1[i] != c2[i]) { return -1; }
- }
- return 0;
+ public APIC_TYPE Type;
+ public byte Length;
}
- ///
- /// Check RSD checksum.
- ///
- /// Address to check.
- /// True if RSDT table checksum is good.
- static bool Check_RSD(uint address)
+ public enum APIC_TYPE : byte
{
- byte sum = 0;
- byte* check = (byte*)address;
+ LocalAPIC,
+ IOAPIC,
+ InterruptOverride
+ }
- for (int i = 0; i < 20; i++)
- {
- sum += *check++;
- }
+ [StructLayout(LayoutKind.Sequential,Pack = 1)]
+ public struct MCFGHeader
+ {
+ public ACPI_HEADER Header;
+ public ulong Reserved;
+ public MCFGEntry Entry0;
+ }
- return sum == 0;
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct MCFGEntry
+ {
+ public ulong BaseAddress;
+ public ushort Segment;
+ public byte StartBus;
+ public byte EndBus;
+ public uint Reserved;
}
- ///
- /// Start the ACPI.
- ///
- /// Initialize the ACPI. (default = true)
- /// Enable the ACPI. (default = true)
- public static void Start(bool initialize = true, bool enable = true)
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct APIC_LOCAL_APIC
{
- if (initialize)
- {
- Init();
- }
+ public APIC_HEADER Header;
+ public byte AcpiProcessorId;
+ public byte ApicId;
+ public uint Flags;
+ }
- if (enable)
- {
- Enable();
- }
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct APIC_IO_APIC
+ {
+ public APIC_HEADER Header;
+ public byte IOApicId;
+ public byte Reserved;
+ public uint IOApicAddress;
+ public uint GlobalSystemInterruptBase;
}
- ///
- /// Shutdown the ACPI.
- ///
- /// Thrown on IO error.
- public static void Shutdown()
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct APIC_INTERRUPT_OVERRIDE
{
- Console.Clear();
- if (PM1a_CNT == null)
- {
- Init();
- }
+ public APIC_HEADER Header;
+ public byte Bus;
+ public byte Source;
+ public uint Interrupt;
+ public ushort Flags;
+ }
- IOPort.Write16(pm1aIO, (ushort)(SLP_TYPa | SLP_EN));
+ [StructLayout(LayoutKind.Sequential,Pack = 1)]
+ public struct ACPI_HPET
+ {
+ public ACPI_HEADER Header;
+ public byte HardwareRevisionID;
+ public byte Attribute;
+ public ushort PCIVendorID;
+ public ACPI_HPET_ADDRESS_STRUCTURE Addresses;
+ public byte HPETNumber;
+ public ushort MinimumTick;
+ public byte PageProtection;
+ }
- if (PM1b_CNT != null)
- {
- IOPort.Write16(pm1bIO, (ushort)(SLP_TYPb | SLP_EN));
- }
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ACPI_HPET_ADDRESS_STRUCTURE
+ {
+ public byte AddressSpaceID;
+ public byte RegisterBitWidth;
+ public byte RegisterBitOffset;
+ public byte Reserved;
+ public ulong Address;
+ }
- CPU.Halt();
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ACPI_FADT
+ {
+ public ACPI_HEADER Header;
+
+ public uint FirmwareCtrl;
+ public uint Dsdt;
+
+ public byte Reserved;
+
+ public byte PreferredPowerManagementProfile;
+ public ushort SCI_Interrupt;
+ public uint SMI_CommandPort;
+ public byte AcpiEnable;
+ public byte AcpiDisable;
+ public byte S4BIOS_REQ;
+ public byte PSTATE_Control;
+ public uint PM1aEventBlock;
+ public uint PM1bEventBlock;
+ public uint PM1aControlBlock;
+ public uint PM1bControlBlock;
+ public uint PM2ControlBlock;
+ public uint PMTimerBlock;
+ public uint GPE0Block;
+ public uint GPE1Block;
+ public byte PM1EventLength;
+ public byte PM1ControlLength;
+ public byte PM2ControlLength;
+ public byte PMTimerLength;
+ public byte GPE0Length;
+ public byte GPE1Length;
+ public byte GPE1Base;
+ public byte CStateControl;
+ public ushort WorstC2Latency;
+ public ushort WorstC3Latency;
+ public ushort FlushSize;
+ public ushort FlushStride;
+ public byte DutyOffset;
+ public byte DutyWidth;
+ public byte DayAlarm;
+ public byte MonthAlarm;
+ public byte Century;
+
+ public ushort BootArchitectureFlags;
+
+ public byte Reserved2;
+ public uint Flags;
}
- ///
- /// Reboot ACPI.
- /// Not implemented.
- ///
- /// Thrown always.
- public static void Reboot()
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ACPI_MADT
{
- throw new NotImplementedException("ACPI Reset not implemented yet."); //TODO
+ public ACPI_HEADER Header;
+ public uint LocalAPICAddress;
+ public uint Flags;
}
- ///
- /// Initialize the ACPI.
- ///
- /// true on success, false on failure.
- private static bool Init()
+ private static unsafe ACPI_RSDP* GetRSDP()
{
- byte* ptr = (byte*)RSDPAddress();
- int addr = 0;
+ byte* p = (byte*)0xE0000;
+ byte* end = (byte*)0xFFFFF;
- for (int i = 19; i >= 16; i--)
+ while (p < end)
{
- addr += *(ptr + i);
- addr = i == 16 ? addr : addr << 8;
+ ulong signature = *(ulong*)p;
+
+ if (signature == 0x2052545020445352) // 'RSD PTR '
+ {
+ return (ACPI_RSDP*)p;
+ }
+
+ p += 16;
}
- ptr = (byte*)addr;
- ptr += 4; addr = 0;
+ return null;
+ }
+
+ public static void Shutdown()
+ {
+ IOPort.Write16((ushort)FADT->PM1aControlBlock, (ushort)(SLP_TYPa | SLP_EN));
+ IOPort.Write16((ushort)FADT->PM1bControlBlock, (ushort)(SLP_TYPb | SLP_EN));
+ CPU.Halt();
+ }
+
+ public static List LocalAPIC_CPUIDs;
- for (int i = 3; i >= 0; i--)
+ public static void Initialize()
+ {
+ FADT = null;
+ MADT = null;
+ IO_APIC = null;
+ HPET = null;
+ MCFG = null;
+
+ LocalAPIC_CPUIDs = new List();
+ ACPI_RSDP* rsdp = GetRSDP();
+ //MMIO.Map(rsdp->RsdtAddress, ushort.MaxValue);
+ ACPI_HEADER* hdr = (ACPI_HEADER*)rsdp->RsdtAddress;
+ ACPI_HEADER* rsdt = (ACPI_HEADER*)rsdp->RsdtAddress;
+
+ if (rsdt != null && *(uint*)rsdt == 0x54445352) //RSDT
{
- addr += *(ptr + i);
- addr = i == 0 ? addr : addr << 8;
+ uint* p = (uint*)(rsdt + 1);
+ uint* end = (uint*)((byte*)rsdt + rsdt->Length);
+
+ while (p < end)
+ {
+ uint address = *p++;
+ ParseDT((ACPI_HEADER*)address);
+ }
}
- int length = addr;
- ptr -= 4;
+ Console.WriteLine("[ACPI] ACPI Initialized");
+ }
- if (ptr != null && acpiCheckHeader(ptr, "RSDT") == 0)
+ private static void ParseDT(ACPI_HEADER* hdr)
+ {
+ if (*(uint*)hdr->Signature == 0x50434146)
{
- addr = 0;
- int entrys = length;
- entrys = (entrys - 36) / 4;
- ptr += 36;
- byte* yeuse;
+ FADT = (ACPI_FADT*)hdr;
- while (0 < entrys--)
+ if (*(uint*)FADT->Dsdt == 0x54445344) //DSDT
{
- for (int i = 3; i >= 0; i--)
+ byte* S5Addr = (byte*)FADT->Dsdt + sizeof(ACPI_HEADER);
+ int dsdtLength = *((int*)FADT->Dsdt + 1) - sizeof(ACPI_HEADER);
+
+ while (0 < dsdtLength--)
{
- addr += *(ptr + i);
- addr = i == 0 ? addr : addr << 8;
+ if (*(uint*)S5Addr == 0x5f35535f) //_S5_
+ break;
+ S5Addr++;
}
- yeuse = (byte*)addr;
- Facp = yeuse;
-
- if (acpiCheckHeader((byte*)facpget(0), "DSDT") == 0)
+ if (dsdtLength > 0)
{
- byte* S5Addr = (byte*)facpget(0) + 36;
- int dsdtLength = *(facpget(0) + 1) - 36;
-
- while (0 < dsdtLength--)
+ if ((*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) && *(S5Addr + 4) == 0x12)
{
- if (Compare("_S5_", S5Addr) == 0)
- {
- break;
- }
+ S5Addr += 5;
+ S5Addr += ((*S5Addr & 0xC0) >> 6) + 2;
+ if (*S5Addr == 0x0A)
+ S5Addr++;
+ SLP_TYPa = (short)(*(S5Addr) << 10);
S5Addr++;
- }
-
- if (dsdtLength > 0)
- {
- if ((*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) && *(S5Addr + 4) == 0x12)
- {
- S5Addr += 5;
- S5Addr += ((*S5Addr & 0xC0) >> 6) + 2;
- if (*S5Addr == 0x0A)
- {
- S5Addr++;
- }
- SLP_TYPa = (short)(*S5Addr << 10);
+ if (*S5Addr == 0x0A)
S5Addr++;
- if (*S5Addr == 0x0A)
- {
- S5Addr++;
- }
- SLP_TYPb = (short)(*S5Addr << 10);
- SMI_CMD = facpget(1);
- ACPI_ENABLE = facpbget(0);
- ACPI_DISABLE = facpbget(1);
- PM1a_CNT = facpget(2);
- PM1b_CNT = facpget(3);
- PM1_CNT_LEN = facpbget(3);
- SLP_EN = 1 << 13;
-
- smiIO = (ushort)SMI_CMD;
- pm1aIO = (ushort)PM1a_CNT;
- pm1bIO = (ushort)PM1b_CNT;
-
- return true;
- }
+ SLP_TYPb = (short)(*(S5Addr) << 10);
+ SLP_EN = 1 << 13;
+
+ return;
}
}
- ptr += 4;
}
}
-
- return false;
- }
-
- ///
- /// Enable ACPI.
- ///
- public static void Enable()
- {
- smiIO = ACPI_ENABLE;
- }
-
- ///
- /// Disable ACPI.
- ///
- public static void Disable()
- {
- smiIO = ACPI_DISABLE;
- }
-
- ///
- /// Get the RSDP address.
- ///
- /// uint value.
- private static unsafe uint RSDPAddress()
- {
- for (uint addr = 0xE0000; addr < 0x100000; addr += 4)
+ else if (*(uint*)hdr->Signature == 0x43495041)
{
- if (Compare("RSD PTR ", (byte*)addr) == 0)
+ MADT = (ACPI_MADT*)hdr;
+
+ byte* p = (byte*)(MADT + 1);
+ byte* end = (byte*)MADT + MADT->Header.Length;
+ while (p < end)
{
- if (Check_RSD(addr))
+ APIC_HEADER* header = (APIC_HEADER*)p;
+ APIC_TYPE type = header->Type;
+ byte length = header->Length;
+
+ if (type == APIC_TYPE.LocalAPIC)
{
- return addr;
+ APIC_LOCAL_APIC* pic = (APIC_LOCAL_APIC*)p;
+ if (((pic->Flags & 1) ^ ((pic->Flags >> 1) & 1)) == 1)
+ {
+ LocalAPIC_CPUIDs.Add(pic->ApicId);
+ }
}
+ else if (type == APIC_TYPE.IOAPIC)
+ {
+ APIC_IO_APIC* ioapic = (APIC_IO_APIC*)p;
+ if (IO_APIC == null)
+ {
+ IO_APIC = ioapic;
+ }
+ }
+ else if (type == APIC_TYPE.InterruptOverride)
+ {
+ APIC_INTERRUPT_OVERRIDE* ovr = (APIC_INTERRUPT_OVERRIDE*)p;
+ }
+
+ p += length;
}
}
-
- uint ebda_address = *(uint*)0x040E;
- ebda_address = (ebda_address * 0x10) & 0x000fffff;
-
- for (uint addr = ebda_address; addr < ebda_address + 1024; addr += 4)
+ else if (*(uint*)hdr->Signature == 0x54455048)
{
- if (Compare("RSD PTR ", (byte*)addr) == 0)
- {
- return addr;
- }
+ HPET = (ACPI_HPET*)hdr;
+ }
+ else if (*(uint*)hdr->Signature == 0x4746434D)
+ {
+ MCFG = (MCFGHeader*)hdr;
}
-
- return 0;
}
- ///
- /// Check RSDT table
- ///
- /// A pointer to the RSDT
- /// RSDT table address
- private static uint* acpiCheckRSDPtr(uint* ptr)
+ public static uint RemapIRQ(uint irq)
{
- string sig = "RSD PTR ";
- var rsdp = (RSDPtr*)ptr;
+ byte* p = (byte*)(MADT + 1);
+ byte* end = (byte*)MADT + MADT->Header.Length;
- byte* bptr;
- byte check = 0;
- int i;
-
- if (Compare(sig, (byte*)rsdp) == 0)
+ while (p < end)
{
- bptr = (byte*)ptr;
-
- for (i = 0; i < 20; i++)
- {
- check += *bptr;
- bptr++;
- }
+ APIC_HEADER* header = (APIC_HEADER*)p;
+ APIC_TYPE type = header->Type;
+ byte length = header->Length;
- if (check == 0)
+ if (type == APIC_TYPE.InterruptOverride)
{
- Compare("RSDT", (byte*)rsdp->RsdtAddress);
+ APIC_INTERRUPT_OVERRIDE* ovr = (APIC_INTERRUPT_OVERRIDE*)p;
- if (rsdp->RsdtAddress != 0)
+ if (ovr->Source == irq)
{
- return (uint*)rsdp->RsdtAddress;
+ return ovr->Interrupt;
}
}
- }
-
- return null;
- }
- ///
- /// Get data from the FACP table.
- ///
- /// Index number of the data to get.
- ///
- /// - 0 - ACPI ENABLE
- /// - 1 - ACPI DISABLE
- /// - 2 - PM1 CNT LEN
- /// - other - 0
- ///
- ///
- /// byte value.
- private static byte facpbget(int number)
- {
- switch (number)
- {
- case 0:
- return *(Facp + 52);
- case 1:
- return *(Facp + 53);
- case 2:
- return *(Facp + 89);
- default:
- return 0;
+ p += length;
}
- }
- ///
- /// Get pointer to the data on the FACP.
- ///
- /// Index number of the data to get.
- ///
- /// - 0 - DSDT
- /// - 1 - SMI CMD
- /// - 2 - PM1a
- /// - 3 - PM1b
- /// - other - null
- ///
- ///
- /// int pointer.
- private static int* facpget(int number)
- {
- switch (number)
- {
- case 0:
- return (int*)*(int*)(Facp + 40);
- case 1:
- return (int*)*(int*)(Facp + 48);
- case 2:
- return (int*)*(int*)(Facp + 64);
- case 3:
- return (int*)*(int*)(Facp + 68);
- default:
- return null;
- }
+ return irq;
}
}
}
\ No newline at end of file
diff --git a/source/Cosmos.Core/ManagedMemoryBlock.cs b/source/Cosmos.Core/ManagedMemoryBlock.cs
index 4a6be7d7cf..16918da90e 100644
--- a/source/Cosmos.Core/ManagedMemoryBlock.cs
+++ b/source/Cosmos.Core/ManagedMemoryBlock.cs
@@ -154,6 +154,20 @@ public unsafe void Copy(int aStart, int[] aData, int aIndex, int aCount)
}
}
+ public unsafe void Get(int aStart, int[] aData, int aIndex, int aCount)
+ {
+ // TODO throw exception if aStart and aCount are not in bound. I've tried to do this but Bochs dies :-(
+ int* xSrc;
+ fixed (byte* aArrayPtr = memory)
+ {
+ xSrc = (int*)aArrayPtr + aStart;
+ }
+ fixed (int* aDataPtr = aData)
+ {
+ MemoryOperations.Copy(aDataPtr + aIndex, xSrc, aCount);
+ }
+ }
+
///
/// Copy MemoryBlock into ManagedMemoryBlock
///
diff --git a/source/Cosmos.Core/MemoryBlock.cs b/source/Cosmos.Core/MemoryBlock.cs
index bed3816176..beba53dcfb 100644
--- a/source/Cosmos.Core/MemoryBlock.cs
+++ b/source/Cosmos.Core/MemoryBlock.cs
@@ -270,6 +270,38 @@ public unsafe void Copy(ManagedMemoryBlock block)
MemoryOperations.Copy(xDest, aDataPtr, (int)block.Size);
}
+ ///
+ /// Copies a specified number of integers from the memory block into an integer array.
+ ///
+ /// The byte offset in the memory block from where the copy starts.
+ /// The integer array where the data will be copied to.
+ /// The starting index in the destination integer array.
+ /// The number of integers to copy.
+ public unsafe void Get(int aByteOffset, int[] aData, int aIndex, int aCount)
+ {
+ int* xSource = (int*)(Base + aByteOffset);
+ fixed (int* aDataPtr = aData)
+ {
+ MemoryOperations.Copy(aDataPtr + aIndex, xSource, aCount);
+ }
+ }
+
+ ///
+ /// Copies a specified number of bytes from the memory block into an array.
+ ///
+ /// The byte offset in the memory block from where the copy starts.
+ /// The array where the data will be copied to.
+ /// The starting index in the destination array.
+ /// The number of bytes to copy.
+ public unsafe void Get(int aByteOffset, byte[] aData, int aIndex, int aCount)
+ {
+ byte* xSource = (byte*)(Base + aByteOffset);
+ fixed (byte* aDataPtr = aData)
+ {
+ MemoryOperations.Copy(aDataPtr + aIndex, xSource, aCount);
+ }
+ }
+
///
/// Move bytes array down the memory block.
///
diff --git a/source/Cosmos.Core/PCIE/PCIDevice.cs b/source/Cosmos.Core/PCIE/PCIDevice.cs
new file mode 100644
index 0000000000..f7d471241f
--- /dev/null
+++ b/source/Cosmos.Core/PCIE/PCIDevice.cs
@@ -0,0 +1,200 @@
+using System.Collections.Generic;
+using System;
+using Cosmos.Core;
+
+namespace Cosmos.Core.PCIE
+{
+ public class PCIDevice
+ {
+ public ushort Bus;
+ public ushort Slot;
+ public ushort Function;
+ public ushort VendorID;
+
+ public ushort DeviceID;
+
+ public byte ClassID;
+ public byte SubClassID;
+ public byte ProgIF;
+ public byte IRQ;
+
+ public uint Bar0;
+ public uint Bar1;
+ public uint Bar2;
+ public uint Bar3;
+ public uint Bar4;
+ public uint Bar5;
+
+ //PCI Express
+ public ushort Segment;
+ public bool IsPCIEDevice;
+
+ public void WriteRegister(ushort Register, ushort Value)
+ {
+ PCI.WriteRegister16(Bus, Slot, Function, (byte)Register, (ushort)(ReadRegister(Register) | Value));
+ }
+
+ public ushort ReadRegister(ushort Register)
+ {
+ return PCI.ReadRegister16(Bus, Slot, Function, (byte)Register);
+ }
+ }
+
+ public static unsafe class PCI
+ {
+ public static List Devices;
+
+ public static PCIDevice GetDevice(ushort VendorID, ushort DeviceID)
+ {
+ for (int i = 0; i < Devices.Count; i++)
+ {
+ if (
+ Devices[i] != null &&
+ Devices[i].VendorID == VendorID &&
+ Devices[i].DeviceID == DeviceID
+ )
+ {
+ return Devices[i];
+ }
+ }
+ return null;
+ }
+
+ public static PCIDevice GetDevice(byte ClassID, byte SubClassID, byte ProgIF)
+ {
+ for (int i = 0; i < Devices.Count; i++)
+ {
+ if (
+ Devices[i] != null &&
+ Devices[i].ClassID == ClassID &&
+ Devices[i].SubClassID == SubClassID &&
+ Devices[i].ProgIF == ProgIF
+ )
+ {
+ return Devices[i];
+ }
+ }
+ return null;
+ }
+
+ public static void Initialise()
+ {
+ Devices = new List();
+ if ((GetHeaderType(0x0, 0x0, 0x0) & 0x80) == 0)
+ {
+ CheckBus(0);
+ }
+ else
+ {
+ for (ushort fn = 0; fn < 8; fn++)
+ {
+ if (GetVendorID(0x0, 0x0, fn) != 0xFFFF)
+ break;
+
+ CheckBus(fn);
+ }
+ }
+
+ PCIExpress.Initialize();
+
+ Console.Write("[PCI] PCI Initialized. ");
+ Console.Write(((ulong)Devices.Count).ToString());
+ Console.WriteLine(" Devices");
+ }
+
+ public static void CheckBus(ushort Bus)
+ {
+ for (ushort slot = 0; slot < 32; slot++)
+ {
+ ushort vendorID = GetVendorID(Bus, slot, 0);
+ if (vendorID == 0xFFFF)
+ {
+ continue;
+ }
+
+ PCIDevice device = new PCIDevice();
+ device.Bus = Bus;
+ device.Slot = slot;
+ device.Function = 0;
+ device.VendorID = vendorID;
+ device.Segment = 0;
+ device.IsPCIEDevice = false;
+
+ device.Bar0 = ReadRegister32(device.Bus, device.Slot, device.Function, 0x10);
+ device.Bar1 = ReadRegister32(device.Bus, device.Slot, device.Function, 0x14);
+ device.Bar2 = ReadRegister32(device.Bus, device.Slot, device.Function, 0x18);
+ device.Bar3 = ReadRegister32(device.Bus, device.Slot, device.Function, 0x1C);
+ device.Bar4 = ReadRegister32(device.Bus, device.Slot, device.Function, 0x20);
+ device.Bar5 = ReadRegister32(device.Bus, device.Slot, device.Function, 0x24);
+
+ device.ClassID = ReadRegister8(device.Bus, device.Slot, device.Function, 11);
+ device.SubClassID = ReadRegister8(device.Bus, device.Slot, device.Function, 10);
+ device.ProgIF = ReadRegister8(device.Bus, device.Slot, device.Function, 9);
+ device.IRQ = (byte)(0x20 + ReadRegister8(device.Bus, device.Slot, device.Function, 60));
+
+ device.DeviceID = ReadRegister16(device.Bus, device.Slot, device.Function, 2);
+
+ Devices.Add(device);
+
+ if (device.ClassID == 0x06 && device.SubClassID == 0x04)
+ {
+ CheckBus(ReadRegister8(device.Bus, device.Slot, device.Function, 25));
+ }
+ }
+ }
+
+ public static void WriteRegister32(ushort Bus, ushort Slot, ushort Function, byte aRegister, uint Value)
+ {
+ uint xAddr = GetAddressBase(Bus, Slot, Function) | ((uint)(aRegister & 0xFC));
+ IOPort.Write32(0xCF8, xAddr);
+ IOPort.Write32(0xCFC, Value);
+ }
+
+ public static uint ReadRegister32(ushort Bus, ushort Slot, ushort Function, byte aRegister)
+ {
+ uint xAddr = PCI.GetAddressBase(Bus, Slot, Function) | ((uint)(aRegister & 0xFC));
+ IOPort.Write32(0xCF8, xAddr);
+ return IOPort.Read32(0xCFC);
+ }
+
+ public static ushort ReadRegister16(ushort Bus, ushort Slot, ushort Function, byte aRegister)
+ {
+ uint xAddr = PCI.GetAddressBase(Bus, Slot, Function) | ((uint)(aRegister & 0xFC));
+ IOPort.Write32(0xCF8, xAddr);
+ return (ushort)(IOPort.Read32(0xCFC) >> ((aRegister % 4) * 8) & 0xFFFF);
+ }
+
+ public static byte ReadRegister8(ushort Bus, ushort Slot, ushort Function, byte aRegister)
+ {
+ uint xAddr = PCI.GetAddressBase(Bus, Slot, Function) | ((uint)(aRegister & 0xFC));
+ IOPort.Write32(0xCF8, xAddr);
+ return ((byte)(IOPort.Read32(0xCFC) >> ((aRegister % 4) * 8) & 0xFF));
+ }
+
+ public static void WriteRegister16(ushort Bus, ushort Slot, ushort Function, byte aRegister, ushort Value)
+ {
+ uint xAddr = GetAddressBase(Bus, Slot, Function) | ((uint)(aRegister & 0xFC));
+ IOPort.Write32(0xCF8, xAddr);
+ IOPort.Write16(0xCFC, Value);
+ }
+
+ public static ushort GetVendorID(ushort Bus, ushort Slot, ushort Function)
+ {
+ uint xAddr = GetAddressBase(Bus, Slot, Function) | 0x0 & 0xFC;
+ IOPort.Write32(0xCF8, xAddr);
+ return (ushort)(IOPort.Read32(0xCFC) >> ((0x0 % 4) * 8) & 0xFFFF);
+ }
+
+ public static ushort GetHeaderType(ushort Bus, ushort Slot, ushort Function)
+ {
+ uint xAddr = GetAddressBase(Bus, Slot, Function) | 0xE & 0xFC;
+ IOPort.Write32(0xCF8, xAddr);
+ return (byte)(IOPort.Read32(0xCFC) >> ((0xE % 4) * 8) & 0xFF);
+ }
+
+ public static uint GetAddressBase(ushort Bus, uint Slot, uint Function)
+ {
+ return (uint)(0x80000000 | (Bus << 16) | ((Slot & 0x1F) << 11) | ((Function & 0x07) << 8));
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/Cosmos.Core/PCIE/PCIExpress.cs b/source/Cosmos.Core/PCIE/PCIExpress.cs
new file mode 100644
index 0000000000..d658bbd608
--- /dev/null
+++ b/source/Cosmos.Core/PCIE/PCIExpress.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Runtime.InteropServices;
+using PCIDevice = Cosmos.Core.PCIE.PCIDevice;
+
+namespace Cosmos.Core.PCIE
+{
+ public static unsafe class PCIExpress
+ {
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct Header
+ {
+ public ushort VendorID;
+ public ushort DeviceID;
+ public ushort Command;
+ public ushort Status;
+ public byte RevisionID;
+ public byte ProgIF;
+ public byte SubClass;
+ public byte ClassID;
+ public byte CachelineSize;
+ public byte LatencyTimer;
+ public byte HeaderType;
+ public byte BIST;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct DeviceHeader
+ {
+ public Header Header;
+ public uint Bar0;
+ public uint Bar1;
+ public uint Bar2;
+ public uint Bar3;
+ public uint Bar4;
+ public uint Bar5;
+ public uint CardbusCisPtr;
+ public ushort SubSystemVendorID;
+ public ushort SubSystemID;
+ public uint ExpRomBaseAddr;
+ public byte CapabPtr;
+ public byte Reserved0;
+ public ushort Reserved1;
+ public uint Reserved2;
+ public byte InterruptLine;
+ public byte InterruptPin;
+ public byte MinGrid;
+ public byte MaxLatency;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct BridgeHeader
+ {
+ public Header Header;
+ public uint Bar0;
+ public uint Bar1;
+ public byte PrimaryBus;
+ public byte SecondBus;
+ public byte SubBus;
+ public byte SecLatTimer;
+ public byte IOBase;
+ public byte IOLimit;
+ public ushort SecStatus;
+ public ushort MemoryBase;
+ public ushort MemLimit;
+ public ushort PrefMembase;
+ public ushort PrefMemlimit;
+ public uint PrefBaseUp;
+ public uint PrefLimitUp;
+ public ushort IOBaseUp;
+ public ushort IOLimitUp;
+ public byte CapabPtr;
+ public byte Reserved0;
+ public ushort Reserved1;
+ public uint ExpRomBase;
+ public byte InterruptLine;
+ public byte InterruptPin;
+ public ushort BridgeCtrl;
+ };
+
+ public static void Initialize()
+ {
+ if (ACPI.MCFG == null) return;
+
+ var numEntries = (ACPI.MCFG->Header.Length - sizeof(ACPI.MCFGHeader) + sizeof(ACPI.MCFGEntry)) / sizeof(ACPI.MCFGEntry);
+ Console.WriteLine(numEntries + " PCIE entries");
+ for (int i = 0; i < numEntries; i++)
+ {
+ ACPI.MCFGEntry* Entries = &ACPI.MCFG->Entry0;
+ for (var bus = Entries->StartBus; bus < Entries->EndBus; bus++)
+ {
+ PCIExpress.CheckBus(Entries->BaseAddress, bus, Entries->Segment);
+ }
+ }
+
+ Console.WriteLine(numEntries + " PCIE entries");
+
+ }
+
+ public static void CheckBus(ulong BaseAddress, byte Bus, ushort Segment)
+ {
+ ulong BusAddress = BaseAddress + (ulong)(Bus << 20);
+
+ Header* Header0 = (Header*)BusAddress;
+ if (Header0->DeviceID == 0 || Header0->DeviceID == 0xFFFF)return;
+
+ for (byte Slot = 0; Slot < 32; Slot++)
+ {
+ ulong DeviceAddress = BusAddress + (ulong)(Slot << 15);
+
+ Header* Header1 = (Header*)DeviceAddress;
+ if (Header1->DeviceID == 0 || Header1->DeviceID == 0xFFFF) return;
+
+ for (byte Func = 0; Func < 8; Func++)
+ {
+ ulong FuncAddress = DeviceAddress + (ulong)(Func << 12);
+
+ DeviceHeader* Dev = (DeviceHeader*)FuncAddress;
+ if (Dev->Header.DeviceID == 0 || Dev->Header.DeviceID == 0xFFFF) return;
+
+ PCIDevice device = new PCIDevice();
+ device.Segment = Segment;
+ device.Bus = Bus;
+ device.Slot = Slot;
+ device.Function = Func;
+ device.VendorID = Dev->Header.VendorID;
+ device.IsPCIEDevice = true;
+
+ device.ClassID = Dev->Header.ClassID;
+ device.SubClassID = Dev->Header.SubClass;
+ device.ProgIF = Dev->Header.ProgIF;
+
+ device.DeviceID = Dev->Header.DeviceID;
+
+ if (device.ClassID == 0x06 && device.SubClassID == 0x04)
+ {
+ BridgeHeader* Bri = (BridgeHeader*)Dev;
+
+ device.IRQ = (byte)(Bri->InterruptLine + 0x20);
+ device.Bar0 = Bri->Bar0;
+ device.Bar1 = Bri->Bar1;
+ device.Bar2 = 0;
+ device.Bar3 = 0;
+ device.Bar4 = 0;
+ device.Bar5 = 0;
+
+ PCI.CheckBus(Bri->SecondBus);
+ }
+ else
+ {
+ device.IRQ = (byte)(Dev->InterruptLine + 0x20);
+ device.Bar0 = Dev->Bar0;
+ device.Bar1 = Dev->Bar1;
+ device.Bar2 = Dev->Bar2;
+ device.Bar3 = Dev->Bar3;
+ device.Bar4 = Dev->Bar4;
+ device.Bar5 = Dev->Bar5;
+ }
+
+ Console.WriteLine($"[PCI Express {device.Bus}:{device.Slot}:{device.Function}] {device.VendorID} {device.ClassID}");
+
+ PCI.Devices.Add(device);
+ }
+ }
+ }
+ }
+}
diff --git a/source/Cosmos.Core/packages.lock.json b/source/Cosmos.Core/packages.lock.json
index b1d944ce02..f158b4a5a8 100644
--- a/source/Cosmos.Core/packages.lock.json
+++ b/source/Cosmos.Core/packages.lock.json
@@ -10,4 +10,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs b/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs
index 5182cd263a..e88bddd17a 100644
--- a/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs
+++ b/source/Cosmos.HAL2/Drivers/Video/VBEDriver.cs
@@ -297,6 +297,18 @@ public void CopyVRAM(int aStart, int[] aData, int aIndex, int aCount)
lastbuffer.Copy(aStart, aData, aIndex, aCount);
}
+ ///
+ /// Get VRAM data.
+ ///
+ /// Start position in VRAM.
+ /// Array to copy data into.
+ /// Starting index in the array to begin copying data.
+ /// Number of elements to copy.
+ public void GetVRAM(int aStart, int[] aData, int aIndex, int aCount)
+ {
+ lastbuffer.Get(aStart, aData, aIndex, aCount);
+ }
+
///
/// Copy VRAM.
///
diff --git a/source/Cosmos.HAL2/Global.cs b/source/Cosmos.HAL2/Global.cs
index c088298b5b..180f6da759 100644
--- a/source/Cosmos.HAL2/Global.cs
+++ b/source/Cosmos.HAL2/Global.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-
using Cosmos.Core;
using Cosmos.Debug.Kernel;
using Cosmos.HAL.BlockDevice;
@@ -52,7 +51,7 @@ static public void Init(TextScreenBase textScreen, bool InitScrollWheel, bool In
Console.WriteLine("Starting ACPI");
debugger.Send("ACPI Init");
- ACPI.Start();
+ ACPI.Initialize();
// http://wiki.osdev.org/%228042%22_PS/2_Controller#Initialising_the_PS.2F2_Controller
// TODO: USB should be initialized before the PS/2 controller
diff --git a/source/Cosmos.HAL2/Power.cs b/source/Cosmos.HAL2/Power.cs
index e054259023..31bccbd1a3 100644
--- a/source/Cosmos.HAL2/Power.cs
+++ b/source/Cosmos.HAL2/Power.cs
@@ -20,11 +20,18 @@ public static void CPUReboot()
///
/// Reboot the system using ACPI. Currently not implemented.
///
- /// Thrown always.
- [Obsolete("This method is not yet implemented.", error: true)]
+ //// Thrown always.
+ //[Obsolete("This method is not yet implemented.", error: true)] -- the method should work now no need to throw an exception
public static void ACPIReboot()
{
- ACPI.Reboot();
+ try
+ {
+ CPU.Reboot();
+ }
+ catch
+ {
+ ACPI.Shutdown();
+ }
}
///
diff --git a/source/Cosmos.HAL2/packages.lock.json b/source/Cosmos.HAL2/packages.lock.json
index a523aa23aa..0da9c41a62 100644
--- a/source/Cosmos.HAL2/packages.lock.json
+++ b/source/Cosmos.HAL2/packages.lock.json
@@ -23,4 +23,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/source/Cosmos.System2/Graphics/Canvas.cs b/source/Cosmos.System2/Graphics/Canvas.cs
index a6ac312140..795edfa2e5 100644
--- a/source/Cosmos.System2/Graphics/Canvas.cs
+++ b/source/Cosmos.System2/Graphics/Canvas.cs
@@ -100,6 +100,22 @@ public virtual void Clear(Color color)
/// The Y coordinate.
public abstract void DrawPoint(Color color, int x, int y);
+ ///
+ /// Sets the pixel at the given coordinates to the specified . without ToArgb()
+ ///
+ /// The color to draw with (raw argb).
+ /// The X coordinate.
+ /// The Y coordinate.
+ public abstract void DrawRawPoint(uint color, int x, int y);
+
+ ///
+ /// Sets the pixel at the given coordinates to the specified . without ToArgb()
+ ///
+ /// The color to draw with (raw argb).
+ /// The X coordinate.
+ /// The Y coordinate.
+ public abstract void DrawRawPoint(int color, int x, int y);
+
///
/// The name of the Canvas implementation.
///
@@ -117,6 +133,13 @@ public virtual void Clear(Color color)
/// The X coordinate.
/// The Y coordinate.
public abstract Color GetPointColor(int x, int y);
+
+ ///
+ /// Gets the color of the pixel at the given coordinates in ARGB.
+ ///
+ /// The X coordinate.
+ /// The Y coordinate.
+ public abstract int GetRawPointColor(int x, int y);
///
/// Gets the index of the pixel at the given coordinates.
///
@@ -147,6 +170,47 @@ public virtual void DrawArray(Color[] colors, int x, int y, int width, int heigh
}
}
+ ///
+ /// Draws an array of pixels to the canvas, starting at the given coordinates,
+ /// using the given width.
+ ///
+ /// The pixels to draw.
+ /// The X coordinate.
+ /// The Y coordinate.
+ /// The width of the drawn bitmap.
+ /// The height of the drawn bitmap.
+ public virtual void DrawArray(int[] colors, int x, int y, int width, int height)
+ {
+ for (int X = 0; X < width; X++)
+ {
+ for (int Y = 0; Y < height; Y++)
+ {
+ DrawRawPoint(colors[Y * width + X], x + X, y + Y);
+ }
+ }
+ }
+
+ ///
+ /// Draws an array of pixels to the canvas, starting at the given coordinates,
+ /// using the given width.
+ ///
+ /// The pixels to draw.
+ /// The X coordinate.
+ /// The Y coordinate.
+ /// The width of the drawn bitmap.
+ /// The height of the drawn bitmap.
+ /// int[] colors tarting position
+ public virtual void DrawArray(int[] colors, int x, int y, int width, int height, int startIndex)
+ {
+ for (int X = 0; X < width; X++)
+ {
+ for (int Y = 0; Y < height; Y++)
+ {
+ DrawRawPoint(colors[Y * width + X + startIndex], x + X, y + Y);
+ }
+ }
+ }
+
///
/// Draws a horizontal line.
///
@@ -485,40 +549,17 @@ public virtual void DrawSquare(Color color, int x, int y, int size)
/// The height of the rectangle.
public virtual void DrawRectangle(Color color, int x, int y, int width, int height)
{
- /*
- * we must draw four lines connecting any vertex of our rectangle to do this we first obtain the position of these
- * vertex (we call these vertexes A, B, C, D as for geometric convention)
- */
-
- /* The check of the validity of x and y are done in DrawLine() */
-
- /* The vertex A is where x,y are */
- int xa = x;
- int ya = y;
-
- /* The vertex B has the same y coordinate of A but x is moved of width pixels */
- int xb = x + width;
- int yb = y;
-
- /* The vertex C has the same x coordiate of A but this time is y that is moved of height pixels */
- int xc = x;
- int yc = y + height;
+ // Draw top edge from (x, y) to (x + width, y)
+ DrawLine(color, x, y, x + width, y);
- /* The Vertex D has x moved of width pixels and y moved of height pixels */
- int xd = x + width;
- int yd = y + height;
+ // Draw left edge from (x, y) to (x, y + height)
+ DrawLine(color, x, y, x, y + height);
- /* Draw a line betwen A and B */
- DrawLine(color, xa, ya, xb, yb);
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ DrawLine(color, x, y + height, x + width, y + height);
- /* Draw a line between A and C */
- DrawLine(color, xa, ya, xc, yc);
-
- /* Draw a line between B and D */
- DrawLine(color, xb, yb, xd, yd);
-
- /* Draw a line between C and D */
- DrawLine(color, xc, yc, xd, yd);
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ DrawLine(color, x + width, y, x + width, y + height);
}
///
@@ -529,6 +570,7 @@ public virtual void DrawRectangle(Color color, int x, int y, int width, int heig
/// The starting point Y coordinate.
/// The width of the rectangle.
/// The height of the rectangle.
+ /// Prevents drawing outside the bounds of the canvas.
public virtual void DrawFilledRectangle(Color color, int xStart, int yStart, int width, int height, bool preventOffBoundPixels = true)
{
if (height == -1)
@@ -569,6 +611,7 @@ public virtual void DrawTriangle(Color color, int v1x, int v1y, int v2x, int v2y
/// The image to draw.
/// The origin X coordinate.
/// The origin Y coordinate.
+ /// Prevents drawing outside the bounds of the canvas.
public virtual void DrawImage(Image image, int x, int y, bool preventOffBoundPixels = true)
{
Color color;
@@ -598,6 +641,48 @@ public virtual void DrawImage(Image image, int x, int y, bool preventOffBoundPix
}
}
+ ///
+ /// Draws the given image at the specified coordinates, cropped to maxWidth and maxHeight
+ ///
+ /// The image to draw.
+ /// The origin X coordinate.
+ /// The origin Y coordinate.
+ /// Max image width to display
+ /// Max image height to display
+ public virtual void CroppedDrawImage(Image image, int x, int y, int maxWidth, int maxHeight, bool preventOffBoundPixels = true)
+ {
+
+ }
+
+ ///
+ /// Retrieves a specified region of the canvas as a bitmap.
+ ///
+ /// The x-coordinate of the top-left corner of the region.
+ /// The y-coordinate of the top-left corner of the region.
+ /// The width of the region to retrieve.
+ /// The height of the region to retrieve.
+ /// A bitmap containing the specified region of the canvas.
+ public virtual Bitmap GetImage(int x, int y, int width, int height)
+ {
+ Bitmap bitmap = new ((uint)width, (uint)height, ColorDepth.ColorDepth32);
+
+ for (int posy = y, desty = 0; posy < y + height; posy++, desty++)
+ {
+ for (int posx = x, destx = 0; posx < x + width; posx++, destx++)
+ {
+ bitmap.RawData[desty * width + destx] = GetRawPointColor(posx, posy);
+ }
+ }
+ return bitmap;
+ }
+
+ ///
+ /// Scales an image to the specified new width and height.
+ ///
+ /// The image to be scaled.
+ /// The width of the scaled image.
+ /// The height of the scaled image.
+ /// An array of integers representing the scaled image's pixel data. (Raw bitmap data)
static int[] ScaleImage(Image image, int newWidth, int newHeight)
{
int[] pixels = image.RawData;
@@ -629,6 +714,7 @@ static int[] ScaleImage(Image image, int newWidth, int newHeight)
/// The Y coordinate.
/// The desired width to scale the image to before drawing.
/// The desired height to scale the image to before drawing
+ /// Prevents drawing outside the bounds of the canvas.
public virtual void DrawImage(Image image, int x, int y, int w, int h, bool preventOffBoundPixels = true)
{
Color color;
@@ -666,7 +752,8 @@ public virtual void DrawImage(Image image, int x, int y, int w, int h, bool prev
/// The image to draw.
/// The X coordinate.
/// The Y coordinate.
- public void DrawImageAlpha(Image image, int x, int y, bool preventOffBoundPixels = true)
+ /// Prevents drawing outside the bounds of the canvas.
+ public virtual void DrawImageAlpha(Image image, int x, int y, bool preventOffBoundPixels = true)
{
Color color;
if (preventOffBoundPixels)
diff --git a/source/Cosmos.System2/Graphics/FullScreenCanvas.cs b/source/Cosmos.System2/Graphics/FullScreenCanvas.cs
index 1733e970d2..89d4c22dec 100644
--- a/source/Cosmos.System2/Graphics/FullScreenCanvas.cs
+++ b/source/Cosmos.System2/Graphics/FullScreenCanvas.cs
@@ -35,7 +35,7 @@ private enum VideoDriver
VGADriver
}
- static Canvas videoDriver = null;
+ public static Canvas videoDriver = null;
static readonly PCIDevice svgaIIDevice = PCI.GetDevice(VendorID.VMWare, DeviceID.SVGAIIAdapter);
///
diff --git a/source/Cosmos.System2/Graphics/SVGAIICanvas.cs b/source/Cosmos.System2/Graphics/SVGAIICanvas.cs
index 32a01de9fe..d7e5fb41f1 100644
--- a/source/Cosmos.System2/Graphics/SVGAIICanvas.cs
+++ b/source/Cosmos.System2/Graphics/SVGAIICanvas.cs
@@ -18,7 +18,7 @@ public class SVGAIICanvas : Canvas
static readonly Mode defaultMode = new(1024, 768, ColorDepth.ColorDepth32);
private Mode mode;
- private readonly VMWareSVGAII driver;
+ public readonly VMWareSVGAII driver;
///
/// Initializes a new instance of the class.
@@ -80,11 +80,55 @@ public override void DrawPoint(Color color, int x, int y)
driver.SetPixel((uint)x, (uint)y, (uint)color.ToArgb());
}
+ public override void DrawRawPoint(uint color, int x, int y)
+ {
+ driver.SetPixel((uint)x, (uint)y, color);
+ }
+
+ public override void DrawRawPoint(int color, int x, int y)
+ {
+ driver.SetPixel((uint)x, (uint)y, (uint)color);
+ }
+
+ public override void DrawArray(Color[] colors, int x, int y, int width, int height)
+ {
+ ThrowIfCoordNotValid(x, y);
+ ThrowIfCoordNotValid(x + width, y + height);
+
+ for (int i = 0; i < x; i++)
+ {
+ for (int ii = 0; ii < y; ii++)
+ {
+ DrawPoint(colors[i + (ii * width)], i, ii);
+ }
+ }
+ }
+
+ public override void DrawArray(int[] colors, int x, int y, int width, int height)
+ {
+ var frameSize = (int)driver.FrameSize;
+
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, colors, i * width, width);
+ }
+ }
+
+ public override void DrawArray(int[] colors, int x, int y, int width, int height, int startIndex)
+ {
+ var frameSize = (int)driver.FrameSize;
+
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, colors, i * width + startIndex, width);
+ }
+ }
+
public override void DrawFilledRectangle(Color color, int xStart, int yStart, int width, int height, bool preventOffBoundPixels = true)
{
var argb = color.ToArgb();
var frameSize = (int)driver.FrameSize;
- if(preventOffBoundPixels)
+ if (preventOffBoundPixels)
{
width = Math.Min(width, (int)mode.Width - xStart);
height = Math.Min(height, (int)mode.Height - yStart);
@@ -97,6 +141,54 @@ public override void DrawFilledRectangle(Color color, int xStart, int yStart, in
}
}
+ public override void DrawRectangle(Color color, int x, int y, int width, int height)
+ {
+ if (color.A < 255)
+ {
+ // Draw top edge from (x, y) to (x + width, y)
+ DrawLine(color, x, y, x + width, y);
+
+ // Draw left edge from (x, y) to (x, y + height)
+ DrawLine(color, x, y, x, y + height);
+
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ DrawLine(color, x, y + height, x + width, y + height);
+
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ DrawLine(color, x + width, y, x + width, y + height);
+ }
+ else
+ {
+ int rawColor = color.ToArgb();
+
+ /* Draw the top edge (A to B) */
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawRawPoint((uint)rawColor, posX, y);
+ }
+
+ /* Draw the bottom edge (C to D) */
+ int newY = y + height;
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawRawPoint((uint)rawColor, posX, newY);
+ }
+
+ /* Draw the left edge (A to C) */
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawRawPoint((uint)rawColor, x, posY);
+ }
+
+ /* Draw the right edge (B to D) */
+ int newX = x + width;
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawRawPoint((uint)rawColor, newX, posY);
+ }
+ }
+ }
+
//public override IReadOnlyList AvailableModes { get; } = new List
///
/// Available SVGA 2 supported video modes.
@@ -315,6 +407,11 @@ public override Color GetPointColor(int x, int y)
return Color.FromArgb((int)driver.GetPixel((uint)x, (uint)y));
}
+ public override int GetRawPointColor(int x, int y)
+ {
+ return (int)driver.GetPixel((uint)x, (uint)y);
+ }
+
public override void Display()
{
driver.DoubleBufferUpdate();
@@ -357,14 +454,25 @@ public override void DrawImage(Image image, int x, int y, bool preventOffBoundPi
var height = (int)image.Height;
var frameSize = (int)driver.FrameSize;
var data = image.RawData;
+
if (preventOffBoundPixels)
{
var maxWidth = Math.Min(width, (int)mode.Width - x);
var maxHeight = Math.Min(height, (int)mode.Height - y);
+ var startX = Math.Max(0, x);
+ var startY = Math.Max(0, y);
+
+ var sourceX = Math.Max(0, -x);
+ var sourceY = Math.Max(0, -y);
+
+ // Adjust maxWidth and maxHeight if startX or startY were changed
+ maxWidth -= startX - x;
+ maxHeight -= startY - y;
for (int i = 0; i < maxHeight; i++)
{
- driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, data, i * width, maxWidth);
+ int sourceIndex = (sourceY + i) * width + sourceX;
+ driver.videoMemory.Copy(GetPointOffset(startX, startY + i) + frameSize, data, sourceIndex, maxWidth);
}
}
else
@@ -375,5 +483,75 @@ public override void DrawImage(Image image, int x, int y, bool preventOffBoundPi
}
}
}
+
+
+ ///
+ /// Draws a cropped image on the canvas at the specified position with maximum width and height.
+ ///
+ /// The image to be drawn.
+ /// The x-coordinate of the top-left corner where the image will be drawn.
+ /// The y-coordinate of the top-left corner where the image will be drawn.
+ /// The maximum width of the cropped area.
+ /// The maximum height of the cropped area.
+ public override void CroppedDrawImage(Image image, int x, int y, int width, int height, bool preventOffBoundPixels = true)
+ {
+ var frameSize = (int)driver.FrameSize;
+ var data = image.RawData;
+
+ if (preventOffBoundPixels)
+ {
+ var modeWidth = (int)mode.Width;
+ var modeHeight = (int)mode.Height;
+
+ var maxWidth = Math.Min(width, modeWidth - x);
+ var maxHeight = Math.Min(height, modeHeight - y);
+
+ var startX = Math.Max(0, -x);
+ var startY = Math.Max(0, -y);
+
+ var sourceWidth = maxWidth - startX;
+ var sourceHeight = maxHeight - startY;
+
+ for (int i = 0; i < sourceHeight; i++)
+ {
+ int destY = y + startY + i;
+ int destOffset = GetPointOffset(x + startX, destY) + frameSize;
+
+ driver.videoMemory.Copy(destOffset, data, (startY + i) * width + startX, sourceWidth);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Copy(GetPointOffset(x, y + i) + frameSize, data, i * width, width);
+ }
+ }
+ }
+
+
+ ///
+ /// Retrieves a specified region of the canvas as a bitmap.
+ ///
+ /// The x-coordinate of the top-left corner of the region.
+ /// The y-coordinate of the top-left corner of the region.
+ /// The width of the region to retrieve.
+ /// The height of the region to retrieve.
+ /// A bitmap containing the specified region of the canvas.
+ public override Bitmap GetImage(int x, int y, int width, int height)
+ {
+ var frameSize = (int)driver.FrameSize;
+ int[] buffer = new int[width];
+ int[] all = new int[width * height];
+ for (int i = 0; i < height; i++)
+ {
+ driver.videoMemory.Get(GetPointOffset(x, y + i) + frameSize, buffer, 0, width);
+ buffer.CopyTo(all, width * i);
+ }
+ Bitmap toReturn = new Bitmap((uint)width, (uint)height, ColorDepth.ColorDepth32);
+ toReturn.RawData = all;
+
+ return toReturn;
+ }
}
}
\ No newline at end of file
diff --git a/source/Cosmos.System2/Graphics/VBECanvas.cs b/source/Cosmos.System2/Graphics/VBECanvas.cs
index bb86dbf1be..0743363175 100644
--- a/source/Cosmos.System2/Graphics/VBECanvas.cs
+++ b/source/Cosmos.System2/Graphics/VBECanvas.cs
@@ -3,6 +3,7 @@
using Cosmos.Core.Multiboot;
using System.Drawing;
using System;
+using System.Net;
namespace Cosmos.System.Graphics
{
@@ -14,7 +15,7 @@ namespace Cosmos.System.Graphics
public class VBECanvas : Canvas
{
static readonly Mode defaultMode = new(1024, 768, ColorDepth.ColorDepth32);
- readonly VBEDriver driver;
+ public readonly VBEDriver driver;
Mode mode;
///
@@ -234,6 +235,39 @@ public override void DrawPoint(Color aColor, int aX, int aY)
}
}
+ public override void DrawRawPoint(uint aColor, int aX, int aY)
+ {
+ uint offset;
+
+ switch (Mode.ColorDepth)
+ {
+ case ColorDepth.ColorDepth32:
+ offset = (uint)GetPointOffset(aX, aY);
+
+ driver.SetVRAM(offset, (byte)((aColor >> 16) & 0xFF));
+ driver.SetVRAM(offset + 1, (byte)((aColor >> 8) & 0xFF));
+ driver.SetVRAM(offset + 2, (byte)(aColor & 0xFF));
+ driver.SetVRAM(offset + 3, (byte)((aColor >> 24) & 0xFF));
+
+ break;
+ case ColorDepth.ColorDepth24:
+ offset = (uint)GetPointOffset(aX, aY);
+
+ driver.SetVRAM(offset, (byte)((aColor >> 16) & 0xFF));
+ driver.SetVRAM(offset + 1, (byte)((aColor >> 8) & 0xFF));
+ driver.SetVRAM(offset + 2, (byte)(aColor & 0xFF));
+
+ break;
+ default:
+ throw new NotImplementedException("Drawing pixels with color depth " + (int)Mode.ColorDepth + " is not yet supported.");
+ }
+ }
+
+ public override void DrawRawPoint(int aColor, int aX, int aY)
+ {
+ DrawRawPoint((uint)aColor, aX, aY);
+ }
+
public override void DrawArray(Color[] aColors, int aX, int aY, int aWidth, int aHeight)
{
ThrowIfCoordNotValid(aX, aY);
@@ -248,11 +282,29 @@ public override void DrawArray(Color[] aColors, int aX, int aY, int aWidth, int
}
}
+ public override void DrawArray(int[] aColors, int aX, int aY, int aWidth, int aHeight)
+ {
+ for (int i = 0; i < aHeight; i++)
+ {
+ int destinationIndex = (aY + i) * (int)mode.Width + aX;
+ driver.CopyVRAM(destinationIndex, aColors, i * aWidth, aWidth);
+ }
+ }
+
+ public override void DrawArray(int[] aColors, int aX, int aY, int aWidth, int aHeight, int startIndex)
+ {
+ for (int i = 0; i < aHeight; i++)
+ {
+ int destinationIndex = (aY + i) * (int)mode.Width + aX;
+ driver.CopyVRAM(destinationIndex, aColors, i * aWidth + startIndex, aWidth);
+ }
+ }
+
public override void DrawFilledRectangle(Color aColor, int aX, int aY, int aWidth, int aHeight, bool preventOffBoundPixels = true)
{
// ClearVRAM clears one uint at a time. So we clear pixelwise not byte wise. That's why we divide by 32 and not 8.
- if(preventOffBoundPixels)
- aWidth = (int)(Math.Min(aWidth, Mode.Width - aX) * (int)Mode.ColorDepth / 32);
+ if (preventOffBoundPixels)
+ aWidth = (int)(Math.Min(aWidth, Mode.Width - aX) * (int)Mode.ColorDepth / 32);
var color = aColor.ToArgb();
for (int i = aY; i < aY + aHeight; i++)
@@ -261,32 +313,137 @@ public override void DrawFilledRectangle(Color aColor, int aX, int aY, int aWidt
}
}
- public override void DrawImage(Image aImage, int aX, int aY, bool preventOffBoundPixels = true)
+ ///
+ /// Draws a rectangle on the canvas with the specified color and dimensions.
+ ///
+ /// The color of the rectangle.
+ /// The x-coordinate of the top-left corner of the rectangle.
+ /// The y-coordinate of the top-left corner of the rectangle.
+ /// The width of the rectangle.
+ /// The height of the rectangle.
+ public override void DrawRectangle(Color color, int x, int y, int width, int height)
{
- var xBitmap = aImage.RawData;
- var xWidth = (int)aImage.Width;
- var xHeight = (int)aImage.Height;
+ if (color.A < 255)
+ {
+ // Draw top edge from (x, y) to (x + width, y)
+ DrawLine(color, x, y, x + width, y);
+
+ // Draw left edge from (x, y) to (x, y + height)
+ DrawLine(color, x, y, x, y + height);
+
+ // Draw bottom edge from (x, y + height) to (x + width, y + height)
+ DrawLine(color, x, y + height, x + width, y + height);
+
+ // Draw right edge from (x + width, y) to (x + width, y + height)
+ DrawLine(color, x + width, y, x + width, y + height);
+ }
+ else
+ {
+ int rawColor = color.ToArgb();
+
+ /* Draw the top edge (A to B) */
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawRawPoint((uint)rawColor, posX, y);
+ }
+
+ /* Draw the bottom edge (C to D) */
+ int newY = y + height;
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawRawPoint((uint)rawColor, posX, newY);
+ }
+
+ /* Draw the left edge (A to C) */
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawRawPoint((uint)rawColor, x, posY);
+ }
+
+ /* Draw the right edge (B to D) */
+ int newX = x + width;
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawRawPoint((uint)rawColor, newX, posY);
+ }
+ }
+ }
+
+ public override void DrawImage(Image image, int x, int y, bool preventOffBoundPixels = true)
+ {
+ var width = (int)image.Width;
+ var height = (int)image.Height;
+ var data = image.RawData;
+
if (preventOffBoundPixels)
{
- var maxWidth = Math.Min(xWidth, (int)mode.Width - aX);
- var maxHeight = Math.Min(xHeight, (int)mode.Height - aY);
- int xOffset = aY * (int)Mode.Width + aX;
+ var maxWidth = Math.Min(width, (int)mode.Width - x);
+ var maxHeight = Math.Min(height, (int)mode.Height - y);
+ var startX = Math.Max(0, x);
+ var startY = Math.Max(0, y);
+
+ var sourceX = Math.Max(0, -x);
+ var sourceY = Math.Max(0, -y);
+
+ // Adjust maxWidth and maxHeight if startX or startY were changed
+ maxWidth -= startX - x;
+ maxHeight -= startY - y;
+
for (int i = 0; i < maxHeight; i++)
{
- driver.CopyVRAM((i * (int)Mode.Width) + xOffset, xBitmap, i * xWidth, maxWidth);
+ int sourceIndex = (sourceY + i) * width + sourceX;
+ int destinationIndex = (startY + i) * (int)mode.Width + startX;
+ driver.CopyVRAM(destinationIndex, data, sourceIndex, maxWidth);
}
}
else
{
- int xOffset = aY * xHeight + aX;
- for (int i = 0; i < Mode.Height; i++)
+ for (int i = 0; i < height; i++)
{
- driver.CopyVRAM((i * (int)Mode.Width) + xOffset, xBitmap, i * xWidth, xWidth);
+ int destinationIndex = (y + i) * (int)mode.Width + x;
+ driver.CopyVRAM(destinationIndex, data, i * width, width);
}
}
+ }
+
+ public override void CroppedDrawImage(Image aImage, int aX, int aY, int aWidth, int aHeight, bool preventOffBoundPixels = true)
+ {
+ var xBitmap = aImage.RawData;
+ var xWidth = aWidth;
+ var xHeight = aHeight;
+
+ if (preventOffBoundPixels)
+ {
+ var maxWidth = Math.Min(xWidth, (int)Mode.Width - aX);
+ var maxHeight = Math.Min(xHeight, (int)Mode.Height - aY);
+
+ var startX = Math.Max(0, aX);
+ var startY = Math.Max(0, aY);
+
+ var sourceX = Math.Max(0, -aX);
+ var sourceY = Math.Max(0, -aY);
+ maxWidth -= startX - aX;
+ maxHeight -= startY - aY;
+
+ for (int i = 0; i < maxHeight; i++)
+ {
+ int sourceIndex = (sourceY + i) * xWidth + sourceX;
+ int destinationIndex = (startY + i) * (int)Mode.Width + startX;
+ driver.CopyVRAM(destinationIndex, xBitmap, sourceIndex, maxWidth);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < xHeight; i++)
+ {
+ int destinationIndex = (aY + i) * (int)Mode.Width + aX;
+ driver.CopyVRAM(destinationIndex, xBitmap, i * xWidth, xWidth);
+ }
+ }
}
+
#endregion
public override void Display()
@@ -302,7 +459,38 @@ public override Color GetPointColor(int aX, int aY)
return Color.FromArgb((int)driver.GetVRAM(offset));
}
- #endregion
+ public override int GetRawPointColor(int aX, int aY)
+ {
+ uint offset = (uint)GetPointOffset(aX, aY);
+ return (int)driver.GetVRAM(offset);
+ }
+ public override Bitmap GetImage(int x, int y, int width, int height)
+ {
+ Bitmap bitmap = new((uint)width, (uint)height, ColorDepth.ColorDepth32);
+
+ int startX = Math.Max(0, x);
+ int startY = Math.Max(0, y);
+ int endX = Math.Min(x + width, (int)Mode.Width);
+ int endY = Math.Min(y + height, (int)Mode.Height);
+
+ int offsetX = Math.Max(0, -x);
+ int offsetY = Math.Max(0, -y);
+
+ int[] rawData = new int[width * height];
+
+ for (int posy = startY; posy < endY; posy++)
+ {
+ int srcOffset = posy * (int)Mode.Width + startX;
+ int destOffset = (posy - startY) * width;
+ driver.GetVRAM(srcOffset, rawData, destOffset, endX - startX);
+ }
+
+ bitmap.RawData = rawData;
+ return bitmap;
+ }
+
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/source/Cosmos.System2/Graphics/VGACanvas.cs b/source/Cosmos.System2/Graphics/VGACanvas.cs
index 2157e06dee..3236c88802 100644
--- a/source/Cosmos.System2/Graphics/VGACanvas.cs
+++ b/source/Cosmos.System2/Graphics/VGACanvas.cs
@@ -96,6 +96,37 @@ public override void DrawFilledRectangle(Color aColor, int aXStart, int aYStart,
driver.DrawFilledRectangle(aXStart, aYStart, aWidth, aHeight, driver.GetClosestColorInPalette(aColor));
}
+ public override void DrawRectangle(Color color, int x, int y, int width, int height)
+ {
+ int rawColor = color.ToArgb();
+
+ /* Draw the top edge (A to B) */
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawRawPoint((uint)rawColor, posX, y);
+ }
+
+ /* Draw the bottom edge (C to D) */
+ int newY = y + height;
+ for (int posX = x; posX < x + width; posX++)
+ {
+ DrawRawPoint((uint)rawColor, posX, newY);
+ }
+
+ /* Draw the left edge (A to C) */
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawRawPoint((uint)rawColor, x, posY);
+ }
+
+ /* Draw the right edge (B to D) */
+ int newX = x + width;
+ for (int posY = y; posY < y + height; posY++)
+ {
+ DrawRawPoint((uint)rawColor, newX, posY);
+ }
+ }
+
public override void DrawPoint(Color aColor, int aX, int aY)
{
driver.SetPixel((uint)aX, (uint)aY, aColor);
@@ -106,6 +137,16 @@ public void DrawPoint(uint aColor, int aX, int aY)
driver.SetPixel((uint)aX, (uint)aY, aColor);
}
+ public override void DrawRawPoint(uint aColor, int aX, int aY)
+ {
+ driver.SetPixel((uint)aX, (uint)aY, aColor);
+ }
+
+ public override void DrawRawPoint(int aColor, int aX, int aY)
+ {
+ driver.SetPixel((uint)aX, (uint)aY, (uint)aColor);
+ }
+
public override List AvailableModes => availableModes;
public override Color GetPointColor(int aX, int aY)
@@ -113,6 +154,11 @@ public override Color GetPointColor(int aX, int aY)
return Color.FromArgb((int)driver.GetPixel((uint)aX, (uint)aY));
}
+ public override int GetRawPointColor(int aX, int aY)
+ {
+ return (int)driver.GetPixel((uint)aX, (uint)aY);
+ }
+
public override Mode DefaultGraphicsMode => new Mode(640, 480, ColorDepth.ColorDepth4);
///
diff --git a/source/Cosmos.System2/Graphics/VGAScreen.cs b/source/Cosmos.System2/Graphics/VGAScreen.cs
index 8702099f54..e5a4c9867b 100644
--- a/source/Cosmos.System2/Graphics/VGAScreen.cs
+++ b/source/Cosmos.System2/Graphics/VGAScreen.cs
@@ -9,7 +9,7 @@ namespace Cosmos.System.Graphics
///
public class VGAScreen
{
- static readonly VGADriver screen = new();
+ public static readonly VGADriver screen = new();
///
/// Sets the currently used graphics mode.
diff --git a/source/Cosmos.System2/packages.lock.json b/source/Cosmos.System2/packages.lock.json
index d270257913..326f0da9af 100644
--- a/source/Cosmos.System2/packages.lock.json
+++ b/source/Cosmos.System2/packages.lock.json
@@ -32,4 +32,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/source/Cosmos.System2_Plugs/packages.lock.json b/source/Cosmos.System2_Plugs/packages.lock.json
index 9835c1b263..d4cf3af104 100644
--- a/source/Cosmos.System2_Plugs/packages.lock.json
+++ b/source/Cosmos.System2_Plugs/packages.lock.json
@@ -41,4 +41,4 @@
}
}
}
-}
\ No newline at end of file
+}