//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity - Singularity ABI Implementation // Copyright (c) Microsoft Corporation. All rights reserved. // // File: EndpointCore.cs // // Note: // using System; using System.Threading; using System.Runtime.CompilerServices; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Security; using Microsoft.Singularity.Memory; using Microsoft.Singularity.V1.Security; using Microsoft.Singularity.V1.Threads; using Microsoft.Singularity.V1.Types; namespace Microsoft.Singularity.V1.Services { using Allocation = SharedHeapService.Allocation; using EndpointCoreImplementation = Microsoft.Singularity.Channels.EndpointCore; [CLSCompliant(false)] public enum ChannelServiceEvent : ushort { TransferBlockOwnership = 1, TransferContentOwnership = 2, } [CLSCompliant(false)] unsafe public struct EndpointCore { //////////////////////////////////////////////////////////////////// // Fields //////////////////////////////////////////////////////////////////// // // NOTE: The fields specified here must match those in: // Kernel/Singularity/Channels/EndpointCore.cs // Kernel/Singularity/V1/Services/ChannelServices.cs // Libraries/Singuarity.V1/Services/ChannelServices.cs /// /// Handle to the actual message delivery mechanism /// private DeliveryHandle deliveryHandle; /// /// Event handle in case this endpoint is part of a collection /// private AutoResetEventHandle collectionEvent; // // These "cached" fields are directly accessable by user programs, // but are not trusted by the kernel (as they could be modified by untrusted // code). The kernel relies on the trusted shadow copies held in the // deliveryImpl object, but updates these fields to reflect any changes to user // apps. // /// /// Event on which sends are signaled to this endpoint. /// The handle is owned by the kernel, since the endpoint can move. /// The kernel deallocates the handle when the channel is deallocated. /// NOTE: stays valid until the entire channel gets collected. /// private AutoResetEventHandle cachedMessageEvent; /// /// Closed flag /// private bool cachedClosed; /// /// Contains the process id of the process currently owning this end of the /// channel. /// private int cachedOwnerProcessId; /// /// Contains the channelId (positive on the EXP endpoint, negative on the imp endpoint) /// private int cachedChannelId; /// /// Whether to marshall or not /// private bool cachedMarshall; /// /// Points to the peer endpoint /// private Allocation* /*EndpointCore* opt(ExHeap)*/ cachedPeer; /// /// If true then the peer state can be queried directly from cachedPeer /// private bool peerStateValid; //////////////////////////////////////////////////////////////////// // Methods //////////////////////////////////////////////////////////////////// /// /// Used to allocate a channel endpoint. The size must be correctly computed by /// the trusted caller (currently trusted code NewChannel) /// [ExternalEntryPoint] public static Allocation* //EndpointCore* opt(ExHeap)! Allocate(uint size, SystemType st) { Allocation* ep = (Allocation*) SharedHeap.CurrentProcessSharedHeap.Allocate( size, st.id, 0, SharedHeap.CurrentProcessSharedHeap.EndpointOwnerId); if (ep == null) { throw new ApplicationException("SharedHeap.Allocate returned null"); } return ep; } /// /// Closes this end of the channel and frees associated resources, EXCEPT the block /// of memory for this endpoint. It must be released by the caller. Sing# does this /// for the programmer. /// Returns true for success, false for failure. /// [ExternalEntryPoint] public static bool Dispose(ref EndpointCore endpoint) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->Dispose(); } } /// /// Deallocates this end of the channel. If other end is also /// deallocated, the entire channel is deallocated. /// [ExternalEntryPoint] public static void Free(Allocation* /* EndpointCore* opt(ExHeap) */ endpoint) { EndpointCoreImplementation.Free((SharedHeap.Allocation*)endpoint); } /// /// Performs the initialization of the core part of each endpoint and cross links /// them to form a channel. /// [ExternalEntryPoint] public static void Connect( Allocation* /*EndpointCore* opt(ExHeap)!*/ imp, Allocation* /*EndpointCore* opt(ExHeap)!*/ exp, Allocation* /*EndpointCore* opt(ExHeap) */ ep) { EndpointCoreImplementation.Connect((SharedHeap.Allocation*)imp, (SharedHeap.Allocation*)exp, (SharedHeap.Allocation*)ep); } /// /// Indicates if this endpoint is closed /// [NoHeapAllocation] public static bool Closed(ref EndpointCore endpoint) { // kernel methods always access the shadowed copy in deliveryImpl // not the user accessable copy in EndpointCore fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->Closed(); } } /// /// Indicates if the peer endpoint is closed /// public static bool PeerClosed(ref EndpointCore ep) { // kernel methods always access the shadowed copy in deliveryImpl // not the user accessable copy in EndpointCore return PeerClosedABI(ref ep); } /// /// Indicates if the peer endpoint is closed (ABI call) /// [ExternalEntryPoint] public static bool PeerClosedABI(ref EndpointCore endpoint) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->PeerClosed(); } } /// /// Set this end to closed /// [ExternalEntryPoint] public static void Close(ref EndpointCore endpoint) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; epimp->Close(); } } /// /// The endpoint to which this endpoint is connected. /// public static Allocation* /*EndpointCore* opt(ExHeap) */ GetPeer(ref EndpointCore ep, out bool marshall) { // kernel methods always access the shadowed copy in deliveryImpl // not the user accessable copy in EndpointCore return GetPeerABI(ref ep, out marshall); } [ExternalEntryPoint] public static Allocation* /*EndpointCore* opt(ExHeap) */ GetPeerABI(ref EndpointCore endpoint, out bool marshall) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return (Allocation*) epimp->Peer(out marshall); } } /// /// The event to wait for messages on this endpoint. Used by Select. /// public static SyncHandle GetWaitHandle(ref EndpointCore endpoint) { // kernel methods always access the shadowed copy in deliveryImpl // not the user accessable copy in EndpointCore fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->GetWaitHandle(); } } /// /// Notify the owner of this endpoint that a message is ready. /// Notifies the set owner if this endpoint is part of a set. /// [ExternalEntryPoint] public static void NotifyPeer(ref EndpointCore endpoint) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; epimp->NotifyPeer(); } } /// /// Wait for a message to arrive on this endpoint. /// public static void Wait(ref EndpointCore ep) { SyncHandle.WaitOne(GetWaitHandle(ref ep)); } /// /// Transfer the given Allocation block to the target endpoint /// [ExternalEntryPoint] public static void TransferBlockOwnership(Allocation* ptr, ref EndpointCore target) { fixed (EndpointCore* ep = &target) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; EndpointCoreImplementation.TransferBlockOwnership((SharedHeap.Allocation*)ptr, ref *epimp); } } /// /// Transfer any contents that needs to be adjusted from the transferee to the target /// endpoint. Currently, this means setting the ownerProcessId of the /// transferee to that of the target. /// [ExternalEntryPoint] public static void TransferContentOwnership( ref EndpointCore transferee, ref EndpointCore target) { fixed (EndpointCore* ep1 = &transferee, ep2 = &target) { EndpointCoreImplementation* epimp1 = (EndpointCoreImplementation*)ep1; EndpointCoreImplementation* epimp2 = (EndpointCoreImplementation*)ep2; EndpointCoreImplementation.TransferContentOwnership(ref *epimp1, ref *epimp2); } } [NoHeapAllocation] public static int GetChannelID(ref EndpointCore endpoint) { // kernel methods always access the shadowed copy in deliveryImpl // not the user accessable copy in EndpointCore fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->ChannelId; } } [NoHeapAllocation] public static int GetOwnerProcessID(ref EndpointCore endpoint) { // kernel methods always access the shadowed copy in deliveryImpl // not the user accessable copy in EndpointCore fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->ProcessId; } } [NoHeapAllocation] public static int GetPeerProcessID(ref EndpointCore ep) { // kernel methods always access the shadowed copy in deliveryImpl // not the user accessable copy in EndpointCore return GetPeerProcessIDABI(ref ep); } [ExternalEntryPoint] [NoHeapAllocation] public static int GetPeerProcessIDABI(ref EndpointCore endpoint) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->PeerProcessId; } } [ExternalEntryPoint] public static void AcceptDelegation(Allocation* /*EndpointCore* opt(ExHeap)!*/ imp, Allocation* /*EndpointCore* opt(ExHeap)!*/ exp, Allocation* /*EndpointCore* opt(ExHeap)!*/ ep) { EndpointCoreImplementation.AcceptDelegation((SharedHeap.Allocation*)imp, (SharedHeap.Allocation*)exp, (SharedHeap.Allocation*)ep); } [ExternalEntryPoint] public static void EnableDelegation(ref EndpointCore endpoint, bool allowMediation) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; epimp->EnableDelegation(allowMediation); } } [ExternalEntryPoint] [NoHeapAllocation] public static PrincipalHandle GetPeerPrincipalHandle(ref EndpointCore endpoint) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->PeerPrincipalHandle; } } [ExternalEntryPoint] [NoHeapAllocation] public static PrincipalHandle GetOwnerPrincipalHandle(ref EndpointCore endpoint) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->OwnerPrincipalHandle; } } /// /// Instruct the selectable object to signal events on the given AutoResetEvent /// rather than its normal event in order to aggregate signalling into a set. /// A selectable object need only support being part of a single collection at /// any point in time. /// public static void LinkIntoCollection(ref EndpointCore ep, AutoResetEventHandle ev) { ep.collectionEvent = ev; } /// /// Instruct the selectable object to stop signalling events on the given /// AutoResetEvent. /// public static void UnlinkFromCollection(ref EndpointCore ep, AutoResetEventHandle ev) { ep.collectionEvent = new AutoResetEventHandle(); } [ExternalEntryPoint] unsafe public static void MarshallMessage(ref EndpointCore endpoint, byte* basep, byte* source, int* tagAddress, int msgSize) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; epimp->BeginUpdate(basep, source, tagAddress, msgSize); } } [ExternalEntryPoint] public static void MarshallPointer(ref EndpointCore endpoint, byte* basep, byte** target, SystemType type, byte* parent, int offset) { fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; epimp->MarshallPointer(basep, target, type, parent, offset); } } } }