mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-27 22:12:25 +00:00
617 lines
No EOL
21 KiB
C#
617 lines
No EOL
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Cosmos.Core
|
|
{
|
|
public class INTs
|
|
{
|
|
#region Enums
|
|
// TODO: Protect IRQs like memory and ports are
|
|
// TODO: Make IRQs so they are not hookable, and instead release high priority threads like FreeBSD (When we get threading)
|
|
public enum EFlagsEnum : uint
|
|
{
|
|
Carry = 1,
|
|
Parity = 1 << 2,
|
|
AuxilliaryCarry = 1 << 4,
|
|
Zero = 1 << 6,
|
|
Sign = 1 << 7,
|
|
Trap = 1 << 8,
|
|
InterruptEnable = 1 << 9,
|
|
Direction = 1 << 10,
|
|
Overflow = 1 << 11,
|
|
NestedTag = 1 << 14,
|
|
Resume = 1 << 16,
|
|
Virtual8086Mode = 1 << 17,
|
|
AlignmentCheck = 1 << 18,
|
|
VirtualInterrupt = 1 << 19,
|
|
VirtualInterruptPending = 1 << 20,
|
|
ID = 1 << 21
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit, Size = 0x68)]
|
|
public struct TSS
|
|
{
|
|
[FieldOffset(0)]
|
|
public ushort Link;
|
|
[FieldOffset(4)]
|
|
public uint ESP0;
|
|
[FieldOffset(8)]
|
|
public ushort SS0;
|
|
[FieldOffset(12)]
|
|
public uint ESP1;
|
|
[FieldOffset(16)]
|
|
public ushort SS1;
|
|
[FieldOffset(20)]
|
|
public uint ESP2;
|
|
[FieldOffset(24)]
|
|
public ushort SS2;
|
|
[FieldOffset(28)]
|
|
public uint CR3;
|
|
[FieldOffset(32)]
|
|
public uint EIP;
|
|
[FieldOffset(36)]
|
|
public EFlagsEnum EFlags;
|
|
[FieldOffset(40)]
|
|
public uint EAX;
|
|
[FieldOffset(44)]
|
|
public uint ECX;
|
|
[FieldOffset(48)]
|
|
public uint EDX;
|
|
[FieldOffset(52)]
|
|
public uint EBX;
|
|
[FieldOffset(56)]
|
|
public uint ESP;
|
|
[FieldOffset(60)]
|
|
public uint EBP;
|
|
[FieldOffset(64)]
|
|
public uint ESI;
|
|
[FieldOffset(68)]
|
|
public uint EDI;
|
|
[FieldOffset(72)]
|
|
public ushort ES;
|
|
[FieldOffset(76)]
|
|
public ushort CS;
|
|
[FieldOffset(80)]
|
|
public ushort SS;
|
|
[FieldOffset(84)]
|
|
public ushort DS;
|
|
[FieldOffset(88)]
|
|
public ushort FS;
|
|
[FieldOffset(92)]
|
|
public ushort GS;
|
|
[FieldOffset(96)]
|
|
public ushort LDTR;
|
|
[FieldOffset(102)]
|
|
public ushort IOPBOffset;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit, Size = 512)]
|
|
public struct MMXContext
|
|
{
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit, Size = 80)]
|
|
public struct IRQContext
|
|
{
|
|
[FieldOffset(0)]
|
|
public unsafe MMXContext* MMXContext;
|
|
|
|
[FieldOffset(4)]
|
|
public uint EDI;
|
|
|
|
[FieldOffset(8)]
|
|
public uint ESI;
|
|
|
|
[FieldOffset(12)]
|
|
public uint EBP;
|
|
|
|
[FieldOffset(16)]
|
|
public uint ESP;
|
|
|
|
[FieldOffset(20)]
|
|
public uint EBX;
|
|
|
|
[FieldOffset(24)]
|
|
public uint EDX;
|
|
|
|
[FieldOffset(28)]
|
|
public uint ECX;
|
|
|
|
[FieldOffset(32)]
|
|
public uint EAX;
|
|
|
|
[FieldOffset(36)]
|
|
public uint Interrupt;
|
|
|
|
[FieldOffset(40)]
|
|
public uint Param;
|
|
|
|
[FieldOffset(44)]
|
|
public uint EIP;
|
|
|
|
[FieldOffset(48)]
|
|
public uint CS;
|
|
|
|
[FieldOffset(52)]
|
|
public EFlagsEnum EFlags;
|
|
|
|
[FieldOffset(56)]
|
|
public uint UserESP;
|
|
}
|
|
#endregion
|
|
|
|
private static IRQDelegate[] mIRQ_Handlers = new IRQDelegate[256];
|
|
|
|
// We used to use:
|
|
//Interrupts.IRQ01 += HandleKeyboardInterrupt;
|
|
// But at one point we had issues with multi cast delegates, so we changed to this single cast option.
|
|
// [1:48:37 PM] Matthijs ter Woord: the issues were: "they didn't work, would crash kernel". not sure if we still have them..
|
|
public static void SetIntHandler(byte aIntNo, IRQDelegate aHandler)
|
|
{
|
|
mIRQ_Handlers[aIntNo] = aHandler;
|
|
}
|
|
public static void SetIrqHandler(byte aIrqNo, IRQDelegate aHandler)
|
|
{
|
|
SetIntHandler((byte)(0x20 + aIrqNo), aHandler);
|
|
}
|
|
|
|
private static void IRQ(uint irq, ref IRQContext aContext)
|
|
{
|
|
var xCallback = mIRQ_Handlers[irq];
|
|
if (xCallback != null)
|
|
{
|
|
HMI.GCMonitor();
|
|
xCallback(ref aContext);
|
|
HMI.GCFreeAll();
|
|
}
|
|
}
|
|
|
|
public static void HandleInterrupt_Default(ref IRQContext aContext)
|
|
{
|
|
if (aContext.Interrupt >= 0x20 && aContext.Interrupt <= 0x2F)
|
|
{
|
|
if (aContext.Interrupt >= 0x28)
|
|
{
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
else
|
|
{
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
}
|
|
}
|
|
|
|
public delegate void IRQDelegate(ref IRQContext aContext);
|
|
public delegate void ExceptionInterruptDelegate(ref IRQContext aContext, ref bool aHandled);
|
|
|
|
#region Default Interrupt Handlers
|
|
|
|
//IRQ 0 - System timer. Reserved for the system. Cannot be changed by a user.
|
|
public static void HandleInterrupt_20(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x20, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
|
|
//public static IRQDelegate IRQ01;
|
|
//IRQ 1 - Keyboard. Reserved for the system. Cannot be altered even if no keyboard is present or needed.
|
|
public static void HandleInterrupt_21(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x21, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
public static void HandleInterrupt_22(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x22, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
public static void HandleInterrupt_23(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x23, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
public static void HandleInterrupt_24(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x24, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
public static void HandleInterrupt_25(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x25, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
public static void HandleInterrupt_26(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x26, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
public static void HandleInterrupt_27(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x27, ref aContext);
|
|
Global.PIC.EoiMaster();
|
|
}
|
|
|
|
public static void HandleInterrupt_28(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x28, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
//IRQ 09 - (Added for AMD PCNet network card)
|
|
//public static IRQDelegate IRQ09;
|
|
|
|
public static void HandleInterrupt_29(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x29, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
|
|
//IRQ 10 - (Added for VIA Rhine network card)
|
|
//public static IRQDelegate IRQ10;
|
|
|
|
public static void HandleInterrupt_2A(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x2A, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
|
|
//IRQ 11 - (Added for RTL8139 network card)
|
|
//public static IRQDelegate IRQ11;
|
|
|
|
public static void HandleInterrupt_2B(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x2B, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
|
|
public static void HandleInterrupt_2C(ref IRQContext aContext)
|
|
{
|
|
|
|
IRQ(0x2C, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
|
|
|
|
public static void HandleInterrupt_2D(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x2D, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
//IRQ 14 - Primary IDE. If no Primary IDE this can be changed
|
|
public static void HandleInterrupt_2E(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x2E, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
//IRQ 15 - Secondary IDE
|
|
public static void HandleInterrupt_2F(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x2F, ref aContext);
|
|
Global.PIC.EoiSlave();
|
|
}
|
|
|
|
public static event IRQDelegate Interrupt30;
|
|
// Interrupt 0x30, enter VMM
|
|
public static void HandleInterrupt_30(ref IRQContext aContext)
|
|
{
|
|
if (Interrupt30 != null)
|
|
{
|
|
Interrupt30(ref aContext);
|
|
}
|
|
}
|
|
|
|
public static void HandleInterrupt_35(ref IRQContext aContext)
|
|
{
|
|
Global.Dbg.SendMessage("Interrupts", "Interrupt 35 handler");
|
|
aContext.EAX *= 2;
|
|
aContext.EBX *= 2;
|
|
aContext.ECX *= 2;
|
|
aContext.EDX *= 2;
|
|
}
|
|
|
|
public static void HandleInterrupt_40(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x40, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_41(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x41, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_42(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x42, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_43(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x43, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_44(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x44, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_45(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x45, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_46(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x46, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_47(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x47, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_48(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x48, ref aContext);
|
|
}
|
|
public static void HandleInterrupt_49(ref IRQContext aContext)
|
|
{
|
|
IRQ(0x49, ref aContext);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CPU Exceptions
|
|
|
|
public static IRQDelegate GeneralProtectionFault;
|
|
|
|
public static void HandleInterrupt_00(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Divide by zero", "EDivideByZero", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_01(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Debug Exception", "Debug Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_02(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Non Maskable Interrupt Exception", "Non Maskable Interrupt Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_03(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Breakpoint Exception", "Breakpoint Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_04(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Into Detected Overflow Exception", "Into Detected Overflow Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_05(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Out of Bounds Exception", "Out of Bounds Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_06(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Invalid Opcode", "EInvalidOpcode", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_07(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "No Coprocessor Exception", "No Coprocessor Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_08(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Double Fault Exception", "Double Fault Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_09(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Coprocessor Segment Overrun Exception", "Coprocessor Segment Overrun Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_0A(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Bad TSS Exception", "Bad TSS Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_0B(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Segment Not Present", "Segment Not Present", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_0C(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Stack Fault Exception", "Stack Fault Exception", ref aContext);
|
|
}
|
|
public static void HandleInterrupt_0D(ref IRQContext aContext)
|
|
{
|
|
if (GeneralProtectionFault != null)
|
|
{
|
|
GeneralProtectionFault(ref aContext);
|
|
}
|
|
else
|
|
{
|
|
HandleException(aContext.EIP, "General Protection Fault", "GPF", ref aContext);
|
|
}
|
|
}
|
|
|
|
public static void HandleInterrupt_0E(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Page Fault Exception", "Page Fault Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_0F(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Unknown Interrupt Exception", "Unknown Interrupt Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_10(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "x87 Floating Point Exception", "Coprocessor Fault Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_11(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Alignment Exception", "Alignment Exception", ref aContext);
|
|
}
|
|
|
|
public static void HandleInterrupt_12(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "Machine Check Exception", "Machine Check Exception", ref aContext);
|
|
}
|
|
public static void HandleInterrupt_13(ref IRQContext aContext)
|
|
{
|
|
HandleException(aContext.EIP, "SIMD Floating Point Exception", "SIMD Floating Point Exception", ref aContext);
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
private static void HandleException(uint aEIP, string aDescription, string aName, ref IRQContext ctx)
|
|
{
|
|
// At this point we are in a very unstable state.
|
|
// Try not to use any Cosmos routines, just
|
|
// report a crash dump.
|
|
const string xHex = "0123456789ABCDEF";
|
|
uint xPtr = ctx.EIP;
|
|
|
|
// we're printing exception info to the screen now:
|
|
// 0/0: x
|
|
// 1/0: exception number in hex
|
|
unsafe
|
|
{
|
|
byte* xAddress = (byte*)0xB8000;
|
|
xAddress[0] = (byte)' ';
|
|
xAddress[1] = 0x0C;
|
|
xAddress[2] = (byte)'*';
|
|
xAddress[3] = 0x0C;
|
|
xAddress[4] = (byte)'*';
|
|
xAddress[5] = 0x0C;
|
|
xAddress[6] = (byte)'*';
|
|
xAddress[7] = 0x0C;
|
|
xAddress[8] = (byte)' ';
|
|
xAddress[9] = 0x0C;
|
|
xAddress[10] = (byte)'C';
|
|
xAddress[11] = 0x0C;
|
|
xAddress[12] = (byte)'P';
|
|
xAddress[13] = 0x0C;
|
|
xAddress[14] = (byte)'U';
|
|
xAddress[15] = 0x0C;
|
|
xAddress[16] = (byte)' ';
|
|
xAddress[17] = 0x0C;
|
|
xAddress[18] = (byte)'E';
|
|
xAddress[19] = 0x0C;
|
|
xAddress[20] = (byte)'x';
|
|
xAddress[21] = 0x0C;
|
|
xAddress[22] = (byte)'c';
|
|
xAddress[23] = 0x0C;
|
|
xAddress[24] = (byte)'e';
|
|
xAddress[25] = 0x0C;
|
|
xAddress[26] = (byte)'p';
|
|
xAddress[27] = 0x0C;
|
|
xAddress[28] = (byte)'t';
|
|
xAddress[29] = 0x0C;
|
|
xAddress[30] = (byte)'i';
|
|
xAddress[31] = 0x0C;
|
|
xAddress[32] = (byte)'o';
|
|
xAddress[33] = 0x0C;
|
|
xAddress[34] = (byte)'n';
|
|
xAddress[35] = 0x0C;
|
|
xAddress[36] = (byte)' ';
|
|
xAddress[37] = 0x0C;
|
|
xAddress[38] = (byte)'x';
|
|
xAddress[39] = 0x0C;
|
|
xAddress[40] = (byte)xHex[(int)((ctx.Interrupt >> 4) & 0xF)];
|
|
xAddress[41] = 0x0C;
|
|
xAddress[42] = (byte)xHex[(int)(ctx.Interrupt & 0xF)];
|
|
xAddress[43] = 0x0C;
|
|
xAddress[44] = (byte)' ';
|
|
xAddress[45] = 0x0C;
|
|
xAddress[46] = (byte)'*';
|
|
xAddress[47] = 0x0C;
|
|
xAddress[48] = (byte)'*';
|
|
xAddress[49] = 0x0C;
|
|
xAddress[50] = (byte)'*';
|
|
xAddress[51] = 0x0C;
|
|
xAddress[52] = (byte)' ';
|
|
xAddress[53] = 0x0C;
|
|
}
|
|
|
|
// lock up
|
|
while (true)
|
|
{
|
|
}
|
|
}
|
|
|
|
// This is to trick IL2CPU to compile it in
|
|
//TODO: Make a new attribute that IL2CPU sees when scanning to force inclusion so we dont have to do this.
|
|
// We dont actually need to cal this method
|
|
public static void Dummy()
|
|
{
|
|
// Compiler magic
|
|
bool xTest = false;
|
|
if (xTest)
|
|
{
|
|
unsafe
|
|
{
|
|
var xCtx = new IRQContext();
|
|
HandleInterrupt_Default(ref xCtx);
|
|
HandleInterrupt_00(ref xCtx);
|
|
HandleInterrupt_01(ref xCtx);
|
|
HandleInterrupt_02(ref xCtx);
|
|
HandleInterrupt_03(ref xCtx);
|
|
HandleInterrupt_04(ref xCtx);
|
|
HandleInterrupt_05(ref xCtx);
|
|
HandleInterrupt_06(ref xCtx);
|
|
HandleInterrupt_07(ref xCtx);
|
|
HandleInterrupt_08(ref xCtx);
|
|
HandleInterrupt_09(ref xCtx);
|
|
HandleInterrupt_0A(ref xCtx);
|
|
HandleInterrupt_0B(ref xCtx);
|
|
HandleInterrupt_0C(ref xCtx);
|
|
HandleInterrupt_0D(ref xCtx);
|
|
HandleInterrupt_0E(ref xCtx);
|
|
HandleInterrupt_0F(ref xCtx);
|
|
HandleInterrupt_10(ref xCtx);
|
|
HandleInterrupt_11(ref xCtx);
|
|
HandleInterrupt_12(ref xCtx);
|
|
HandleInterrupt_13(ref xCtx);
|
|
HandleInterrupt_20(ref xCtx);
|
|
HandleInterrupt_21(ref xCtx);
|
|
HandleInterrupt_22(ref xCtx);
|
|
HandleInterrupt_23(ref xCtx);
|
|
HandleInterrupt_24(ref xCtx);
|
|
HandleInterrupt_25(ref xCtx);
|
|
HandleInterrupt_26(ref xCtx);
|
|
HandleInterrupt_27(ref xCtx);
|
|
HandleInterrupt_28(ref xCtx);
|
|
HandleInterrupt_29(ref xCtx);
|
|
HandleInterrupt_2A(ref xCtx);
|
|
HandleInterrupt_2B(ref xCtx);
|
|
HandleInterrupt_2C(ref xCtx);
|
|
HandleInterrupt_2D(ref xCtx);
|
|
HandleInterrupt_2E(ref xCtx);
|
|
HandleInterrupt_2F(ref xCtx);
|
|
HandleInterrupt_30(ref xCtx);
|
|
HandleInterrupt_35(ref xCtx);
|
|
HandleInterrupt_40(ref xCtx);
|
|
HandleInterrupt_41(ref xCtx);
|
|
HandleInterrupt_42(ref xCtx);
|
|
HandleInterrupt_43(ref xCtx);
|
|
HandleInterrupt_44(ref xCtx);
|
|
HandleInterrupt_45(ref xCtx);
|
|
HandleInterrupt_46(ref xCtx);
|
|
HandleInterrupt_47(ref xCtx);
|
|
HandleInterrupt_48(ref xCtx);
|
|
HandleInterrupt_49(ref xCtx);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
} |