//
// Created by Eugeny Grishul
//
// See license at http://bamelg.com/license.txt
//
// Execution and context-switch related functionality
//
using System;
using System.Diagnostics;
using System.Runtime;
using System.Runtime.CompilerServices;
using Platform.Kernel;
using Platform.Libc;
namespace System.IO {
public partial struct Fiber {
internal partial struct FiberInfo {
[Alignment( Boundary = 4 )]
private struct ProcessorContextX86_32 : ProcessorContext {
public uint EIP;
// public uint EAX; // volatile register
public uint EBX;
// public uint ECX; // volatile register
// public uint EDX; // volatile register
public uint EBP;
public uint EDI;
public uint ESI;
public uint ESP;
}
[Alignment( Boundary = 8 )]
private struct ProcessorContextX86_64 : ProcessorContext {
// public ulong RAX; // volatile register
public ulong RBX;
// public ulong RCX; // volatile register
// public ulong RDX; // volatile register
public ulong RBP;
public ulong RDI; // volatile register, but need to pass parameters
// public ulong R8; // volatile register
// public ulong R9; // volatile register
// public ulong R10; // volatile register
// public ulong R11; // volatile register
public ulong R12;
public ulong R13;
public ulong R14;
public ulong R15;
public ulong RIP;
public ulong RSP;
public ulong RSI; // volatile register, but need to pass parameters
}
private static void PrepareContext( ucontext& context, void* stack, int stackSize, Functors.Action<void*> function, void* parameter ) {
LibcApi.getcontext( context );
context.uc_link = ( ucontext* ) &FiberManager.CurrentFiber->Context;
context.uc_stack.ss_sp = stack;
context.uc_stack.ss_size = ( uint ) stackSize;
LibcApi.makecontext( context, FiberFunction, 2, function, parameter );
}
private static void PrepareContext( ProcessorContextX86_32& context, void* stack, int stackSize, Functors.Action<void*> function, void* parameter ) {
context.ESP = cast<uint>( cast<byte*>( stack ) + ( ( stackSize - 12 ) & ~0xF ) - sizeof( context.EIP ) );
context.EIP = ( uint ) bitcast<uintptr>( memberinfo( FiberFunction ).Address );
*( uint* )( context.ESP + 0 ) = ( uint ) bitcast<uintptr>( memberinfo( FiberIncorrectExitHandler ).Address );
*( uint* )( context.ESP + 4 ) = ( uint ) bitcast<uintptr>( function );
*( uint* )( context.ESP + 8 ) = ( uint ) bitcast<uintptr>( parameter );
}
private static void PrepareContext( ProcessorContextX86_64& context, void* stack, int stackSize, Functors.Action<void*> function, void* parameter ) {
context.RSP = cast<ulong>( cast<byte*>( stack ) + ( stackSize & ~0xF ) - sizeof( context.RIP ) );
context.RIP = cast<uintptr>( memberinfo( FiberFunction ).Address );
*cast<void**>( context.RSP + 0 ) = memberinfo( FiberIncorrectExitHandler ).Address;
context.RDI = bitcast<uintptr>( function );
context.RSI = bitcast<uintptr>( parameter );
}
private static void PrepareMainFiberEnvironment( FiberInfo* context ) {
}
private static void PrepareFiberEnvironment( FiberInfo* context ) {
}
private static void SwitchEnvironment( FiberInfo* context, FiberInfo* newContext ) {
}
private static void SwitchCurrentContext( ucontext& context, ucontext& newContext ) {
LibcApi.swapcontext( context, newContext );
}
private static void SwitchCurrentContext( ProcessorContext& context, ProcessorContext& newContext ) asm {
X86_32 {
mov ecx, [esp] // return address
mov eax, [esp + 4] // context
lea edx, [esp + 4] // edx = esp + 4
mov [eax + const( memberinfo( ProcessorContextX86_32.EIP ).ByteOffset )], ecx
mov [eax + const( memberinfo( ProcessorContextX86_32.EBX ).ByteOffset )], ebx
mov [eax + const( memberinfo( ProcessorContextX86_32.EBP ).ByteOffset )], ebp
mov [eax + const( memberinfo( ProcessorContextX86_32.EDI ).ByteOffset )], edi
mov [eax + const( memberinfo( ProcessorContextX86_32.ESI ).ByteOffset )], esi
mov [eax + const( memberinfo( ProcessorContextX86_32.ESP ).ByteOffset )], edx
mov eax, [esp + 8] // newContext
mov ecx, [eax + const( memberinfo( ProcessorContextX86_32.EIP ).ByteOffset )]
mov ebx, [eax + const( memberinfo( ProcessorContextX86_32.EBX ).ByteOffset )]
mov ebp, [eax + const( memberinfo( ProcessorContextX86_32.EBP ).ByteOffset )]
mov edi, [eax + const( memberinfo( ProcessorContextX86_32.EDI ).ByteOffset )]
mov esi, [eax + const( memberinfo( ProcessorContextX86_32.ESI ).ByteOffset )]
mov esp, [eax + const( memberinfo( ProcessorContextX86_32.ESP ).ByteOffset )]
jmp ecx
}
X86_64 {
mov rcx, [rsp] // return address
lea rdx, [rsp + 8] // do not include return address
// rdi - context
mov [rdi + const( memberinfo( ProcessorContextX86_64.RBX ).ByteOffset )], rbx
mov [rdi + const( memberinfo( ProcessorContextX86_64.RBP ).ByteOffset )], rbp
mov [rdi + const( memberinfo( ProcessorContextX86_64.RDI ).ByteOffset )], rdi
mov [rdi + const( memberinfo( ProcessorContextX86_64.R12 ).ByteOffset )], r12
mov [rdi + const( memberinfo( ProcessorContextX86_64.R13 ).ByteOffset )], r13
mov [rdi + const( memberinfo( ProcessorContextX86_64.R14 ).ByteOffset )], r14
mov [rdi + const( memberinfo( ProcessorContextX86_64.R15 ).ByteOffset )], r15
mov [rdi + const( memberinfo( ProcessorContextX86_64.RIP ).ByteOffset )], rcx
mov [rdi + const( memberinfo( ProcessorContextX86_64.RSP ).ByteOffset )], rdx
mov [rdi + const( memberinfo( ProcessorContextX86_64.RSI ).ByteOffset )], rsi
// rsi - newContext
mov rbx, [rsi + const( memberinfo( ProcessorContextX86_64.RBX ).ByteOffset )]
mov rbp, [rsi + const( memberinfo( ProcessorContextX86_64.RBP ).ByteOffset )]
mov rdi, [rsi + const( memberinfo( ProcessorContextX86_64.RDI ).ByteOffset )]
mov r12, [rsi + const( memberinfo( ProcessorContextX86_64.R12 ).ByteOffset )]
mov r13, [rsi + const( memberinfo( ProcessorContextX86_64.R13 ).ByteOffset )]
mov r14, [rsi + const( memberinfo( ProcessorContextX86_64.R14 ).ByteOffset )]
mov r15, [rsi + const( memberinfo( ProcessorContextX86_64.R15 ).ByteOffset )]
mov rax, [rsi + const( memberinfo( ProcessorContextX86_64.RIP ).ByteOffset )]
mov rsp, [rsi + const( memberinfo( ProcessorContextX86_64.RSP ).ByteOffset )]
mov rsi, [rsi + const( memberinfo( ProcessorContextX86_64.RSI ).ByteOffset )]
jmp rax
}
default {
Assert.NotImplemented();
}
}
}
}
}