mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-29 20:30:44 +00:00
Working context switching but far from stable. Changes needed to be made to the internals of cosmos to include mutex's in vital components (Heap, Thread Manager, ect). Context switching currently only switches the general registers and does not switch the MMX context, however this will be added in the future. Also when a thread currently dies it takes the whole system down, patches to the IDT handlers needed to be made to prevent system lockup in the future
166 lines
7.4 KiB
C#
166 lines
7.4 KiB
C#
using IL2CPU.API.Attribs;
|
|
using System;
|
|
using System.Reflection;
|
|
using XSharp;
|
|
using XSharp.Assembler;
|
|
using XSharp.Assembler.x86;
|
|
using static XSharp.XSRegisters;
|
|
|
|
namespace Cosmos.Core_Asm
|
|
{
|
|
public class CPUUpdateIDTAsm : AssemblerMethod
|
|
{
|
|
public static MethodBase GetMethodDef(Assembly aAssembly, string aType, string aMethodName, bool aErrorWhenNotFound)
|
|
{
|
|
Type xType = aAssembly.GetType(aType, false);
|
|
if (xType != null)
|
|
{
|
|
MethodBase xMethod = xType.GetMethod(aMethodName);
|
|
if (xMethod != null)
|
|
{
|
|
return xMethod;
|
|
}
|
|
}
|
|
if (aErrorWhenNotFound)
|
|
{
|
|
throw new Exception("Method '" + aType + "::" + aMethodName + "' not found!");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static MethodBase GetInterruptHandler(byte aInterrupt)
|
|
{
|
|
return GetMethodDef(typeof(Cosmos.Core.INTs).Assembly, typeof(Cosmos.Core.INTs).FullName
|
|
, "HandleInterrupt_" + aInterrupt.ToString("X2"), false);
|
|
}
|
|
|
|
public override void AssembleNew(Assembler aAssembler, object aMethodInfo)
|
|
{
|
|
// IDT is already initialized but just for base hooks, and asm only.
|
|
// ie Int 1, 3 and GPF
|
|
// This routine updates the IDT now that we have C# running to allow C# hooks to handle
|
|
// the other INTs
|
|
|
|
// We are updating the IDT, disable interrupts
|
|
XS.ClearInterruptFlag();
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
// These are already mapped, don't remap them.
|
|
// Maybe in the future we can look at ones that are present
|
|
// and skip them, but some we may want to overwrite anyways.
|
|
if (i == 1 || i == 3)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
XS.Set(EAX, "__ISR_Handler_" + i.ToString("X2"));
|
|
XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 0);
|
|
XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 1);
|
|
XS.Set("_NATIVE_IDT_Contents", 0x8, destinationDisplacement: (i * 8) + 2, size: RegisterSize.Byte8);
|
|
XS.Set("_NATIVE_IDT_Contents", 0x8E, destinationDisplacement: (i * 8) + 5, size: RegisterSize.Byte8);
|
|
XS.ShiftRight(EAX, 16);
|
|
XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 6);
|
|
XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 7);
|
|
}
|
|
|
|
XS.Jump("__AFTER__ALL__ISR__HANDLER__STUBS__");
|
|
var xInterruptsWithParam = new[] { 8, 10, 11, 12, 13, 14 };
|
|
for (int j = 0; j < 256; j++)
|
|
{
|
|
XS.Label("__ISR_Handler_" + j.ToString("X2"));
|
|
XS.Call("__INTERRUPT_OCCURRED__");
|
|
if (Array.IndexOf(xInterruptsWithParam, j) == -1)
|
|
{
|
|
XS.Push(0);
|
|
}
|
|
XS.Push((uint)j);
|
|
if (j != 0x20)
|
|
{
|
|
XS.PushAllRegisters();
|
|
|
|
XS.Sub(ESP, 4);
|
|
XS.Set(EAX, ESP); // preserve old stack address for passing to interrupt handler
|
|
|
|
// store floating point data
|
|
XS.And(ESP, 0xfffffff0); // fxsave needs to be 16-byte alligned
|
|
XS.Sub(ESP, 512); // fxsave needs 512 bytes
|
|
XS.SSE.FXSave(ESP, isIndirect: true); // save the registers
|
|
XS.Set(EAX, ESP, destinationIsIndirect: true);
|
|
|
|
XS.Push(EAX); //
|
|
XS.Push(EAX); // pass old stack address (pointer to InterruptContext struct) to the interrupt handler
|
|
|
|
|
|
XS.JumpToSegment(8, "__ISR_Handler_" + j.ToString("X2") + "_SetCS");
|
|
XS.Label("__ISR_Handler_" + j.ToString("X2") + "_SetCS");
|
|
MethodBase xHandler = GetInterruptHandler((byte)j);
|
|
if (xHandler == null)
|
|
{
|
|
xHandler = GetMethodDef(typeof(Cosmos.Core.INTs).Assembly, typeof(Cosmos.Core.INTs).FullName, "HandleInterrupt_Default", true);
|
|
}
|
|
XS.Call(LabelName.Get(xHandler));
|
|
|
|
XS.Pop(EAX);
|
|
XS.SSE.FXRestore(ESP, isIndirect: true);
|
|
|
|
XS.Set(ESP, EAX); // this restores the stack for the FX stuff, except the pointer to the FX data
|
|
XS.Add(ESP, 4); // "pop" the pointer
|
|
|
|
XS.PopAllRegisters();
|
|
}
|
|
else
|
|
{
|
|
new LiteralAssemblerCode("pushad");
|
|
new LiteralAssemblerCode("mov eax, ds");
|
|
new LiteralAssemblerCode("push eax");
|
|
new LiteralAssemblerCode("mov eax, es");
|
|
new LiteralAssemblerCode("push eax");
|
|
new LiteralAssemblerCode("mov eax, fs");
|
|
new LiteralAssemblerCode("push eax");
|
|
new LiteralAssemblerCode("mov eax, gs");
|
|
new LiteralAssemblerCode("push eax");
|
|
new LiteralAssemblerCode("mov ax, 0x10");
|
|
new LiteralAssemblerCode("mov ds, ax");
|
|
new LiteralAssemblerCode("mov es, ax");
|
|
new LiteralAssemblerCode("mov fs, ax");
|
|
new LiteralAssemblerCode("mov gs, ax");
|
|
new LiteralAssemblerCode("mov eax, esp");
|
|
XS.Set("static_field__Cosmos_Core_INTs_mStackContext", EAX, destinationIsIndirect: true);
|
|
XS.Call(LabelName.Get(GetMethodDef(typeof(Cosmos.Core.Processing.ProcessorScheduler).Assembly, typeof(Cosmos.Core.Processing.ProcessorScheduler).FullName, "SwitchTask", true)));
|
|
XS.Set(EAX, "static_field__Cosmos_Core_INTs_mStackContext", sourceIsIndirect: true);
|
|
new LiteralAssemblerCode("mov esp, eax");
|
|
new LiteralAssemblerCode("pop eax");
|
|
new LiteralAssemblerCode("mov gs, eax");
|
|
new LiteralAssemblerCode("pop eax");
|
|
new LiteralAssemblerCode("mov fs, eax");
|
|
new LiteralAssemblerCode("pop eax");
|
|
new LiteralAssemblerCode("mov es, eax");
|
|
new LiteralAssemblerCode("pop eax");
|
|
new LiteralAssemblerCode("mov ds, eax");
|
|
new LiteralAssemblerCode("popad");
|
|
}
|
|
|
|
XS.Add(ESP, 8);
|
|
XS.Label("__ISR_Handler_" + j.ToString("X2") + "_END");
|
|
XS.InterruptReturn();
|
|
}
|
|
XS.Label("__INTERRUPT_OCCURRED__");
|
|
XS.Return();
|
|
XS.Label("__AFTER__ALL__ISR__HANDLER__STUBS__");
|
|
XS.Noop();
|
|
XS.Set(EAX, EBP, sourceDisplacement: 8);
|
|
XS.Compare(EAX, 0);
|
|
XS.Jump(ConditionalTestEnum.Zero, ".__AFTER_ENABLE_INTERRUPTS");
|
|
|
|
// reload interrupt list
|
|
XS.Set(EAX, "_NATIVE_IDT_Pointer");
|
|
XS.Set(AsmMarker.Labels[AsmMarker.Type.Processor_IntsEnabled], 1, destinationIsIndirect: true, size: RegisterSize.Byte8);
|
|
XS.LoadIdt(EAX, isIndirect: true);
|
|
// Reenable interrupts
|
|
XS.EnableInterrupts();
|
|
|
|
XS.Label(".__AFTER_ENABLE_INTERRUPTS");
|
|
}
|
|
}
|
|
}
|