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 +}