diff --git a/boot/xtldr/includes/libxtos.hh b/boot/xtldr/includes/libxtos.hh index 845874b..fca9111 100644 --- a/boot/xtldr/includes/libxtos.hh +++ b/boot/xtldr/includes/libxtos.hh @@ -30,7 +30,7 @@ namespace AR public: STATIC XTAPI VOID GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType, OUT PVOID *TrampolineCode, - OUT PULONG_PTR TrampolineSize); + OUT PULONG TrampolineSize); }; } diff --git a/boot/xtldr/modules/xtos_o/amd64/memory.cc b/boot/xtldr/modules/xtos_o/amd64/memory.cc index 3755ff8..70e1bb9 100644 --- a/boot/xtldr/modules/xtos_o/amd64/memory.cc +++ b/boot/xtldr/modules/xtos_o/amd64/memory.cc @@ -116,7 +116,7 @@ Xtos::EnablePaging(IN PXTBL_PAGE_MAPPING PageMap) EFI_STATUS Status; EFI_PHYSICAL_ADDRESS TrampolineAddress; PXT_TRAMPOLINE_ENTRY TrampolineEntry; - ULONG_PTR TrampolineSize; + ULONG TrampolineSize; PVOID TrampolineCode; /* Check the configured page map level to set the LA57 state accordingly */ diff --git a/sdk/xtdk/amd64/hltypes.h b/sdk/xtdk/amd64/hltypes.h index 68cdfa2..3446d7a 100644 --- a/sdk/xtdk/amd64/hltypes.h +++ b/sdk/xtdk/amd64/hltypes.h @@ -39,6 +39,9 @@ #define APIC_VECTOR_PERF 0xFE #define APIC_VECTOR_NMI 0xFF +/* APIC SIPI vector shift */ +#define APIC_VECTOR_SIPI_SHIFT 12 + /* APIC destination formats */ #define APIC_DF_FLAT 0xFFFFFFFF #define APIC_DF_CLUSTER 0x0FFFFFFF diff --git a/sdk/xtdk/amd64/ketypes.h b/sdk/xtdk/amd64/ketypes.h index 209903d..5e8fd34 100644 --- a/sdk/xtdk/amd64/ketypes.h +++ b/sdk/xtdk/amd64/ketypes.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include ARCH_HEADER(xtstruct.h) #include ARCH_HEADER(artypes.h) @@ -132,6 +133,18 @@ #define CONTEXT_SEGMENTS (CONTEXT_ARCHITECTURE | 0x04) #define CONTEXT_FLOATING_POINT (CONTEXT_ARCHITECTURE | 0x08) #define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARCHITECTURE | 0x10) +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | \ + CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS) + +/* Clock control flags */ +#define CLOCK_QUANTUM_DECREMENT 3 + +/* DPC definitions */ +#define DPC_ADJUST_THRESHOLD 20 +#define DPC_IDEAL_RATE 20 +#define DPC_MAXIMUM_QUEUE_DEPTH 4 +#define DPC_MINIMUM_RATE 3 /* Interrupt request levels definitions */ #define PASSIVE_LEVEL 0 @@ -232,7 +245,7 @@ typedef struct _CONTEXT USHORT SegFs; USHORT SegGs; USHORT SegSs; - ULONG EFlags; + ULONG Flags; ULONG64 Dr0; ULONG64 Dr1; ULONG64 Dr2; @@ -298,6 +311,24 @@ typedef struct _KDESCRIPTOR PVOID Base; } KDESCRIPTOR, *PKDESCRIPTOR; +/* Device Queue structure definition */ +typedef struct _KDEVICE_QUEUE +{ + CSHORT Type; + CSHORT Size; + LIST_ENTRY DeviceListHead; + KSPIN_LOCK Lock; + union + { + BOOLEAN Busy; + struct + { + LONGLONG Reserved:8; + LONGLONG Hint:56; + }; + }; +} KDEVICE_QUEUE, *PKDEVICE_QUEUE; + /* Global Descriptor Table (GDT) entry union definition */ typedef struct _KGDTENTRY { @@ -560,13 +591,30 @@ typedef struct _KPROCESSOR_CONTROL_BLOCK ULONG_PTR SetMember; CPU_IDENTIFICATION CpuId; KPROCESSOR_STATE ProcessorState; + KSPIN_LOCK PrcbLock; KSPIN_LOCK_QUEUE LockQueue[MaximumLock]; + LOOKASIDE_LIST LookasideList[16]; + LOOKASIDE_LIST NonPagedLookasideList[POOL_LOOKASIDE_LISTS]; + LOOKASIDE_LIST PagedLookasideList[POOL_LOOKASIDE_LISTS]; + VOLATILE ULONG IpiFrozen; + VOLATILE LONG_PTR RequestSummary; KDPC_DATA DpcData[2]; PVOID DpcStack; + LONG MaximumDpcQueueDepth; + ULONG DpcRequestRate; + BOOLEAN DpcInterruptRequested; VOLATILE BOOLEAN DpcRoutineActive; + ULONG DpcLastCount; + VOLATILE ULONG_PTR TimerHand; VOLATILE ULONG_PTR TimerRequest; ULONG_PTR MultiThreadProcessorSet; SINGLE_LIST_ENTRY DeferredReadyListHead; + ULONG InterruptCount; + ULONG KernelTime; + ULONG UserTime; + ULONG DpcTime; + ULONG InterruptTime; + ULONG AdjustDpcThreshold; PROCESSOR_POWER_STATE PowerState; ULONG ProfilingCountdown; } KPROCESSOR_CONTROL_BLOCK, *PKPROCESSOR_CONTROL_BLOCK; diff --git a/sdk/xtdk/amd64/mmtypes.h b/sdk/xtdk/amd64/mmtypes.h index 47ae971..bdbc144 100644 --- a/sdk/xtdk/amd64/mmtypes.h +++ b/sdk/xtdk/amd64/mmtypes.h @@ -110,6 +110,10 @@ /* Highest system address */ #define MM_HIGHEST_SYSTEM_ADDRESS 0xFFFFFFFFFFFFFFFFULL +/* User probe address */ +#define MM_USER_PROBE_ADDRESS 0x00007FFFFFFF0000ULL +#define MM_USER_PROBE_LA57_ADDRESS 0x00FFFFFFFFFF0000ULL + /* Trampoline code address */ #define MM_TRAMPOLINE_ADDRESS 0x80000 @@ -348,5 +352,62 @@ typedef struct _POOL_DESCRIPTOR SIZE_T Reserved; } POOL_DESCRIPTOR, *PPOOL_DESCRIPTOR; +/* Working set list entry structure definition */ +typedef struct _MMWSLENTRY +{ + ULONG_PTR Valid:1; + ULONG_PTR LockedInWs:1; + ULONG_PTR LockedInMemory:1; + ULONG_PTR Protection:5; + ULONG_PTR Hashed:1; + ULONG_PTR Direct:1; + ULONG_PTR Age:2; + ULONG_PTR VirtualPageNumber:52; +} MMWSLENTRY, *PMMWSLENTRY; + +/* Working set free entry structure definition */ +typedef struct _MMWSLE_FREE_ENTRY +{ + ULONG MustBeZero:1; + ULONG PreviousFree:31; + LONG NextFree; +} MMWSLE_FREE_ENTRY, *PMMWSLE_FREE_ENTRY; + +/* Working set list entry union definition */ +typedef union _MMWSLE +{ + PVOID VirtualAddress; + ULONG_PTR Long; + MMWSLENTRY e1; + MMWSLE_FREE_ENTRY Free; +} MMWSLE, *PMMWSLE; + +/* Working set list structure definition */ +typedef struct _MMWSL +{ + ULONG FirstFree; + ULONG FirstDynamic; + ULONG LastEntry; + ULONG NextSlot; + PMMWSLE Wsle; + ULONG LastInitializedWsle; + ULONG NonDirectCount; + PMMWSLE_HASH HashTable; + ULONG HashTableSize; + ULONG NumberOfCommittedPageTables; + PVOID HashTableStart; + PVOID HighestPermittedHashAddress; + ULONG NumberOfImageWaiters; + ULONG VadBitMapHint; + PVOID HighestUserAddress; + ULONG MaximumUserPageTablePages; + ULONG MaximumUserPageDirectoryPages; + PULONG CommittedPageTables; + ULONG NumberOfCommittedPageDirectories; + PULONG CommittedPageDirectories; + ULONG NumberOfCommittedPageDirectoryParents; + ULONGLONG CommittedPageDirectoryParents[1]; +} MMWSL, *PMMWSL; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_AMD64_MMTYPES_H */ diff --git a/sdk/xtdk/amd64/rtltypes.h b/sdk/xtdk/amd64/rtltypes.h new file mode 100644 index 0000000..9ca5f2b --- /dev/null +++ b/sdk/xtdk/amd64/rtltypes.h @@ -0,0 +1,57 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: sdk/xtdk/amd64/rtltypes.h + * DESCRIPTION: Runtime library structures definitions for AMD64 architecture + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTDK_AMD64_RTLTYPES_H +#define __XTDK_AMD64_RTLTYPES_H + +#include +#include + + +/* C/C++ specific code */ +#ifndef __XTOS_ASSEMBLER__ + +/* Header for a sequenced single linked list union definition */ +typedef union _SINGLE_LIST_HEADER +{ + struct + { + ULONGLONG Alignment; + ULONGLONG Region; + }; + struct + { + ULONGLONG Depth:16; + ULONGLONG Sequence:9; + ULONGLONG NextEntry:39; + ULONGLONG HeaderType:1; + ULONGLONG Init:1; + ULONGLONG Reserved:59; + ULONGLONG Region:3; + } Header8; + struct + { + ULONGLONG Depth:16; + ULONGLONG Sequence:48; + ULONGLONG HeaderType:1; + ULONGLONG Init:1; + ULONGLONG Reserved:2; + ULONGLONG NextEntry:60; + } Header16; + struct + { + ULONGLONG Depth:16; + ULONGLONG Sequence:48; + ULONGLONG HeaderType:1; + ULONGLONG Reserved:3; + ULONGLONG NextEntry:60; + } Header64; +} SINGLE_LIST_HEADER, *PSINGLE_LIST_HEADER; + +#endif /* __XTOS_ASSEMBLER__ */ +#endif /* __XTDK_AMD64_RTLTYPES_H */ diff --git a/sdk/xtdk/amd64/xtstruct.h b/sdk/xtdk/amd64/xtstruct.h index 41975a1..e087880 100644 --- a/sdk/xtdk/amd64/xtstruct.h +++ b/sdk/xtdk/amd64/xtstruct.h @@ -50,6 +50,7 @@ typedef struct _HARDWARE_PTE HARDWARE_PTE, *PHARDWARE_PTE; typedef struct _HPET_REGISTERS HPET_REGISTERS, *PHPET_REGISTERS; typedef struct _IOAPIC_DATA IOAPIC_DATA, *PIOAPIC_DATA; typedef struct _KDESCRIPTOR KDESCRIPTOR, *PKDESCRIPTOR; +typedef struct _KDEVICE_QUEUE KDEVICE_QUEUE, *PKDEVICE_QUEUE; typedef struct _KEXCEPTION_FRAME KEXCEPTION_FRAME, *PKEXCEPTION_FRAME; typedef struct _KGDTENTRY KGDTENTRY, *PKGDTENTRY; typedef struct _KIDTENTRY KIDTENTRY, *PKIDTENTRY; @@ -71,6 +72,9 @@ typedef struct _MMPTE_PROTOTYPE MMPTE_PROTOTYPE, *PMMPTE_PROTOTYPE; typedef struct _MMPTE_SOFTWARE MMPTE_SOFTWARE, *PMMPTE_SOFTWARE; typedef struct _MMPTE_SUBSECTION MMPTE_SUBSECTION, *PMMPTE_SUBSECTION; typedef struct _MMPTE_TRANSITION MMPTE_TRANSITION, *PMMPTE_TRANSITION; +typedef struct _MMWSL MMWSL, *PMMWSL; +typedef struct _MMWSLE_FREE_ENTRY MMWSLE_FREE_ENTRY, *PMMWSLE_FREE_ENTRY; +typedef struct _MMWSLENTRY MMWSLENTRY, *PMMWSLENTRY; typedef struct _POOL_DESCRIPTOR POOL_DESCRIPTOR, *PPOOL_DESCRIPTOR; typedef struct _THREAD_ENVIRONMENT_BLOCK THREAD_ENVIRONMENT_BLOCK, *PTHREAD_ENVIRONMENT_BLOCK; typedef struct _TIMER_CAPABILITIES TIMER_CAPABILITIES, *PTIMER_CAPABILITIES; @@ -86,10 +90,12 @@ typedef union _MMPTE MMPDE, *PMMPDE; typedef union _MMPTE MMPPE, *PMMPPE; typedef union _MMPTE MMPTE, *PMMPTE; typedef union _MMPTE MMPXE, *PMMPXE; +typedef union _MMWSLE MMWSLE, *PMMWSLE; typedef union _PIC_I8259_ICW1 PIC_I8259_ICW1, *PPIC_I8259_ICW1; typedef union _PIC_I8259_ICW2 PIC_I8259_ICW2, *PPIC_I8259_ICW2; typedef union _PIC_I8259_ICW3 PIC_I8259_ICW3, *PPIC_I8259_ICW3; typedef union _PIC_I8259_ICW4 PIC_I8259_ICW4, *PPIC_I8259_ICW4; +typedef union _SINGLE_LIST_HEADER SINGLE_LIST_HEADER, *PSINGLE_LIST_HEADER; #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_AMD64_XTSTRUCT_H */ diff --git a/sdk/xtdk/bltypes.h b/sdk/xtdk/bltypes.h index 1d2b487..bed3d38 100644 --- a/sdk/xtdk/bltypes.h +++ b/sdk/xtdk/bltypes.h @@ -57,7 +57,7 @@ typedef EFI_STATUS (XTCDECL *PBL_ALLOCATE_PAGES)(IN EFI_ALLOCATE_TYPE Allocation typedef EFI_STATUS (XTCDECL *PBL_ALLOCATE_POOL)(IN UINT_PTR Size, OUT PVOID *Memory); typedef EFI_STATUS (XTCDECL *PBL_BOOTMENU_INITIALIZE_OS_LIST)(IN ULONG MaxNameLength, OUT PXTBL_BOOTMENU_ITEM *MenuEntries, OUT PULONG EntriesCount, OUT PULONG DefaultId); typedef BOOLEAN (XTCDECL *PBL_BOOTUTILS_GET_BOOLEAN_PARAMETER)(IN PCWSTR Parameters, IN PCWSTR Needle); -typedef VOID (XTAPI *PBL_BOOTUTILS_GET_TRAMPOLINE_INFORMATION)(IN TRAMPOLINE_TYPE TrampolineType, OUT PVOID *TrampolineCode, OUT PULONG_PTR TrampolineSize); +typedef VOID (XTAPI *PBL_BOOTUTILS_GET_TRAMPOLINE_INFORMATION)(IN TRAMPOLINE_TYPE TrampolineType, OUT PVOID *TrampolineCode, OUT PULONG TrampolineSize); typedef EFI_STATUS (XTCDECL *PBL_BUILD_PAGE_MAP)(IN PXTBL_PAGE_MAPPING PageMap, IN ULONG_PTR SelfMapAddress); typedef EFI_STATUS (XTCDECL *PBL_COMMIT_PAGE_MAP)(IN PXTBL_PAGE_MAPPING PageMap); typedef EFI_STATUS (XTCDECL *PBL_CLOSE_VOLUME)(IN PEFI_HANDLE VolumeHandle); diff --git a/sdk/xtdk/cmtypes.h b/sdk/xtdk/cmtypes.h new file mode 100644 index 0000000..f5909bf --- /dev/null +++ b/sdk/xtdk/cmtypes.h @@ -0,0 +1,135 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: sdk/xtdk/cmtypes.h + * DESCRIPTION: Configuration Manager structures definitions + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTDK_CMTYPES_H +#define __XTDK_CMTYPES_H + +#include +#include +#include + + +/* C/C++ specific code */ +#ifndef __XTOS_ASSEMBLER__ + +/* Partial resource descriptor */ +typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR +{ + UCHAR Type; + UCHAR ShareDisposition; + USHORT Flags; + union + { + struct + { + PHYSICAL_ADDRESS Start; + ULONG Length; + } Generic; + struct + { + PHYSICAL_ADDRESS Start; + ULONG Length; + } Port; + struct + { + USHORT Level; + USHORT Group; + ULONG Vector; + PKAFFINITY_MAP Affinity; + } Interrupt; + struct + { + union + { + struct + { + USHORT Group; + USHORT MessageCount; + ULONG Vector; + PKAFFINITY_MAP Affinity; + } Raw; + struct + { + USHORT Level; + USHORT Group; + ULONG Vector; + PKAFFINITY_MAP Affinity; + } Translated; + }; + } MessageInterrupt; + struct + { + PHYSICAL_ADDRESS Start; + ULONG Length; + } Memory; + struct + { + ULONG Channel; + ULONG Port; + ULONG Reserved1; + } Dma; + struct + { + ULONG Data[3]; + } DevicePrivate; + struct + { + ULONG Start; + ULONG Length; + ULONG Reserved; + } BusNumber; + struct + { + ULONG DataSize; + ULONG Reserved1; + ULONG Reserved2; + } DeviceSpecificData; + struct + { + PHYSICAL_ADDRESS Start; + ULONG Length40; + } Memory40; + struct + { + PHYSICAL_ADDRESS Start; + ULONG Length48; + } Memory48; + struct + { + PHYSICAL_ADDRESS Start; + ULONG Length64; + } Memory64; + } u; +} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR; + +/* Partial resource list */ +typedef struct _CM_PARTIAL_RESOURCE_LIST +{ + USHORT Version; + USHORT Revision; + ULONG Count; + CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]; +} CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST; + +/* Full resource descriptor */ +typedef struct _CM_FULL_RESOURCE_DESCRIPTOR +{ + INTERFACE_TYPE InterfaceType; + ULONG BusNumber; + CM_PARTIAL_RESOURCE_LIST PartialResourceList; +} CM_FULL_RESOURCE_DESCRIPTOR, *PCM_FULL_RESOURCE_DESCRIPTOR; + +/* Full resource list */ +typedef struct _CM_RESOURCE_LIST +{ + ULONG Count; + CM_FULL_RESOURCE_DESCRIPTOR List[1]; +} CM_RESOURCE_LIST, *PCM_RESOURCE_LIST; + +#endif /* __XTOS_ASSEMBLER__ */ +#endif /* __XTDK_CMTYPES_H */ diff --git a/sdk/xtdk/extypes.h b/sdk/xtdk/extypes.h index 8e66c94..351ab16 100644 --- a/sdk/xtdk/extypes.h +++ b/sdk/xtdk/extypes.h @@ -17,18 +17,75 @@ /* Rundown protection flags */ #define EX_RUNDOWN_ACTIVE 0x1 +/* Number of lookaside lists */ +#define POOL_LOOKASIDE_LISTS 32 /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ -/* Executive rundown protection structure definition */ -typedef struct _EX_RUNDOWN_REFERENCE +/* Kernel routine callbacks */ +typedef XTSTATUS (XTAPI *PALLOCATE_FUNCTION)(IN MMPOOL_TYPE PoolType, IN SIZE_T Bytes, OUT PVOID *Memory, IN ULONG Tag); +typedef XTSTATUS (XTAPI *PALLOCATE_FUNCTION_EX)(IN MMPOOL_TYPE PoolType, IN SIZE_T Bytes, OUT PVOID *Memory, IN ULONG Tag, IN PLOOKASIDE_LIST_EX Lookaside); +typedef XTSTATUS (XTAPI *PFREE_FUNCTION)(IN PVOID Buffer); +typedef XTSTATUS (XTAPI *PFREE_FUNCTION_EX)(IN PVOID Buffer, IN OUT PLOOKASIDE_LIST_EX Lookaside); +typedef VOID (XTAPI *PWORKER_THREAD_ROUTINE)(IN PVOID Parameter); + +/* Work queue types */ +typedef enum _WORK_QUEUE_TYPE { + CriticalWorkQueue, + DelayedWorkQueue, + HyperCriticalWorkQueue, + NormalWorkQueue, + BackgroundWorkQueue, + RealTimeWorkQueue, + SuperCriticalWorkQueue, + MaximumWorkQueue, +} WORK_QUEUE_TYPE, *PWORK_QUEUE_TYPE; + +/* Owner entry structure definition */ +typedef struct _OWNER_ENTRY +{ + ULONG_PTR OwnerThread; union { - ULONG_PTR Count; - PVOID Ptr; + struct + { + ULONG IoPriorityBoosted:1; + ULONG OwnerReferenced:1; + ULONG OwnerCount:30; + }; + ULONG TableSize; }; +} OWNER_ENTRY, *POWNER_ENTRY; + +/* Exclusive resource structure definition */ +typedef struct _ERESOURCE +{ + LIST_ENTRY SystemResourcesList; + POWNER_ENTRY OwnerTable; + SHORT ActiveCount; + USHORT Flag; + VOLATILE PKSEMAPHORE SharedWaiters; + VOLATILE PKEVENT ExclusiveWaiters; + OWNER_ENTRY OwnerEntry; + ULONG ActiveEntries; + ULONG ContentionCount; + ULONG NumberOfSharedWaiters; + ULONG NumberOfExclusiveWaiters; + union + { + PVOID Address; + ULONG_PTR CreatorBackTraceIndex; + }; + KSPIN_LOCK SpinLock; +} ERESOURCE, *PERESOURCE; + +/* Executive rundown protection structure definition */ +typedef union _EX_RUNDOWN_REFERENCE +{ + ULONG_PTR Count; + PVOID Ptr; } EX_RUNDOWN_REFERENCE, *PEX_RUNDOWN_REFERENCE; /* Executive rundown wait block definition */ @@ -38,5 +95,82 @@ typedef struct _EX_RUNDOWN_WAIT_BLOCK KEVENT WakeEvent; } EX_RUNDOWN_WAIT_BLOCK, *PEX_RUNDOWN_WAIT_BLOCK; +/* Lookaside list structure definition */ +typedef struct _GENERAL_LOOKASIDE +{ + union + { + SINGLE_LIST_HEADER ListHead; + SINGLE_LIST_ENTRY SingleListHead; + }; + USHORT Depth; + USHORT MaximumDepth; + ULONG TotalAllocates; + union + { + ULONG AllocateMisses; + ULONG AllocateHits; + }; + ULONG TotalFrees; + union { + ULONG FreeMisses; + ULONG FreeHits; + }; + MMPOOL_TYPE Type; + ULONG Tag; + ULONG Size; + union + { + PALLOCATE_FUNCTION_EX AllocateEx; + PALLOCATE_FUNCTION Allocate; + }; + union + { + PFREE_FUNCTION_EX FreeEx; + PFREE_FUNCTION Free; + }; + LIST_ENTRY ListEntry; + ULONG LastTotalAllocates; + union + { + ULONG LastAllocateMisses; + ULONG LastAllocateHits; + }; + ULONG Future[2]; +} GENERAL_LOOKASIDE, *PGENERAL_LOOKASIDE; + +/* Lookaside list pointers structure definition */ +typedef struct _LOOKASIDE_LIST +{ + PGENERAL_LOOKASIDE Local; + PGENERAL_LOOKASIDE Global; +} LOOKASIDE_LIST, *PLOOKASIDE_LIST; + +/* Lookaside list extended structure definition */ +typedef struct _LOOKASIDE_LIST_EX +{ + GENERAL_LOOKASIDE Global; +} LOOKASIDE_LIST_EX, *PLOOKASIDE_LIST_EX; + +/* Non-paged lookaside list structure definition */ +typedef struct _NONPAGED_LOOKASIDE_LIST +{ + GENERAL_LOOKASIDE Global; +} NONPAGED_LOOKASIDE_LIST, *PNONPAGED_LOOKASIDE_LIST; + +/* Paged lookaside list structure definition */ +typedef struct _PAGED_LOOKASIDE_LIST +{ + GENERAL_LOOKASIDE Global; +} PAGED_LOOKASIDE_LIST, *PPAGED_LOOKASIDE_LIST; + +/* Work queue item structure definition */ +typedef struct _WORK_QUEUE_ITEM +{ + LIST_ENTRY List; + PWORKER_THREAD_ROUTINE WorkerRoutine; + VOLATILE PVOID Parameter; +} WORK_QUEUE_ITEM, *PWORK_QUEUE_ITEM; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_EXTYPES_H */ diff --git a/sdk/xtdk/hltypes.h b/sdk/xtdk/hltypes.h index 2bb4c83..805d8ef 100644 --- a/sdk/xtdk/hltypes.h +++ b/sdk/xtdk/hltypes.h @@ -215,6 +215,30 @@ typedef ULONG (XTAPI *PHALP_QUERY_TIME_DELTA)(VOID); typedef ULONG (XTAPI *PHALP_SET_CLOCK_RATE)(IN ULONG Increment); typedef VOID (XTAPI *PHALP_STALL_EXECUTION)(IN ULONG MicroSeconds); +/* Interface types */ +typedef enum _INTERFACE_TYPE +{ + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + Vmcs, + MaximumInterfaceType +} INTERFACE_TYPE, *PINTERFACE_TYPE; + /* Generic Address structure */ typedef struct _GENERIC_ADDRESS { diff --git a/sdk/xtdk/i686/hltypes.h b/sdk/xtdk/i686/hltypes.h index 898ed95..1b61693 100644 --- a/sdk/xtdk/i686/hltypes.h +++ b/sdk/xtdk/i686/hltypes.h @@ -45,6 +45,9 @@ #define APIC_VECTOR_PERF 0xFE #define APIC_VECTOR_NMI 0xFF +/* APIC SIPI vector shift */ +#define APIC_VECTOR_SIPI_SHIFT 12 + /* APIC destination formats */ #define APIC_DF_FLAT 0xFFFFFFFF #define APIC_DF_CLUSTER 0x0FFFFFFF diff --git a/sdk/xtdk/i686/ketypes.h b/sdk/xtdk/i686/ketypes.h index 39b0ee4..3e5c174 100644 --- a/sdk/xtdk/i686/ketypes.h +++ b/sdk/xtdk/i686/ketypes.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include ARCH_HEADER(xtstruct.h) #include ARCH_HEADER(artypes.h) @@ -154,6 +155,19 @@ #define CONTEXT_FLOATING_POINT (CONTEXT_ARCHITECTURE | 0x08) #define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARCHITECTURE | 0x10) #define CONTEXT_EXTENDED_REGISTERS (CONTEXT_ARCHITECTURE | 0x20) +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) +#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | \ + CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | \ + CONTEXT_EXTENDED_REGISTERS) + +/* Clock control flags */ +#define CLOCK_QUANTUM_DECREMENT 3 + +/* DPC definitions */ +#define DPC_ADJUST_THRESHOLD 20 +#define DPC_IDEAL_RATE 20 +#define DPC_MAXIMUM_QUEUE_DEPTH 4 +#define DPC_MINIMUM_RATE 3 /* Interrupt request levels definitions */ #define PASSIVE_LEVEL 0 @@ -291,7 +305,7 @@ typedef struct _CONTEXT ULONG Ebp; ULONG Eip; ULONG SegCs; - ULONG EFlags; + ULONG Flags; ULONG Esp; ULONG SegSs; UCHAR ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; @@ -305,6 +319,16 @@ typedef struct _KDESCRIPTOR PVOID Base; } KDESCRIPTOR, *PKDESCRIPTOR; +/* Device Queue structure definition */ +typedef struct _KDEVICE_QUEUE +{ + CSHORT Type; + CSHORT Size; + LIST_ENTRY DeviceListHead; + KSPIN_LOCK Lock; + BOOLEAN Busy; +} KDEVICE_QUEUE, *PKDEVICE_QUEUE; + /* Global Descriptor Table (GDT) entry structure definition */ typedef struct _KGDTENTRY { @@ -415,18 +439,19 @@ typedef struct _KEXCEPTION_FRAME /* Thread start frame definition */ typedef struct _KSTART_FRAME { - PKSYSTEM_ROUTINE SystemRoutine; - PKSTART_ROUTINE StartRoutine; - PVOID StartContext; + ULONG P1Home; + ULONG P2Home; + ULONG P3Home; BOOLEAN UserMode; + ULONG Return; } KSTART_FRAME, *PKSTART_FRAME; /* Switch frame definition */ typedef struct _KSWITCH_FRAME { PVOID ExceptionList; - BOOLEAN ApcBypassDisabled; - PVOID Return; + KRUNLEVEL ApcBypass; + ULONG Return; } KSWITCH_FRAME, *PKSWITCH_FRAME; /* Trap frame definition */ @@ -519,13 +544,30 @@ typedef struct _KPROCESSOR_CONTROL_BLOCK ULONG_PTR SetMember; CPU_IDENTIFICATION CpuId; KPROCESSOR_STATE ProcessorState; + KSPIN_LOCK PrcbLock; KSPIN_LOCK_QUEUE LockQueue[MaximumLock]; + LOOKASIDE_LIST LookasideList[16]; + LOOKASIDE_LIST NonPagedLookasideList[POOL_LOOKASIDE_LISTS]; + LOOKASIDE_LIST PagedLookasideList[POOL_LOOKASIDE_LISTS]; ULONG_PTR MultiThreadProcessorSet; + VOLATILE ULONG IpiFrozen; + VOLATILE LONG_PTR RequestSummary; KDPC_DATA DpcData[2]; PVOID DpcStack; + LONG MaximumDpcQueueDepth; + ULONG DpcRequestRate; + BOOLEAN DpcInterruptRequested; VOLATILE BOOLEAN DpcRoutineActive; + ULONG DpcLastCount; + VOLATILE ULONG_PTR TimerHand; VOLATILE ULONG_PTR TimerRequest; SINGLE_LIST_ENTRY DeferredReadyListHead; + ULONG InterruptCount; + ULONG KernelTime; + ULONG UserTime; + ULONG DpcTime; + ULONG InterruptTime; + ULONG AdjustDpcThreshold; PROCESSOR_POWER_STATE PowerState; ULONG ProfilingCountdown; } KPROCESSOR_CONTROL_BLOCK, *PKPROCESSOR_CONTROL_BLOCK; diff --git a/sdk/xtdk/i686/mmtypes.h b/sdk/xtdk/i686/mmtypes.h index 110cf6a..0f80573 100644 --- a/sdk/xtdk/i686/mmtypes.h +++ b/sdk/xtdk/i686/mmtypes.h @@ -108,6 +108,9 @@ /* Highest system address */ #define MM_HIGHEST_SYSTEM_ADDRESS 0xFFFFFFFF +/* User probe address */ +#define MM_USER_PROBE_ADDRESS 0x7FFF0000 + /* Trampoline code address */ #define MM_TRAMPOLINE_ADDRESS 0x80000 @@ -441,5 +444,56 @@ typedef struct _POOL_DESCRIPTOR SIZE_T Reserved; } POOL_DESCRIPTOR, *PPOOL_DESCRIPTOR; +/* Working set list entry structure definition */ +typedef struct _MMWSLENTRY +{ + ULONG_PTR Valid:1; + ULONG_PTR LockedInWs:1; + ULONG_PTR LockedInMemory:1; + ULONG_PTR Protection:5; + ULONG_PTR Hashed:1; + ULONG_PTR Direct:1; + ULONG_PTR Age:2; + ULONG_PTR VirtualPageNumber:20; +} MMWSLENTRY, *PMMWSLENTRY; + +/* Working set free entry structure definition */ +typedef struct _MMWSLE_FREE_ENTRY +{ + ULONG MustBeZero:1; + ULONG PreviousFree:11; + LONG NextFree:20; +} MMWSLE_FREE_ENTRY, *PMMWSLE_FREE_ENTRY; + +/* Working set list entry union definition */ +typedef union _MMWSLE +{ + PVOID VirtualAddress; + ULONG_PTR Long; + MMWSLENTRY e1; + MMWSLE_FREE_ENTRY Free; +} MMWSLE, *PMMWSLE; + +/* Working set list structure definition */ +typedef struct _MMWSL +{ + ULONG FirstFree; + ULONG FirstDynamic; + ULONG LastEntry; + ULONG NextSlot; + PMMWSLE Wsle; + ULONG LastInitializedWsle; + ULONG NonDirectCount; + PMMWSLE_HASH HashTable; + ULONG HashTableSize; + ULONG NumberOfCommittedPageTables; + PVOID HashTableStart; + PVOID HighestPermittedHashAddress; + ULONG NumberOfImageWaiters; + ULONG VadBitMapHint; + USHORT UsedPageTableEntries[768]; + ULONG CommittedPageTables[24]; +} MMWSL, *PMMWSL; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_I686_MMTYPES_H */ diff --git a/sdk/xtdk/i686/rtltypes.h b/sdk/xtdk/i686/rtltypes.h new file mode 100644 index 0000000..a8407ed --- /dev/null +++ b/sdk/xtdk/i686/rtltypes.h @@ -0,0 +1,32 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: sdk/xtdk/amd64/rtltypes.h + * DESCRIPTION: Runtime library structures definitions for i686 architecture + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTDK_I686_RTLTYPES_H +#define __XTDK_I686_RTLTYPES_H + +#include +#include + + +/* C/C++ specific code */ +#ifndef __XTOS_ASSEMBLER__ + +/* Header for a sequenced single linked list union definition */ +typedef union _SINGLE_LIST_HEADER +{ + ULONGLONG Alignment; + struct + { + SINGLE_LIST_ENTRY Next; + USHORT Depth; + USHORT Sequence; + }; +} SINGLE_LIST_HEADER, *PSINGLE_LIST_HEADER; + +#endif /* __XTOS_ASSEMBLER__ */ +#endif /* __XTDK_I686_RTLTYPES_H */ diff --git a/sdk/xtdk/i686/xtstruct.h b/sdk/xtdk/i686/xtstruct.h index eb12ff2..5644a28 100644 --- a/sdk/xtdk/i686/xtstruct.h +++ b/sdk/xtdk/i686/xtstruct.h @@ -53,6 +53,7 @@ typedef struct _HARDWARE_MODERN_PTE HARDWARE_MODERN_PTE, *PHARDWARE_MODERN_PTE; typedef struct _HPET_REGISTERS HPET_REGISTERS, *PHPET_REGISTERS; typedef struct _IOAPIC_DATA IOAPIC_DATA, *PIOAPIC_DATA; typedef struct _KDESCRIPTOR KDESCRIPTOR, *PKDESCRIPTOR; +typedef struct _KDEVICE_QUEUE KDEVICE_QUEUE, *PKDEVICE_QUEUE; typedef struct _KEXCEPTION_FRAME KEXCEPTION_FRAME, *PKEXCEPTION_FRAME; typedef struct _KGDTENTRY KGDTENTRY, *PKGDTENTRY; typedef struct _KIDTENTRY KIDTENTRY, *PKIDTENTRY; @@ -80,6 +81,9 @@ typedef struct _MMPML3_PTE_PROTOTYPE MMPML3_PTE_PROTOTYPE, *PMMPML3_PTE_PROTOTYP typedef struct _MMPML3_PTE_SOFTWARE MMPML3_PTE_SOFTWARE, *PMMPML3_PTE_SOFTWARE; typedef struct _MMPML3_PTE_SUBSECTION MMPML3_PTE_SUBSECTION, *PMMPML3_PTE_SUBSECTION; typedef struct _MMPML3_PTE_TRANSITION MMPML3_PTE_TRANSITION, *PMMPML3_PTE_TRANSITION; +typedef struct _MMWSL MMWSL, *PMMWSL; +typedef struct _MMWSLE_FREE_ENTRY MMWSLE_FREE_ENTRY, *PMMWSLE_FREE_ENTRY; +typedef struct _MMWSLENTRY MMWSLENTRY, *PMMWSLENTRY; typedef struct _POOL_DESCRIPTOR POOL_DESCRIPTOR, *PPOOL_DESCRIPTOR; typedef struct _THREAD_ENVIRONMENT_BLOCK THREAD_ENVIRONMENT_BLOCK, *PTHREAD_ENVIRONMENT_BLOCK; typedef struct _TIMER_CAPABILITIES TIMER_CAPABILITIES, *PTIMER_CAPABILITIES; @@ -96,10 +100,12 @@ typedef union _MMPML3_PTE MMPML3_PTE, *PMMPML3_PTE; typedef union _MMPTE MMPDE, *PMMPDE; typedef union _MMPTE MMPPE, *PMMPPE; typedef union _MMPTE MMPTE, *PMMPTE; +typedef union _MMWSLE MMWSLE, *PMMWSLE; typedef union _PIC_I8259_ICW1 PIC_I8259_ICW1, *PPIC_I8259_ICW1; typedef union _PIC_I8259_ICW2 PIC_I8259_ICW2, *PPIC_I8259_ICW2; typedef union _PIC_I8259_ICW3 PIC_I8259_ICW3, *PPIC_I8259_ICW3; typedef union _PIC_I8259_ICW4 PIC_I8259_ICW4, *PPIC_I8259_ICW4; +typedef union _SINGLE_LIST_HEADER SINGLE_LIST_HEADER, *PSINGLE_LIST_HEADER; #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_I686_XTSTRUCT_H */ diff --git a/sdk/xtdk/iotypes.h b/sdk/xtdk/iotypes.h index 071edb2..4e3a377 100644 --- a/sdk/xtdk/iotypes.h +++ b/sdk/xtdk/iotypes.h @@ -4,14 +4,55 @@ * FILE: sdk/xtdk/iotypes.h * DESCRIPTION: I/O related type definitions * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #ifndef __XTDK_IOTYPES_H #define __XTDK_IOTYPES_H #include +#include +#include +#include ARCH_HEADER(xtstruct.h) +#include ARCH_HEADER(ketypes.h) +/* Maximum volume label length */ +#define IO_MAXIMUM_VOLUME_LABEL_LENGTH (32 * sizeof(WCHAR)) + +/* I/O Request Packet function codes */ +#define IRP_FC_CREATE 0x00 +#define IRP_FC_CREATE_NAMED_PIPE 0x01 +#define IRP_FC_CLOSE 0x02 +#define IRP_FC_READ 0x03 +#define IRP_FC_WRITE 0x04 +#define IRP_FC_QUERY_INFORMATION 0x05 +#define IRP_FC_SET_INFORMATION 0x06 +#define IRP_FC_QUERY_EA 0x07 +#define IRP_FC_SET_EA 0x08 +#define IRP_FC_FLUSH_BUFFERS 0x09 +#define IRP_FC_QUERY_VOLUME_INFORMATION 0x0a +#define IRP_FC_SET_VOLUME_INFORMATION 0x0b +#define IRP_FC_DIRECTORY_CONTROL 0x0c +#define IRP_FC_FILE_SYSTEM_CONTROL 0x0d +#define IRP_FC_DEVICE_CONTROL 0x0e +#define IRP_FC_INTERNAL_DEVICE_CONTROL 0x0f +#define IRP_FC_SCSI 0x0f +#define IRP_FC_SHUTDOWN 0x10 +#define IRP_FC_LOCK_CONTROL 0x11 +#define IRP_FC_CLEANUP 0x12 +#define IRP_FC_CREATE_MAILSLOT 0x13 +#define IRP_FC_QUERY_SECURITY 0x14 +#define IRP_FC_SET_SECURITY 0x15 +#define IRP_FC_POWER 0x16 +#define IRP_FC_SYSTEM_CONTROL 0x17 +#define IRP_FC_DEVICE_CHANGE 0x18 +#define IRP_FC_QUERY_QUOTA 0x19 +#define IRP_FC_SET_QUOTA 0x1a +#define IRP_FC_PNP 0x1b +#define IRP_FC_PNP_POWER 0x1b +#define IRP_FC_MAXIMUM_FUNCTION 0x1b + /* Number of PCI base address registers */ #define PCI_TYPE0_ADDRESSES 6 #define PCI_TYPE1_ADDRESSES 2 @@ -62,6 +103,937 @@ /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ +/* I/O routine callbacks */ +typedef XTSTATUS (XTAPI *PDRIVER_ADD_DEVICE)(IN PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject); +typedef VOID (XTAPI *PDRIVER_CANCEL)(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); +typedef IO_ALLOCATION_ACTION (XTAPI *PDRIVER_CONTROL)(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context); +typedef XTSTATUS (XTAPI *PDRIVER_DISPATCH)(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); +typedef XTSTATUS (XTAPI *PDRIVER_INITIALIZE)(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath); +typedef VOID (XTAPI *PDRIVER_STARTIO)(IN OUT PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); +typedef VOID (XTAPI *PDRIVER_UNLOAD)(IN PDRIVER_OBJECT DriverObject); +typedef VOID (XTAPI *PFAST_IO_ACQUIRE_FILE)(IN PFILE_OBJECT FileObject); +typedef XTSTATUS (XTAPI *PFAST_IO_ACQUIRE_FOR_CCFLUSH)(IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject); +typedef XTSTATUS (XTAPI *PFAST_IO_ACQUIRE_FOR_MOD_WRITE)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER EndingOffset, OUT PERESOURCE *ResourceToRelease, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_CHECK_IF_POSSIBLE)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN BOOLEAN CheckForReadOperation, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_DEVICE_CONTROL)(IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN PVOID InputBuffer, IN ULONG InputBufferLength, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength, IN ULONG IoControlCode, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef VOID (XTAPI *PFAST_IO_DETACH_DEVICE)(IN PDEVICE_OBJECT SourceDevice, IN PDEVICE_OBJECT TargetDevice); +typedef BOOLEAN (XTAPI *PFAST_IO_LOCK)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, IN PEPROCESS ProcessId, IN ULONG Key, IN BOOLEAN FailImmediately, IN BOOLEAN ExclusiveLock, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_MDL_READ)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_MDL_READ_COMPLETE)(IN PFILE_OBJECT FileObject, IN PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_MDL_READ_COMPLETE_COMPRESSED)(IN PFILE_OBJECT FileObject, IN PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_MDL_WRITE_COMPLETE)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_MDL_WRITE_COMPLETE_COMPRESSED)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_PREPARE_MDL_WRITE)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_QUERY_BASIC_INFO)(IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, OUT PFILE_BASIC_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_QUERY_NETWORK_OPEN_INFO)(IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_QUERY_OPEN)(IN OUT PIRP Irp, OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_QUERY_STANDARD_INFO)(IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, OUT PFILE_STANDARD_INFORMATION Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_READ)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_READ_COMPRESSED)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, OUT PVOID Buffer, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus, OUT PCOMPRESSED_DATA_INFO CompressedDataInfo, IN ULONG CompressedDataInfoLength, IN PDEVICE_OBJECT DeviceObject); +typedef VOID (XTAPI *PFAST_IO_RELEASE_FILE)(IN PFILE_OBJECT FileObject); +typedef XTSTATUS (XTAPI *PFAST_IO_RELEASE_FOR_CCFLUSH)(IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject); +typedef XTSTATUS (XTAPI *PFAST_IO_RELEASE_FOR_MOD_WRITE)(IN PFILE_OBJECT FileObject, IN PERESOURCE ResourceToRelease, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_UNLOCK_ALL)(IN PFILE_OBJECT FileObject, IN PEPROCESS ProcessId, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_UNLOCK_ALL_BY_KEY)(IN PFILE_OBJECT FileObject, IN PVOID ProcessId, IN ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_UNLOCK_SINGLE)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, IN PEPROCESS ProcessId, IN ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_WRITE)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +typedef BOOLEAN (XTAPI *PFAST_IO_WRITE_COMPRESSED)(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG LockKey, IN PVOID Buffer, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus, IN PCOMPRESSED_DATA_INFO CompressedDataInfo, IN ULONG CompressedDataInfoLength, IN PDEVICE_OBJECT DeviceObject); +typedef VOID (XTAPI *PINTERFACE_DEREFERENCE)(IN PVOID Context); +typedef VOID (XTAPI *PINTERFACE_REFERENCE)(IN PVOID Context); +typedef VOID (XTAPI *PIO_APC_ROUTINE)(IN PVOID ApcContext, IN PIO_STATUS_BLOCK IoStatusBlock, IN ULONG Reserved); +typedef XTSTATUS (XTAPI *PIO_COMPLETION_ROUTINE)(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context); +typedef VOID (XTAPI *PIO_TIMER_ROUTINE)(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context); + +/* Bus Query ID Type */ +typedef enum _BUS_QUERY_ID_TYPE +{ + BusQueryDeviceID, + BusQueryHardwareIDs, + BusQueryCompatibleIDs, + BusQueryInstanceID, + BusQueryDeviceSerialNumber, + BusQueryContainerID +} BUS_QUERY_ID_TYPE, *PBUS_QUERY_ID_TYPE; + +/* Device Relation Type */ +typedef enum _DEVICE_RELATION_TYPE +{ + BusRelations, + EjectionRelations, + PowerRelations, + RemovalRelations, + TargetDeviceRelation, + SingleBusRelations, + TransportRelations +} DEVICE_RELATION_TYPE, *PDEVICE_RELATION_TYPE; + +/* Device Text Type */ +typedef enum _DEVICE_TEXT_TYPE +{ + DeviceTextDescription, + DeviceTextLocationInformation +} DEVICE_TEXT_TYPE, *PDEVICE_TEXT_TYPE; + +/* Device Usage Notification Type */ +typedef enum _DEVICE_USAGE_NOTIFICATION_TYPE +{ + DeviceUsageTypeUndefined, + DeviceUsageTypePaging, + DeviceUsageTypeHibernation, + DeviceUsageTypeDumpFile, + DeviceUsageTypeBoot, + DeviceUsageTypePostDisplay, + DeviceUsageTypeGuestAssigned, +} DEVICE_USAGE_NOTIFICATION_TYPE; + +/* Directory Notify Information Class */ +typedef enum _DIRECTORY_NOTIFY_INFORMATION_CLASS +{ + DirectoryNotifyInformation = 1, + DirectoryNotifyExtendedInformation +} DIRECTORY_NOTIFY_INFORMATION_CLASS, *PDIRECTORY_NOTIFY_INFORMATION_CLASS; + +/* File Information Class */ +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, + FileIsRemoteDeviceInformation, + FileAttributeCacheInformation, + FileNumaNodeInformation, + FileStandardLinkInformation, + FileRemoteProtocolInformation, + FileRenameInformationBypassAccessCheck, + FileLinkInformationBypassAccessCheck, + FileVolumeNameInformation, + FileIdInformation, + FileIdExtdDirectoryInformation, + FileReplaceCompletionInformation, + FileHardLinkFullIdInformation, + FileIdExtdBothDirectoryInformation, + FileDispositionInformationEx, + FileRenameInformationEx , + FileRenameInformationExBypassAccessCheck, + FileDesiredStorageClassInformation, + FileStatInformation, + FileMemoryPartitionInformation, + FileStatLxInformation, + FileCaseSensitiveInformation, + FileLinkInformationEx, + FileLinkInformationExBypassAccessCheck, + FileStorageReserveIdInformation, + FileCaseSensitiveInformationForceAccessCheck, + FileKnownFolderInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +/* File System Information Class */ +typedef enum _FS_INFORMATION_CLASS +{ + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsFullSizeInformation, + FileFsObjectIdInformation, + FileFsDriverPathInformation, + FileFsVolumeFlagsInformation, + FileFsMaximumInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +/* IO allocation actions */ +typedef enum _IO_ALLOCATION_ACTION +{ + KeepObject = 1, + DeallocateObject, + DeallocateObjectKeepRegisters +} IO_ALLOCATION_ACTION, *PIO_ALLOCATION_ACTION; + +/* Interrupt Request Device Policy */ +typedef enum _IRQ_DEVICE_POLICY +{ + IrqPolicyMachineDefault = 0, + IrqPolicyAllCloseProcessors, + IrqPolicyOneCloseProcessor, + IrqPolicyAllProcessorsInMachine, + IrqPolicySpecifiedProcessors, + IrqPolicySpreadMessagesAcrossAllProcessors +} IRQ_DEVICE_POLICY, *PIRQ_DEVICE_POLICY; + +/* Interrupt Request Priority */ +typedef enum _IRQ_PRIORITY +{ + IrqPriorityUndefined = 0, + IrqPriorityLow, + IrqPriorityNormal, + IrqPriorityHigh +} IRQ_PRIORITY, *PIRQ_PRIORITY; + +/* Wait context block structure definition */ +typedef struct _WAIT_CONTEXT_BLOCK +{ + KDEVICE_QUEUE_ENTRY WaitQueueEntry; + PDRIVER_CONTROL DeviceRoutine; + PVOID DeviceContext; + ULONG NumberOfMapRegisters; + PVOID DeviceObject; + PVOID CurrentIrp; + PKDPC BufferChainingDpc; +} WAIT_CONTEXT_BLOCK, *PWAIT_CONTEXT_BLOCK; + +/* Client ID structure */ +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +/* Device Capabilities structure definition */ +typedef struct _DEVICE_CAPABILITIES +{ + USHORT Size; + USHORT Version; + ULONG DeviceD1:1; + ULONG DeviceD2:1; + ULONG LockSupported:1; + ULONG EjectSupported:1; + ULONG Removable:1; + ULONG DockDevice:1; + ULONG UniqueID:1; + ULONG SilentInstall:1; + ULONG RawDeviceOK:1; + ULONG SurpriseRemovalOK:1; + ULONG WakeFromD0:1; + ULONG WakeFromD1:1; + ULONG WakeFromD2:1; + ULONG WakeFromD3:1; + ULONG HardwareDisabled:1; + ULONG NonDynamic:1; + ULONG WarmEjectSupported:1; + ULONG NoDisplayInUI:1; + ULONG Reserved1:1; + ULONG WakeFromInterrupt:1; + ULONG SecureDevice:1; + ULONG ChildOfVgaEnabledBridge:1; + ULONG DecodeIoOnBoot:1; + ULONG Reserved:9; + ULONG Address; + ULONG UINumber; + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + SYSTEM_POWER_STATE SystemWake; + DEVICE_POWER_STATE DeviceWake; + ULONG D1Latency; + ULONG D2Latency; + ULONG D3Latency; +} DEVICE_CAPABILITIES, *PDEVICE_CAPABILITIES; + +/* Device object structure definition */ +typedef struct _DEVICE_OBJECT +{ + CSHORT Type; + USHORT Size; + LONG ReferenceCount; + PDRIVER_OBJECT DriverObject; + PDEVICE_OBJECT NextDevice; + PDEVICE_OBJECT AttachedDevice; + PIRP CurrentIrp; + PIO_TIMER Timer; + ULONG Flags; + ULONG Characteristics; + VOLATILE PVPB Vpb; + PVOID DeviceExtension; + DEVICE_TYPE DeviceType; + CCHAR StackSize; + union + { + LIST_ENTRY ListEntry; + WAIT_CONTEXT_BLOCK Wcb; + } Queue; + ULONG AlignmentRequirement; + KDEVICE_QUEUE DeviceQueue; + KDPC Dpc; + ULONG ActiveThreadCount; + PSECURITY_DESCRIPTOR SecurityDescriptor; + KEVENT DeviceLock; + USHORT SectorSize; + USHORT Spare1; + PDEVOBJ_EXTENSION DeviceObjectExtension; + PVOID Reserved; +} DEVICE_OBJECT, *PDEVICE_OBJECT; + +/* Device object extension structure definition */ +typedef struct _DEVOBJ_EXTENSION +{ + CSHORT Type; + USHORT Size; + PDEVICE_OBJECT DeviceObject; +} DEVOBJ_EXTENSION, *PDEVOBJ_EXTENSION; + +/* Driver extension structure definition */ +typedef struct _DRIVER_EXTENSION +{ + PDRIVER_OBJECT DriverObject; + PDRIVER_ADD_DEVICE AddDevice; + ULONG Count; + UNICODE_STRING ServiceKeyName; +} DRIVER_EXTENSION, *PDRIVER_EXTENSION; + +/* Driver object structure definition */ +typedef struct _DRIVER_OBJECT +{ + CSHORT Type; + CSHORT Size; + PDEVICE_OBJECT DeviceObject; + ULONG Flags; + PVOID DriverStart; + ULONG DriverSize; + PVOID DriverSection; + PDRIVER_EXTENSION DriverExtension; + UNICODE_STRING DriverName; + PUNICODE_STRING HardwareDatabase; + PFAST_IO_DISPATCH FastIoDispatch; + PDRIVER_INITIALIZE DriverInit; + PDRIVER_STARTIO DriverStartIo; + PDRIVER_UNLOAD DriverUnload; + PDRIVER_DISPATCH MajorFunction[IRP_FC_MAXIMUM_FUNCTION + 1]; +} DRIVER_OBJECT, *PDRIVER_OBJECT; + +/* Fast I/O dispatch structure definition */ +typedef struct _FAST_IO_DISPATCH +{ + ULONG SizeOfFastIoDispatch; + PFAST_IO_CHECK_IF_POSSIBLE FastIoCheckIfPossible; + PFAST_IO_READ FastIoRead; + PFAST_IO_WRITE FastIoWrite; + PFAST_IO_QUERY_BASIC_INFO FastIoQueryBasicInfo; + PFAST_IO_QUERY_STANDARD_INFO FastIoQueryStandardInfo; + PFAST_IO_LOCK FastIoLock; + PFAST_IO_UNLOCK_SINGLE FastIoUnlockSingle; + PFAST_IO_UNLOCK_ALL FastIoUnlockAll; + PFAST_IO_UNLOCK_ALL_BY_KEY FastIoUnlockAllByKey; + PFAST_IO_DEVICE_CONTROL FastIoDeviceControl; + PFAST_IO_ACQUIRE_FILE AcquireFileForNtCreateSection; + PFAST_IO_RELEASE_FILE ReleaseFileForNtCreateSection; + PFAST_IO_DETACH_DEVICE FastIoDetachDevice; + PFAST_IO_QUERY_NETWORK_OPEN_INFO FastIoQueryNetworkOpenInfo; + PFAST_IO_ACQUIRE_FOR_MOD_WRITE AcquireForModWrite; + PFAST_IO_MDL_READ MdlRead; + PFAST_IO_MDL_READ_COMPLETE MdlReadComplete; + PFAST_IO_PREPARE_MDL_WRITE PrepareMdlWrite; + PFAST_IO_MDL_WRITE_COMPLETE MdlWriteComplete; + PFAST_IO_READ_COMPRESSED FastIoReadCompressed; + PFAST_IO_WRITE_COMPRESSED FastIoWriteCompressed; + PFAST_IO_MDL_READ_COMPLETE_COMPRESSED MdlReadCompleteCompressed; + PFAST_IO_MDL_WRITE_COMPLETE_COMPRESSED MdlWriteCompleteCompressed; + PFAST_IO_QUERY_OPEN FastIoQueryOpen; + PFAST_IO_RELEASE_FOR_MOD_WRITE ReleaseForModWrite; + PFAST_IO_ACQUIRE_FOR_CCFLUSH AcquireForCcFlush; + PFAST_IO_RELEASE_FOR_CCFLUSH ReleaseForCcFlush; +} FAST_IO_DISPATCH, *PFAST_IO_DISPATCH; + +/* File information structure definition */ +typedef struct _FILE_BASIC_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +/* File quota information structure definition */ +typedef struct _FILE_GET_QUOTA_INFORMATION +{ + ULONG NextEntryOffset; + ULONG SidLength; + SID Sid; +} FILE_GET_QUOTA_INFORMATION, *PFILE_GET_QUOTA_INFORMATION; + +/* File network open information structure definition */ +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + +/* File Object structure definition */ +typedef struct _FILE_OBJECT +{ + CSHORT Type; + CSHORT Size; + PDEVICE_OBJECT DeviceObject; + PVPB Vpb; + PVOID FsContext; + PVOID FsContext2; + PSECTION_OBJECT_POINTERS SectionObjectPointer; + PVOID PrivateCacheMap; + XTSTATUS FinalStatus; + PFILE_OBJECT RelatedFileObject; + BOOLEAN LockOperation; + BOOLEAN DeletePending; + BOOLEAN ReadAccess; + BOOLEAN WriteAccess; + BOOLEAN DeleteAccess; + BOOLEAN SharedRead; + BOOLEAN SharedWrite; + BOOLEAN SharedDelete; + ULONG Flags; + UNICODE_STRING FileName; + LARGE_INTEGER CurrentByteOffset; + VOLATILE ULONG Waiters; + VOLATILE ULONG Busy; + PVOID LastLock; + KEVENT Lock; + KEVENT Event; + VOLATILE PIO_COMPLETION_CONTEXT CompletionContext; + KSPIN_LOCK IrpListLock; + LIST_ENTRY IrpList; + VOLATILE PVOID FileObjectExtension; +} FILE_OBJECT, *PFILE_OBJECT; + +/* File standard information structure definition */ +typedef struct _FILE_STANDARD_INFORMATION +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +/* Interface structure definition */ +typedef struct _INTERFACE +{ + USHORT Size; + USHORT Version; + PVOID Context; + PINTERFACE_REFERENCE InterfaceReference; + PINTERFACE_DEREFERENCE InterfaceDereference; +} INTERFACE, *PINTERFACE; + +/* IO completion context structure definition */ +typedef struct _IO_COMPLETION_CONTEXT +{ + PVOID Port; + PVOID Key; +} IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT; + +/* I/O resource descriptor structure definition */ +typedef struct _IO_RESOURCE_DESCRIPTOR +{ + UCHAR Option; + UCHAR Type; + UCHAR ShareDisposition; + UCHAR Spare1; + USHORT Flags; + USHORT Spare2; + union + { + struct + { + ULONG Length; + ULONG Alignment; + PHYSICAL_ADDRESS MinimumAddress; + PHYSICAL_ADDRESS MaximumAddress; + } Port; + struct + { + ULONG Length; + ULONG Alignment; + PHYSICAL_ADDRESS MinimumAddress; + PHYSICAL_ADDRESS MaximumAddress; + } Memory; + struct + { + ULONG MinimumVector; + ULONG MaximumVector; + IRQ_DEVICE_POLICY AffinityPolicy; + USHORT Group; + IRQ_PRIORITY PriorityPolicy; + PKAFFINITY_MAP TargetedProcessors; + } Interrupt; + struct + { + ULONG MinimumChannel; + ULONG MaximumChannel; + } Dma; + struct + { + ULONG Length; + ULONG Alignment; + PHYSICAL_ADDRESS MinimumAddress; + PHYSICAL_ADDRESS MaximumAddress; + } Generic; + struct + { + ULONG Data[3]; + } DevicePrivate; + struct + { + ULONG Length; + ULONG MinBusNumber; + ULONG MaxBusNumber; + ULONG Reserved; + } BusNumber; + struct + { + ULONG Priority; + ULONG Reserved1; + ULONG Reserved2; + } ConfigData; + } u; +} IO_RESOURCE_DESCRIPTOR, *PIO_RESOURCE_DESCRIPTOR; + +/* I/O resource list structure definition */ +typedef struct _IO_RESOURCE_LIST +{ + USHORT Version; + USHORT Revision; + ULONG Count; + IO_RESOURCE_DESCRIPTOR Descriptors[1]; +} IO_RESOURCE_LIST, *PIO_RESOURCE_LIST; + +/* I/O resource requirements list structure definition */ +typedef struct _IO_RESOURCE_REQUIREMENTS_LIST +{ + ULONG ListSize; + INTERFACE_TYPE InterfaceType; + ULONG BusNumber; + ULONG SlotNumber; + ULONG Reserved[3]; + ULONG AlternativeLists; + IO_RESOURCE_LIST List[1]; +} IO_RESOURCE_REQUIREMENTS_LIST, *PIO_RESOURCE_REQUIREMENTS_LIST; + +/* I/O security context structure definition */ +typedef struct _IO_SECURITY_CONTEXT +{ + PSECURITY_QUALITY_OF_SERVICE SecurityQos; + PACCESS_STATE AccessState; + ACCESS_MASK DesiredAccess; + ULONG FullCreateOptions; +} IO_SECURITY_CONTEXT, *PIO_SECURITY_CONTEXT; + +/* I/O stack location structure definition */ +typedef struct _IO_STACK_LOCATION +{ + UCHAR MajorFunction; + UCHAR MinorFunction; + UCHAR Flags; + UCHAR Control; + union + { + struct + { + PIO_SECURITY_CONTEXT SecurityContext; + ULONG Options; + USHORT FileAttributes; + USHORT ShareAccess; + ULONG EaLength; + } Create; + struct + { + PIO_SECURITY_CONTEXT SecurityContext; + ULONG Options; + USHORT Reserved; + USHORT ShareAccess; + PNAMED_PIPE_CREATE_PARAMETERS Parameters; + } CreatePipe; + struct + { + PIO_SECURITY_CONTEXT SecurityContext; + ULONG Options; + USHORT Reserved; + USHORT ShareAccess; + PMAILSLOT_CREATE_PARAMETERS Parameters; + } CreateMailslot; + struct + { + ULONG Length; + ULONG Key; + LARGE_INTEGER ByteOffset; + } Read; + struct + { + ULONG Length; + ULONG Key; + LARGE_INTEGER ByteOffset; + } Write; + struct + { + ULONG Length; + PUNICODE_STRING FileName; + FILE_INFORMATION_CLASS FileInformationClass; + ULONG FileIndex; + } QueryDirectory; + struct + { + ULONG Length; + ULONG CompletionFilter; + } NotifyDirectory; + struct + { + ULONG Length; + ULONG CompletionFilter; + DIRECTORY_NOTIFY_INFORMATION_CLASS DirectoryNotifyInformationClass; + } NotifyDirectoryEx; + struct + { + ULONG Length; + FILE_INFORMATION_CLASS FileInformationClass; + } QueryFile; + struct + { + ULONG Length; + FILE_INFORMATION_CLASS FileInformationClass; + PFILE_OBJECT FileObject; + union + { + struct + { + BOOLEAN ReplaceIfExists; + BOOLEAN AdvanceOnly; + }; + ULONG ClusterCount; + HANDLE DeleteHandle; + }; + } SetFile; + struct + { + ULONG Length; + PVOID EaList; + ULONG EaListLength; + ULONG EaIndex; + } QueryEa; + struct + { + ULONG Length; + } SetEa; + struct + { + ULONG Length; + FS_INFORMATION_CLASS FsInformationClass; + } QueryVolume; + struct + { + ULONG Length; + FS_INFORMATION_CLASS FsInformationClass; + } SetVolume; + struct + { + ULONG OutputBufferLength; + ULONG InputBufferLength; + ULONG FsControlCode; + PVOID Type3InputBuffer; + } FileSystemControl; + struct + { + PLARGE_INTEGER Length; + ULONG Key; + LARGE_INTEGER ByteOffset; + } LockControl; + struct + { + ULONG OutputBufferLength; + ULONG InputBufferLength; + ULONG IoControlCode; + PVOID Type3InputBuffer; + } DeviceIoControl; + struct + { + SECURITY_INFORMATION SecurityInformation; + ULONG Length; + } QuerySecurity; + struct + { + SECURITY_INFORMATION SecurityInformation; + PSECURITY_DESCRIPTOR SecurityDescriptor; + } SetSecurity; + struct + { + PVPB Vpb; + PDEVICE_OBJECT DeviceObject; + } MountVolume; + struct + { + PVPB Vpb; + PDEVICE_OBJECT DeviceObject; + } VerifyVolume; + struct + { + PSCSI_REQUEST_BLOCK Srb; + } Scsi; + struct + { + ULONG Length; + PSID StartSid; + PFILE_GET_QUOTA_INFORMATION SidList; + ULONG SidListLength; + } QueryQuota; + struct + { + ULONG Length; + } SetQuota; + struct + { + DEVICE_RELATION_TYPE Type; + } QueryDeviceRelations; + struct + { + CONST GUID *InterfaceType; + USHORT Size; + USHORT Version; + PINTERFACE Interface; + PVOID InterfaceSpecificData; + } QueryInterface; + struct + { + PDEVICE_CAPABILITIES Capabilities; + } DeviceCapabilities; + struct + { + PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList; + } FilterResourceRequirements; + struct + { + ULONG WhichSpace; + PVOID Buffer; + ULONG Offset; + ULONG Length; + } ReadWriteConfig; + struct + { + BOOLEAN Lock; + } SetLock; + struct + { + BUS_QUERY_ID_TYPE IdType; + } QueryId; + struct + { + DEVICE_TEXT_TYPE DeviceTextType; + LCID LocaleId; + } QueryDeviceText; + struct + { + BOOLEAN InPath; + BOOLEAN Reserved[3]; + DEVICE_USAGE_NOTIFICATION_TYPE Type; + } UsageNotification; + struct + { + SYSTEM_POWER_STATE PowerState; + } WaitWake; + struct + { + PPOWER_SEQUENCE PowerSequence; + } PowerSequence; + struct + { + union + { + ULONG SystemContext; + SYSTEM_POWER_STATE_CONTEXT SystemPowerStateContext; + }; + POWER_STATE_TYPE Type; + POWER_STATE State; + POWER_ACTION ShutdownType; + } Power; + struct + { + PCM_RESOURCE_LIST AllocatedResources; + PCM_RESOURCE_LIST AllocatedResourcesTranslated; + } StartDevice; + struct + { + ULONG_PTR ProviderId; + PVOID DataPath; + ULONG BufferSize; + PVOID Buffer; + } WMI; + struct + { + PVOID Argument1; + PVOID Argument2; + PVOID Argument3; + PVOID Argument4; + } Others; + } Parameters; + PDEVICE_OBJECT DeviceObject; + PFILE_OBJECT FileObject; + PIO_COMPLETION_ROUTINE CompletionRoutine; + PVOID Context; +} IO_STACK_LOCATION, *PIO_STACK_LOCATION; + +/* IO status block structure definition */ +typedef struct _IO_STATUS_BLOCK +{ + union + { + XTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +/* IO timer structure definition */ +typedef struct _IO_TIMER +{ + USHORT Type; + USHORT TimerEnabled; + LIST_ENTRY IoTimerList; + PIO_TIMER_ROUTINE TimerRoutine; + PVOID Context; + PDEVICE_OBJECT DeviceObject; +} IO_TIMER, *PIO_TIMER; + +/* IRP, czyli I/O Request Packet structure definition */ +typedef struct _IRP +{ + CSHORT Type; + USHORT Size; + PMDL MdlAddress; + ULONG Flags; + union + { + PIRP MasterIrp; + VOLATILE LONG IrpCount; + PVOID SystemBuffer; + } AssociatedIrp; + LIST_ENTRY ThreadListEntry; + IO_STATUS_BLOCK IoStatus; + KPROCESSOR_MODE RequestorMode; + BOOLEAN PendingReturned; + CHAR StackCount; + CHAR CurrentLocation; + BOOLEAN Cancel; + KRUNLEVEL CancelIrql; + CCHAR ApcEnvironment; + UCHAR AllocationFlags; + PIO_STATUS_BLOCK UserIosb; + PKEVENT UserEvent; + union + { + struct + { + union + { + PIO_APC_ROUTINE UserApcRoutine; + PVOID IssuingProcess; + }; + PVOID UserApcContext; + } AsynchronousParameters; + LARGE_INTEGER AllocationSize; + } Overlay; + VOLATILE PDRIVER_CANCEL CancelRoutine; + PVOID UserBuffer; + union + { + struct + { + union + { + KDEVICE_QUEUE_ENTRY DeviceQueueEntry; + struct + { + PVOID DriverContext[4]; + }; + }; + PETHREAD Thread; + PCHAR AuxiliaryBuffer; + struct + { + LIST_ENTRY ListEntry; + union + { + PIO_STACK_LOCATION CurrentStackLocation; + ULONG PacketType; + }; + }; + PFILE_OBJECT OriginalFileObject; + } Overlay; + KAPC Apc; + PVOID CompletionKey; + } Tail; +} IRP, *PIRP; + +/* Mailslot create parameters structure definition */ +typedef struct _MAILSLOT_CREATE_PARAMETERS +{ + ULONG MailslotQuota; + ULONG MaximumMessageSize; + LARGE_INTEGER ReadTimeout; + BOOLEAN TimeoutSpecified; +} MAILSLOT_CREATE_PARAMETERS, *PMAILSLOT_CREATE_PARAMETERS; + +/* Named pipe create parameters structure definition */ +typedef struct _NAMED_PIPE_CREATE_PARAMETERS +{ + ULONG NamedPipeType; + ULONG ReadMode; + ULONG CompletionMode; + ULONG MaximumInstances; + ULONG InboundQuota; + ULONG OutboundQuota; + LARGE_INTEGER DefaultTimeout; + BOOLEAN TimeoutSpecified; +} NAMED_PIPE_CREATE_PARAMETERS, *PNAMED_PIPE_CREATE_PARAMETERS; + /* PCI bridge control registers */ typedef struct _PCI_BRIDGE_CONTROL_REGISTER { @@ -105,7 +1077,7 @@ typedef struct _PCI_COMMON_HEADER UCHAR BIST; union { - struct _PCI_TYPE0_HEADER + struct { ULONG BaseAddresses[PCI_TYPE0_ADDRESSES]; ULONG CIS; @@ -120,7 +1092,7 @@ typedef struct _PCI_COMMON_HEADER UCHAR MinimumGrant; UCHAR MaximumLatency; } type0; - struct _PCI_TYPE1_HEADER + struct { ULONG BaseAddresses[PCI_TYPE1_ADDRESSES]; UCHAR PrimaryBus; @@ -145,7 +1117,7 @@ typedef struct _PCI_COMMON_HEADER UCHAR InterruptPin; USHORT BridgeControl; } type1; - struct _PCI_TYPE2_HEADER + struct { ULONG SocketRegistersBaseAddress; UCHAR CapabilitiesPtr; @@ -218,5 +1190,66 @@ typedef struct _PCI_TYPE1_DEVICE PCI_BRIDGE_CONTROL_REGISTER Bridge; } PCI_TYPE1_DEVICE, *PPCI_TYPE1_DEVICE; +/* Power sequence structure definition */ +typedef struct _POWER_SEQUENCE +{ + ULONG SequenceD1; + ULONG SequenceD2; + ULONG SequenceD3; +} POWER_SEQUENCE, *PPOWER_SEQUENCE; + +/* SCSI request block structure definition */ +typedef struct _SCSI_REQUEST_BLOCK +{ + USHORT Length; + UCHAR Function; + UCHAR SrbStatus; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR QueueTag; + UCHAR QueueAction; + UCHAR CdbLength; + UCHAR SenseInfoBufferLength; + ULONG SrbFlags; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + PVOID SenseInfoBuffer; + PSCSI_REQUEST_BLOCK NextSrb; + PVOID OriginalRequest; + PVOID SrbExtension; + union + { + ULONG InternalStatus; + ULONG QueueSortKey; + ULONG LinkTimeoutValue; + }; + UCHAR Cdb[16]; +} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK; + +/* Section object pointers structure definition */ +typedef struct _SECTION_OBJECT_POINTERS +{ + PVOID DataSectionObject; + PVOID SharedCacheMap; + PVOID ImageSectionObject; +} SECTION_OBJECT_POINTERS, *PSECTION_OBJECT_POINTERS; + +/* Volume Parameter Block structure definition */ +typedef struct _VPB +{ + CSHORT Type; + CSHORT Size; + USHORT Flags; + USHORT VolumeLabelLength; + PDEVICE_OBJECT DeviceObject; + PDEVICE_OBJECT RealDevice; + ULONG SerialNumber; + ULONG ReferenceCount; + WCHAR VolumeLabel[IO_MAXIMUM_VOLUME_LABEL_LENGTH / sizeof(WCHAR)]; +} VPB, *PVPB; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_IOTYPES_H */ diff --git a/sdk/xtdk/ketypes.h b/sdk/xtdk/ketypes.h index 11eaf4c..b1dc33b 100644 --- a/sdk/xtdk/ketypes.h +++ b/sdk/xtdk/ketypes.h @@ -14,6 +14,7 @@ #include #include #include ARCH_HEADER(xtstruct.h) +#include ARCH_HEADER(rtltypes.h) /* Exception types and handling mechanisms */ @@ -24,14 +25,49 @@ /* Maximum number of exception parameters */ #define EXCEPTION_MAXIMUM_PARAMETERS 15 +/* IPI types */ +#define IPI_APC 1 +#define IPI_DPC 2 +#define IPI_FREEZE 4 +#define IPI_PACKET_READY 8 +#define IPI_SYNC_REQUEST 16 + +/* IPI frozen states */ +#define IPI_FROZEN_STATE_RUNNING 0x00 +#define IPI_FROZEN_STATE_FROZEN 0x02 +#define IPI_FROZEN_STATE_THAW 0x03 +#define IPI_FROZEN_STATE_OWNER 0x04 +#define IPI_FROZEN_STATE_FREEZE 0x05 +#define IPI_FROZEN_STATE_ACTIVE 0x20 + +/* Lock queue states */ +#define LOCK_QUEUE_WAIT 1 +#define LOCK_QUEUE_OWNER 2 + /* APC pending state length */ #define KAPC_STATE_LENGTH (FIELD_OFFSET(KAPC_STATE, UserApcPending) + sizeof(BOOLEAN)) +/* Indices used to access the PushLock data structure */ +#define KPUSHLOCK_INDEX ((ULONG_PTR)0x00) +#define KPUSHLOCK_LOCK ((ULONG_PTR)0x01) +#define KPUSHLOCK_WAITING ((ULONG_PTR)0x02) +#define KPUSHLOCK_WAKING ((ULONG_PTR)0x04) +#define KPUSHLOCK_MULTIPLE_SHARED ((ULONG_PTR)0x08) +#define KPUSHLOCK_INCREMENT_SHARED ((ULONG_PTR)0x10) + +/* Mask for the pointer bits */ +#define KPUSHLOCK_PTR_BITS ((ULONG_PTR)0x0F) + +/* PushLock related definitions */ +#define KPUSH_LOCK_TOTAL_BITS (sizeof(ULONG_PTR) * 8) +#define KPUSH_LOCK_SPIN_COUNT 1024 + /* Kernel service descriptor tables count */ #define KSERVICE_TABLES_COUNT 4 -/* Timer length */ +/* Timer related definitions */ #define KTIMER_LENGTH (FIELD_OFFSET(KTIMER, Period) + sizeof(LONG)) +#define KTIMER_TABLE_SIZE 512 /* Kernel builtin wait blocks */ #define EVENT_WAIT_BLOCK 2 @@ -43,6 +79,9 @@ #define READY_SKIP_QUANTUM 2 #define THREAD_QUANTUM 6 +/* Dispatcher object type mask */ +#define DISPATCHER_OBJECT_TYPE_MASK 0x7L + /* Thread priority levels */ #define THREAD_LOW_PRIORITY 0 #define THREAD_LOW_REALTIME_PRIORITY 16 @@ -79,6 +118,15 @@ typedef enum _KAPC_ENVIRONMENT InsertApcEnvironment } KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT; +/* Continue status enumeration list */ +typedef enum _KCONTINUE_STATUS +{ + ContinueError, + ContinueSuccess, + ContinueProcessorReselected, + ContinueNextProcessor +} KCONTINUE_STATUS, *PKCONTINUE_STATUS; + /* DPC importance enumeration list */ typedef enum _KDPC_IMPORTANCE { @@ -100,7 +148,7 @@ typedef enum _KOBJECTS { EventNotificationObject = 0, EventSynchronizationObject = 1, - MutantObject = 2, + MutexObject = 2, ProcessObject = 3, QueueObject = 4, SemaphoreObject = 5, @@ -212,6 +260,55 @@ typedef enum _KTIMER_TYPE SynchronizationTimer } KTIMER_TYPE, *PKTIMER_TYPE; +/* Wait reason */ +typedef enum _KWAIT_REASON +{ + Executive, + FreePage, + PageIn, + PoolAllocation, + DelayExecution, + Suspended, + UserRequest, + WrExecutive, + WrFreePage, + WrPageIn, + WrPoolAllocation, + WrDelayExecution, + WrSuspended, + WrUserRequest, + WrEventPair, + WrQueue, + WrLpcReceive, + WrLpcReply, + WrVirtualMemory, + WrPageOut, + WrRendezvous, + WrKeyedEvent, + WrTerminated, + WrProcessInSwap, + WrCpuRateControl, + WrCalloutStack, + WrKernel, + WrResource, + WrPushLock, + WrMutex, + WrQuantumEnd, + WrDispatchInt, + WrPreempted, + WrYieldExecution, + WrFastMutex, + WrGuardedMutex, + WrRundown, + WrAlertByThreadId, + WrDeferredPreempt, + WrPhysicalFault, + WrIoRing, + WrMdlCache, + WrRcu, + MaximumWaitReason +} KWAIT_REASON, *PKWAIT_REASON; + /* APC Types */ typedef enum _MODE { @@ -252,6 +349,27 @@ typedef VOID (XTAPI *PKRUNDOWN_ROUTINE)(IN PKAPC Apc); typedef VOID (XTCDECL *PKSTART_ROUTINE)(IN PVOID StartContext); typedef VOID (XTCDECL *PKSYSTEM_ROUTINE)(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext); +/* Dispatcher object header structure definition */ +typedef struct _DISPATCHER_HEADER +{ + union + { + struct + { + UCHAR Type; + UCHAR Absolute; + UCHAR Size; + union { + UCHAR Inserted; + BOOLEAN DebugActive; + }; + }; + VOLATILE LONG Lock; + }; + LONG SignalState; + LIST_ENTRY WaitListHead; +} DISPATCHER_HEADER, *PDISPATCHER_HEADER; + /* Exception record structure definition */ typedef struct _EXCEPTION_RECORD { @@ -263,6 +381,14 @@ typedef struct _EXCEPTION_RECORD ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD, *PEXCEPTION_RECORD; +/* Extended affinity structure definition */ +typedef struct _KAFFINITY_MAP +{ + USHORT Size; + ULONG Reserved; + KAFFINITY Bitmap[]; +} KAFFINITY_MAP, *PKAFFINITY_MAP; + /* Asynchronous Procedure Call (APC) object structure definition */ typedef struct _KAPC { @@ -331,11 +457,49 @@ typedef struct _KAPC_STATE BOOLEAN UserApcPending; } KAPC_STATE, *PKAPC_STATE; -/* Event gate structure definition */ -typedef struct _KGATE +/* Device queue entry structure definition */ +typedef struct _KDEVICE_QUEUE_ENTRY +{ + LIST_ENTRY DeviceListEntry; + ULONG SortKey; + BOOLEAN Inserted; +} KDEVICE_QUEUE_ENTRY, *PKDEVICE_QUEUE_ENTRY; + +/* Mutex object structure definition */ +typedef struct _KMUTEX { DISPATCHER_HEADER Header; -} KGATE, *PKGATE; + LIST_ENTRY MutexListEntry; + PKTHREAD OwnerThread; + BOOLEAN Abandoned; + UCHAR ApcDisable; +} KMUTEX, *PKMUTEX; + +/* Push Lock structure definition */ +typedef union _KPUSH_LOCK +{ + struct + { + ULONG_PTR Locked:1; + ULONG_PTR Waiting:1; + ULONG_PTR Waking:1; + ULONG_PTR MultipleShared:1; + ULONG_PTR Shared:(KPUSH_LOCK_TOTAL_BITS - 4); + }; + ULONG_PTR Value; + PVOID Ptr; +} KPUSH_LOCK, *PKPUSH_LOCK; + +/* Push lock wait block structure definition */ +typedef struct _KPUSH_LOCK_WAIT_BLOCK +{ + KEVENT WakeEvent; + PKPUSH_LOCK_WAIT_BLOCK Next; + PKPUSH_LOCK_WAIT_BLOCK Last; + PKPUSH_LOCK_WAIT_BLOCK Previous; + LONG ShareCount; + LONG Flags; +} KPUSH_LOCK_WAIT_BLOCK, *PKPUSH_LOCK_WAIT_BLOCK; /* Semaphore object structure definition */ typedef struct _KSEMAPHORE @@ -419,7 +583,8 @@ typedef struct _KPROCESS ULONG_PTR DirectoryTable[2]; USHORT IopmOffset; UCHAR Iopl; - VOLATILE KAFFINITY ActiveProcessors; + PKAFFINITY_MAP Affinity; + PKAFFINITY_MAP ActiveProcessors; ULONG KernelTime; ULONG UserTime; LIST_ENTRY ReadyListHead; @@ -427,7 +592,6 @@ typedef struct _KPROCESS PVOID VdmTrapHandler; LIST_ENTRY ThreadListHead; KSPIN_LOCK ProcessLock; - KAFFINITY Affinity; union { struct @@ -476,13 +640,12 @@ typedef struct _KSHARED_DATA typedef struct _KTHREAD { DISPATCHER_HEADER Header; - LIST_ENTRY MutantListHead; + LIST_ENTRY MutexListHead; PVOID InitialStack; PVOID KernelStack; PVOID StackBase; PVOID StackLimit; KSPIN_LOCK ThreadLock; - ULONG ContextSwitches; VOLATILE UCHAR State; UCHAR NpxState; @@ -507,7 +670,7 @@ typedef struct _KTHREAD PKWAIT_BLOCK WaitBlockList; BOOLEAN Alertable; BOOLEAN WaitNext; - UCHAR WaitReason; + KWAIT_REASON WaitReason; SCHAR Priority; UCHAR StackSwap; VOLATILE UCHAR SwapBusy; @@ -545,9 +708,9 @@ typedef struct _KTHREAD CHAR PreviousMode; UCHAR ResourceIndex; UCHAR DisableBoost; - KAFFINITY UserAffinity; + PKAFFINITY_MAP UserAffinity; PKPROCESS Process; - KAFFINITY Affinity; + PKAFFINITY_MAP Affinity; PVOID ServiceTable; PKAPC_STATE ApcStatePointer[2]; KAPC_STATE SavedApcState; @@ -563,12 +726,12 @@ typedef struct _KTHREAD LIST_ENTRY ThreadListEntry; UCHAR LargeStack; UCHAR PowerState; - UCHAR NpxIrql; + UCHAR NpxRunLevel; UCHAR Spare5; BOOLEAN AutoAlignment; UCHAR Iopl; - CCHAR FreezeCount; - CCHAR SuspendCount; + CHAR FreezeCount; + CHAR SuspendCount; UCHAR Spare0[1]; UCHAR UserIdealProcessor; UCHAR Spare2[3]; diff --git a/sdk/xtdk/ldrtypes.h b/sdk/xtdk/ldrtypes.h index c015612..40650c4 100644 --- a/sdk/xtdk/ldrtypes.h +++ b/sdk/xtdk/ldrtypes.h @@ -74,5 +74,18 @@ typedef struct _LDR_DATA_TABLE_ENTRY PVOID PatchInformation; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; +typedef struct _LDR_PEB_DATA +{ + ULONG Length; + BOOLEAN Initialized; + PVOID SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; + UCHAR ShutdownInProgress; + PVOID ShutdownThreadId; +} LDR_PEB_DATA, *PLDR_PEB_DATA; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_LDRTYPES_H */ diff --git a/sdk/xtdk/lpctypes.h b/sdk/xtdk/lpctypes.h new file mode 100644 index 0000000..1a3311e --- /dev/null +++ b/sdk/xtdk/lpctypes.h @@ -0,0 +1,62 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: sdk/xtdk/lpctypes.h + * DESCRIPTION: Local Procedure Call (LPC) structures and definitions + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTDK_LPCTYPES_H +#define __XTDK_LPCTYPES_H + +#include +#include +#include + + +/* C/C++ specific code */ +#ifndef __XTOS_ASSEMBLER__ + +/* LPC non-paged port queue structure definition */ +typedef struct _LPCP_NONPAGED_PORT_QUEUE +{ + KSEMAPHORE Semaphore; + struct _LPCP_PORT_OBJECT *BackPointer; +} LPCP_NONPAGED_PORT_QUEUE, *PLPCP_NONPAGED_PORT_QUEUE; + +/* LPC port queue structure definition */ +typedef struct _LPCP_PORT_QUEUE +{ + PLPCP_NONPAGED_PORT_QUEUE NonPagedPortQueue; + PKSEMAPHORE Semaphore; + LIST_ENTRY ReceiveHead; +} LPCP_PORT_QUEUE, *PLPCP_PORT_QUEUE; + +/* LPC port object structure definition */ +typedef struct _LPCP_PORT_OBJECT +{ + struct _LPCP_PORT_OBJECT *ConnectionPort; + struct _LPCP_PORT_OBJECT *ConnectedPort; + LPCP_PORT_QUEUE MsgQueue; + CLIENT_ID Creator; + PVOID ClientSectionBase; + PVOID ServerSectionBase; + PVOID PortContext; + PETHREAD ClientThread; + SECURITY_QUALITY_OF_SERVICE SecurityQos; + SECURITY_CLIENT_CONTEXT StaticSecurity; + LIST_ENTRY LpcReplyChainHead; + LIST_ENTRY LpcDataInfoChainHead; + union + { + PEPROCESS ServerProcess; + PEPROCESS MappingProcess; + }; + ULONG MaxMessageLength; + ULONG MaxConnectionInfoLength; + ULONG Flags; + KEVENT WaitEvent; +} LPCP_PORT_OBJECT, *PLPCP_PORT_OBJECT; + +#endif /* __XTOS_ASSEMBLER__ */ +#endif /* __XTDK_LPCTYPES_H */ diff --git a/sdk/xtdk/mmtypes.h b/sdk/xtdk/mmtypes.h index 05ce4ee..f3454b3 100644 --- a/sdk/xtdk/mmtypes.h +++ b/sdk/xtdk/mmtypes.h @@ -11,6 +11,7 @@ #define __XTDK_MMTYPES_H #include +#include #include ARCH_HEADER(xtstruct.h) @@ -55,6 +56,9 @@ /* Protection field shift */ #define MM_PROTECT_FIELD_SHIFT 5 +/* Process Quota Adjustment Thresholds */ +#define MMNONPAGED_QUOTA_INCREASE (64*1024) +#define MMPAGED_QUOTA_INCREASE (512*1024) /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ @@ -107,14 +111,31 @@ typedef enum _MMSYSTEM_PTE_POOL_TYPE MaximumPtePoolTypes } MMSYSTEM_PTE_POOL_TYPE, *PMMSYSTEM_PTE_POOL_TYPE; -/* Page map routines structure definition */ -typedef CONST STRUCT _CMMPAGEMAP_ROUTINES +/* Non-paged lookaside list indices */ +typedef enum _NONPAGED_LOOKASIDE_NUMBER { - VOID (XTAPI *ClearPte)(PHARDWARE_PTE PtePointer); - BOOLEAN (XTAPI *PteValid)(PHARDWARE_PTE PtePointer); - VOID (XTAPI *SetPteCaching)(PHARDWARE_PTE PtePointer, BOOLEAN CacheDisable, BOOLEAN WriteThrough); - VOID (XTAPI *SetPte)(PHARDWARE_PTE PtePointer, PFN_NUMBER PageFrameNumber, BOOLEAN Writable); -} CMMPAGEMAP_ROUTINES, *PCMMPAGEMAP_ROUTINES; + LookasideSmallIrpList, + LookasideLargeIrpList, + LookasideMdlList, + LookasideCreateInfoList, + LookasideNameBufferList, + LookasideTwilightList, + LookasideCompletionList, + LookasideMaximumList +} NONPAGED_LOOKASIDE_NUMBER, *PNONPAGED_LOOKASIDE_NUMBER; + +/* Memory Descriptor List structure definition */ +typedef struct _MDL +{ + PMDL Next; + CSHORT Size; + CSHORT MdlFlags; + PEPROCESS Process; + PVOID MappedSystemVa; + PVOID StartVa; + ULONG ByteCount; + ULONG ByteOffset; +} MDL, *PMDL; /* Color tables structure definition */ typedef struct _MMCOLOR_TABLES @@ -262,5 +283,52 @@ typedef struct _POOL_TRACKING_TABLE ULONG Tag; } POOL_TRACKING_TABLE, *PPOOL_TRACKING_TABLE; +/* Memory manager support flags structure definition */ +typedef struct _MMSUPPORT_FLAGS +{ + ULONG SessionSpace:1; + ULONG BeingTrimmed:1; + ULONG SessionLeader:1; + ULONG TrimHard:1; + ULONG MaximumWorkingSetHard:1; + ULONG ForceTrim:1; + ULONG MinimumWorkingSetHard:1; + ULONG Available0:1; + ULONG MemoryPriority:8; + ULONG GrowWsleHash:1; + ULONG AcquiredUnsafe:1; + ULONG Available:14; +} MMSUPPORT_FLAGS, *PMMSUPPORT_FLAGS; + +/* Memory manager support structure definition */ +typedef struct _MMSUPPORT +{ + LIST_ENTRY WorkingSetExpansionLinks; + USHORT LastTrimpStamp; + USHORT NextPageColor; + MMSUPPORT_FLAGS Flags; + ULONG PageFaultCount; + ULONG PeakWorkingSetSize; + ULONG GrowthSinceLastEstimate; + ULONG MinimumWorkingSetSize; + ULONG MaximumWorkingSetSize; + PMMWSL VmWorkingSetList; + ULONG Claim; + ULONG NextEstimationSlot; + ULONG NextAgingSlot; + ULONG EstimatedAvailable; + ULONG WorkingSetSize; + PKEVENT ExitEvent; + KPUSH_LOCK WorkingSetMutex; + PVOID AccessLog; +} MMSUPPORT, *PMMSUPPORT; + +/* Working Set List Entry Hash structure definition */ +typedef struct _MMWSLE_HASH +{ + PVOID Key; + ULONG Index; +} MMWSLE_HASH, *PMMWSLE_HASH; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_MMTYPES_H */ diff --git a/sdk/xtdk/obtypes.h b/sdk/xtdk/obtypes.h new file mode 100644 index 0000000..6d34450 --- /dev/null +++ b/sdk/xtdk/obtypes.h @@ -0,0 +1,511 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: sdk/xtdk/obtypes.h + * DESCRIPTION: Object Manager structures definitions + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTDK_OBTYPES_H +#define __XTDK_OBTYPES_H + +#include +#include +#include +#include + + +/* Object header information flag masks */ +#define OBJECT_FLAG_NEW_OBJECT 0x01 +#define OBJECT_FLAG_KERNEL_MODE 0x02 +#define OBJECT_FLAG_CREATOR_INFO 0x04 +#define OBJECT_FLAG_EXCLUSIVE 0x08 +#define OBJECT_FLAG_PERMANENT 0x10 +#define OBJECT_FLAG_SECURITY_QUOTA 0x20 +#define OBJECT_FLAG_SINGLE_PROCESS 0x40 +#define OBJECT_FLAG_DEFER_DELETE 0x80 + +/* Object lock states */ +#define OBJECT_LOCK_STATE_WAIT_EXCLUSIVE 0xAAAA1234 +#define OBJECT_LOCK_WAITSHARED_SIGNATURE 0xBBBB1234 +#define OBJECT_LOCK_STATE_OWNED_EXCLUSIVE 0xCCCC1234 +#define OBJECT_LOCK_OWNEDSHARED_SIGNATURE 0xDDDD1234 +#define OBJECT_LOCK_STATE_RELEASED_SIGNATURE 0xEEEE1234 +#define OBJECT_LOCK_STATE_INITIALIZED 0xFFFF1234 + +/* Object name attribute flags */ +#define OBJECT_PROTECT_CLOSE 0x00000001L +#define OBJECT_INHERIT 0x00000002L +#define OBJECT_AUDIT_OBJECT_CLOSE 0x00000004L +#define OBJECT_PERMANENT 0x00000010L +#define OBJECT_EXCLUSIVE 0x00000020L +#define OBJECT_CASE_INSENSITIVE 0x00000040L +#define OBJECT_OPENIF 0x00000080L +#define OBJECT_OPENLINK 0x00000100L +#define OBJECT_KERNEL_HANDLE 0x00000200L +#define OBJECT_FORCE_ACCESS_CHECK 0x00000400L +#define OBJECT_VALID_ATTRIBUTES 0x000007F2L + +/* Object handle attributes */ +#define OBJECT_HANDLE_ATTRIBUTES (OBJECT_PROTECT_CLOSE | \ + OBJECT_INHERIT | \ + OBJECT_AUDIT_OBJECT_CLOSE) + +/* Defines maximum number of handles */ +#define OBJECT_MAX_HANDLES (1<<24) + +/* Handle Table Architecture Dimensions */ +#define OBJECT_HANDLE_HIGHLEVEL_COUNT OBJECT_MAX_HANDLES / (OBJECT_HANDLE_LOWLEVEL_COUNT * OBJECT_HANDLE_MEDIUMLEVEL_COUNT) +#define OBJECT_HANDLE_MEDIUMLEVEL_COUNT (MM_PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY)) +#define OBJECT_HANDLE_LOWLEVEL_COUNT (MM_PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY)) +#define OBJECT_HANDLE_HIGHLEVEL_SIZE (OBJECT_HANDLE_HIGHLEVEL_COUNT * sizeof(PHANDLE_TABLE_ENTRY)) +#define OBJECT_HANDLE_MEDIUMLEVEL_THRESHOLD (OBJECT_HANDLE_MEDIUMLEVEL_COUNT * OBJECT_HANDLE_LOWLEVEL_COUNT) + +/* Handle Value and Table Routing Constants */ +#define OBJECT_HANDLE_LEVEL_CODE_MASK 3 +#define OBJECT_HANDLE_VALUE_INCREMENT 4 + +/* Handle free mask */ +#define OBJECT_FREE_HANDLE_MASK 0xFFFFFFFF + +/* Handle table entry lock bit */ +#define OBJECT_HANDLE_TABLE_ENTRY_LOCK_BIT 1 + +/* Handle additional information signature */ +#define OBJECT_HANDLE_ADDITIONAL_INFO_SIGNATURE (-2) + +/* Handle tracing constants */ +#define OBJECT_HANDLE_TRACE_DB_STACK_SIZE 8 + +/* Object protect-on-close access bit */ +#define OBJECT_ACCESS_PROTECT_CLOSE_BIT 0x02000000L + +/* Maximum number of defined object types */ +#define OBJECT_MAX_DEFINED_OBJECT_TYPES 48 + +/* Object name buffer size */ +#define OBJECT_NAME_BUFFER_SIZE 248 + +/* Object name lock flags */ +#define OBJECT_NAME_LOCKED ((LONG)0x80000000) +#define OBJECT_REMOVE_QUEUE_LOCKED (PVOID)1 + +/* Object name path separator */ +#define OBJECT_NAME_PATH_SEPARATOR ((WCHAR)L'\\') + +/* Kernel mode object handle mask */ +#define OBJECT_HANDLE_KERNEL_MASK ((ULONG_PTR)((LONG)0x80000000)) + +/* Number of hash buckets */ +#define OBJECT_NUMBER_HASH_BUCKETS 37 + + +/* C/C++ specific code */ +#ifndef __XTOS_ASSEMBLER__ + +/* Object Manager routine callbacks */ +typedef BOOLEAN (XTAPI *POB_CHANGE_HANDLE_ROUTINE)(IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN ULONG_PTR Parameter); +typedef VOID (XTAPI *POB_DESTROY_HANDLE_ROUTINE)(IN HANDLE Handle); +typedef VOID (XTAPI *POB_DUMP_METHOD)(IN PVOID Object, IN POBJECT_DUMP_CONTROL Control); +typedef BOOLEAN (XTAPI *POB_DUPLICATE_HANDLE_ROUTINE)(IN PEPROCESS Process, IN PHANDLE_TABLE OldHandleTable, IN PHANDLE_TABLE_ENTRY OldHandleTableEntry, IN PHANDLE_TABLE_ENTRY NewHandleTableEntry); +typedef BOOLEAN (XTAPI *POB_ENUMERATE_HANDLE_ROUTINE)(IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN HANDLE Handle, IN PVOID EnumParameter); +typedef XTSTATUS (XTAPI *POB_OPEN_METHOD)(IN OBJECT_OPEN_REASON Reason, IN PEPROCESS Process, IN PVOID ObjectBody, IN ACCESS_MASK GrantedAccess, IN ULONG HandleCount); +typedef VOID (XTAPI *POB_CLOSE_METHOD)(IN PEPROCESS Process, IN PVOID Object, IN ACCESS_MASK GrantedAccess, IN ULONG ProcessHandleCount, IN ULONG SystemHandleCount); +typedef VOID (XTAPI *POB_DELETE_METHOD)(IN PVOID Object); +typedef BOOLEAN (XTAPI *POB_OKAYTOCLOSE_METHOD)(IN PEPROCESS Process, IN PVOID Object, IN HANDLE Handle, IN KPROCESSOR_MODE ProcessorMode); +typedef XTSTATUS (XTAPI *POB_PARSE_METHOD)(IN PVOID ParseObject, IN PVOID ObjectType, IN OUT PACCESS_STATE AccessState, IN KPROCESSOR_MODE ProcessorMode, IN ULONG Attributes, IN OUT PUNICODE_STRING CompleteName, IN OUT PUNICODE_STRING RemainingName, IN OUT PVOID Context, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, OUT PVOID *Object); +typedef XTSTATUS (XTAPI *POB_QUERYNAME_METHOD)(IN PVOID Object, IN BOOLEAN HasObjectName, OUT POBJECT_NAME_INFORMATION ObjectNameInfo, IN ULONG Length, OUT PULONG ReturnLength, IN KPROCESSOR_MODE ProcessorMode); +typedef XTSTATUS (XTAPI *POB_SECURITY_METHOD)(IN PVOID Object, IN SECURITY_OPERATION_CODE OperationType, IN PSECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN OUT PULONG CapturedLength, IN OUT PSECURITY_DESCRIPTOR *ObjectSecurityDescriptor, IN MMPOOL_TYPE PoolType, IN PGENERIC_MAPPING GenericMapping); +typedef XTSTATUS (XTAPI *POB_SNAPSHOT_HANDLE_ENTRY)(IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO *HandleEntryInfo, IN PVOID ProcessId, IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN HANDLE Handle, IN ULONG Length, IN OUT PULONG RequiredLength); +typedef XTSTATUS (XTAPI *POB_SNAPSHOT_HANDLE_ENTRY_EX)(IN OUT PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX *HandleEntryInfo, IN PVOID ProcessId, IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN HANDLE Handle, IN ULONG Length, IN OUT PULONG RequiredLength); + +/* Bitmasks used to identify the presence of optional object headers in memory */ +typedef enum _OBJECT_HEADER_INFO +{ + ObjectHeaderInfoNone = 0, + ObjectHeaderInfoCreatorInfo = 0x01, + ObjectHeaderInfoNameInfo = 0x02, + ObjectHeaderInfoHandleInfo = 0x04, + ObjectHeaderInfoQuotaInfo = 0x08, + ObjectHeaderInfoProcessInfo = 0x10 +} OBJECT_HEADER_INFO, *POBJECT_HEADER_INFO; + +/* List of information classes used when querying or setting object attributes */ +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInfo, + ObjectNameInfo, + ObjectTypeInfo, + ObjectAllInfo, + ObjectHandleFlagInfo +} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; + +/* List of valid reasons for creating, opening, or duplicating an object handle */ +typedef enum _OBJECT_OPEN_REASON +{ + ObCreateHandle, + ObOpenHandle, + ObDuplicateHandle, + ObInheritHandle, + ObMaxOpenReason +} OBJECT_OPEN_REASON, *POBJECT_OPEN_REASON; + +/* Mapping of device names to object manager devices */ +typedef struct _DEVICE_MAP +{ + POBJECT_DIRECTORY DevicesDirectory; + POBJECT_DIRECTORY GlobalDevicesDirectory; + ULONG ReferenceCount; + ULONG DriveMap; + UCHAR DriveType[32]; +} DEVICE_MAP, *PDEVICE_MAP; + +/* Handle table entry structure definition */ +typedef struct _HANDLE_TABLE_ENTRY +{ + union + { + PVOID Object; + ULONG_PTR ObAttributes; + PHANDLE_TABLE_ENTRY_INFO InfoTable; + ULONG_PTR Value; + }; + union + { + ULONG GrantedAccess; + struct + { + USHORT GrantedAccessIndex; + USHORT CreatorBackTraceIndex; + }; + LONG NextFreeTableEntry; + }; +} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY; + +/* Handle table entry info structure definition */ +typedef struct _HANDLE_TABLE_ENTRY_INFO +{ + ULONG AuditMask; +} HANDLE_TABLE_ENTRY_INFO, *PHANDLE_TABLE_ENTRY_INFO; + +/* Handle table structure definition */ +typedef struct _HANDLE_TABLE +{ + ULONG_PTR TableCode; + PEPROCESS QuotaProcess; + PVOID UniqueProcessId; + KPUSH_LOCK HandleTableLock[4]; + LIST_ENTRY HandleTableList; + KPUSH_LOCK HandleContentionEvent; + PVOID Reserved; + LONG ExtraInfoPages; + union + { + ULONG Flags; + UCHAR StrictFIFO:1; + }; + PHANDLE_TABLE_ENTRY FirstFreeHandle; + PHANDLE_TABLE_ENTRY LastFreeHandle; + LONG HandleCount; + ULONG NextHandleNeedingPool; +} HANDLE_TABLE, *PHANDLE_TABLE; + +/* Parameters provided by a caller when creating or opening an object */ +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + +/* Internal data stored during object creation */ +typedef struct _OBJECT_CREATE_INFORMATION +{ + ULONG Attributes; + HANDLE RootDirectory; + PVOID ParseContext; + KPROCESSOR_MODE ProbeMode; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG SecurityDescriptorCharge; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PSECURITY_QUALITY_OF_SERVICE SecurityQos; + SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; +} OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION; + +/* Optional header storing information about the object's creator */ +typedef struct _OBJECT_CREATOR_INFO +{ + LIST_ENTRY TypeList; + HANDLE CreatorProcessId; +} OBJECT_CREATOR_INFO, *POBJECT_CREATOR_INFO; + +/* Directory object used to structure the namespace hierarchy */ +typedef struct _OBJECT_DIRECTORY +{ + POBJECT_DIRECTORY_ENTRY HashBuckets[OBJECT_NUMBER_HASH_BUCKETS]; + KPUSH_LOCK Lock; + PDEVICE_MAP DeviceMap; + ULONG SessionId; +} OBJECT_DIRECTORY, *POBJECT_DIRECTORY; + +/* Linked list entry representing an object within a directory bucket */ +typedef struct _OBJECT_DIRECTORY_ENTRY +{ + POBJECT_DIRECTORY_ENTRY ChainLink; + PVOID Object; + ULONG HashValue; +} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY; + +/* Control structure used during object diagnostic dumps */ +typedef struct _OBJECT_DUMP_CONTROL +{ + PVOID Stream; + ULONG Detail; +} OBJECT_DUMP_CONTROL, *POBJECT_DUMP_CONTROL; + +/* Handle table interface union definition */ +typedef union _OBJECT_HANDLE +{ + struct + { + ULONG TagBits:2; + ULONG Index:30; + }; + HANDLE GenericHandleOverlay; + ULONG_PTR Value; +} OBJECT_HANDLE, *POBJECT_HANDLE; + +/* Entry tracking the number of open handles a specific process holds */ +typedef struct _OBJECT_HANDLE_COUNT_ENTRY +{ + PEPROCESS OwningProcess; + ULONG HandleTableIndex; + ULONG HandleCount; +} OBJECT_HANDLE_COUNT_ENTRY, *POBJECT_HANDLE_COUNT_ENTRY; + +/* Database array tracking handle counts for objects opened by processes */ +typedef struct _OBJECT_HANDLE_COUNT_DATABASE +{ + ULONG CountEntries; + OBJECT_HANDLE_COUNT_ENTRY HandleCountEntries[1]; +} OBJECT_HANDLE_COUNT_DATABASE, *POBJECT_HANDLE_COUNT_DATABASE; + +/* Database tracking all handle counts across different processes */ +typedef struct _OBJECT_HANDLE_COUNT_INFORMATION +{ + ULONG TotalHandleCount; + ULONG EntryCount; + POBJECT_HANDLE_COUNT_ENTRY Entries; +} OBJECT_HANDLE_COUNT_INFORMATION, *POBJECT_HANDLE_COUNT_INFORMATION; + +/* Optional header containing the handle count database */ +typedef struct _OBJECT_HANDLE_INFO +{ + OBJECT_HANDLE_COUNT_INFORMATION HandleCounts; +} OBJECT_HANDLE_INFO, *POBJECT_HANDLE_INFO; + +/* Object Handle Information */ +typedef struct _OBJECT_HANDLE_INFORMATION +{ + ULONG HandleAttributes; + ACCESS_MASK GrantedAccess; +} OBJECT_HANDLE_INFORMATION, *POBJECT_HANDLE_INFORMATION; + +/* Core object header */ +typedef struct _OBJECT_HEADER +{ + LONG_PTR PointerCount; + union + { + LONG_PTR HandleCount; + VOLATILE PVOID NextToFree; + }; + POBJECT_TYPE Type; + UCHAR NameInfoOffset; + UCHAR HandleInfoOffset; + UCHAR QuotaInfoOffset; + UCHAR Flags; + union + { + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + PVOID QuotaBlockCharged; + }; + PSECURITY_DESCRIPTOR SecurityDescriptor; + QUAD Body; +} OBJECT_HEADER, *POBJECT_HEADER; + +/* Creator tracking information */ +typedef struct _OBJECT_HEADER_CREATOR_INFO +{ + LIST_ENTRY TypeList; + PVOID CreatorUniqueProcess; + USHORT CreatorBackTraceIndex; + USHORT Reserved; +} OBJECT_HEADER_CREATOR_INFO, *POBJECT_HEADER_CREATOR_INFO; + +/* Union representing either a single handle count entry or a full database */ +typedef union _OBJECT_HEADER_HANDLE_INFO +{ + POBJECT_HANDLE_COUNT_DATABASE HandleCountDatabase; + OBJECT_HANDLE_COUNT_ENTRY SingleEntry; +} OBJECT_HEADER_HANDLE_INFO, *POBJECT_HEADER_HANDLE_INFO; + +/* Name information stored in the object header */ +typedef struct _OBJECT_HEADER_NAME_INFO +{ + POBJECT_DIRECTORY Directory; + UNICODE_STRING Name; + ULONG QueryReferences; + ULONG Reserved; + ULONG DbgReferenceCount; +} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO; + +/* Active quota information stored in the object header */ +typedef struct _OBJECT_HEADER_QUOTA_INFO +{ + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG SecurityDescriptorCharge; + PEPROCESS ExclusiveProcess; +} OBJECT_HEADER_QUOTA_INFO, *POBJECT_HEADER_QUOTA_INFO; + +/* Context maintained during namespace traversal and directory lookups */ +typedef struct _OBJECT_LOOKUP_CONTEXT +{ + POBJECT_DIRECTORY Directory; + PVOID Object; + USHORT HashIndex; + BOOLEAN DirectoryLocked; + VOLATILE ULONG LockStateSignature; +} OBJECT_LOOKUP_CONTEXT, *POBJECT_LOOKUP_CONTEXT; + +/* Optional header storing the object's hierarchical name and directory links */ +typedef struct _OBJECT_NAME_INFO +{ + LIST_ENTRY ObjectLinks; + UNICODE_STRING ObjectName; + PWSTR ObjectDirectoryPath; +} OBJECT_NAME_INFO, *POBJECT_NAME_INFO; + +/* Structure used to query an object's name */ +typedef struct _OBJECT_NAME_INFORMATION +{ + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +/* Memory layout sizes for the object's optional headers */ +typedef struct _OBJECT_OPTIONAL_HEADER_LAYOUT +{ + ULONG QuotaInfoSize; + ULONG HandleInfoSize; + ULONG NameInfoSize; + ULONG CreatorInfoSize; + ULONG TotalSize; +} OBJECT_OPTIONAL_HEADER_LAYOUT, *POBJECT_OPTIONAL_HEADER_LAYOUT; + +/* Information block linking an object to a specific process */ +typedef struct _OBJECT_PROCESS_INFO +{ + LIST_ENTRY Entry; + PEPROCESS Process; + ULONG ReferenceCount; +} OBJECT_PROCESS_INFO, *POBJECT_PROCESS_INFO; + +/* Optional header tracking memory pool charges */ +typedef struct _OBJECT_QUOTA_INFO +{ + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG SecurityDescriptorCharge; + PEPROCESS ExclusiveProcess; +} OBJECT_QUOTA_INFO, *POBJECT_QUOTA_INFO; + +/* Configuration block defining the lifecycle and behavior of a specific object type */ +typedef struct _OBJECT_TYPE_INITIALIZER +{ + USHORT Length; + BOOLEAN UseDefaultObject; + BOOLEAN CaseInsensitive; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + BOOLEAN MaintainTypeList; + MMPOOL_TYPE PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; + POB_DUMP_METHOD DumpProcedure; + POB_OPEN_METHOD OpenProcedure; + POB_CLOSE_METHOD CloseProcedure; + POB_DELETE_METHOD DeleteProcedure; + POB_PARSE_METHOD ParseProcedure; + POB_SECURITY_METHOD SecurityProcedure; + POB_QUERYNAME_METHOD QueryNameProcedure; + POB_OKAYTOCLOSE_METHOD OkayToCloseProcedure; +} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; + + +/* Descriptor representing a registered object type in the system */ +typedef struct _OBJECT_TYPE +{ + LIST_ENTRY TypeList; + UNICODE_STRING Name; + PVOID DefaultObject; + ULONG Index; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + OBJECT_TYPE_INITIALIZER TypeInfo; + KPUSH_LOCK TypeLock; + ULONG Key; + LIST_ENTRY CallbackList; +} OBJECT_TYPE, *POBJECT_TYPE; + +/* System handle table entry structure definition */ +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO +{ + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO; + +/* System extended handle information structure definition */ +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX +{ + PVOID Object; + ULONG_PTR UniqueProcessId; + ULONG_PTR HandleValue; + ULONG GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; + +/* System handle information structure definition */ +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG NumberOfHandles; + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; +} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; + +/* System extended handle information structure definition */ +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; + +#endif /* __XTOS_ASSEMBLER__ */ +#endif /* __XTDK_OBTYPES_H */ diff --git a/sdk/xtdk/potypes.h b/sdk/xtdk/potypes.h index feb5972..d426e62 100644 --- a/sdk/xtdk/potypes.h +++ b/sdk/xtdk/potypes.h @@ -14,6 +14,10 @@ #include +/* Processor performance scale factor */ +#define POWER_PERFORMANCE_SCALE 100 + + /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ @@ -21,6 +25,56 @@ typedef VOID (XTFASTCALL *PPROCESSOR_IDLE_FUNCTION)(IN PPROCESSOR_POWER_STATE PowerState); typedef XTSTATUS (XTFASTCALL *PSET_PROCESSOR_THROTTLE)(IN UCHAR Throttle); +/* Device power states */ +typedef enum _DEVICE_POWER_STATE +{ + PowerDeviceUnspecified = 0, + PowerDeviceD0, + PowerDeviceD1, + PowerDeviceD2, + PowerDeviceD3, + PowerDeviceMaximum +} DEVICE_POWER_STATE, *PDEVICE_POWER_STATE; + +/* Power actions list */ +typedef enum _POWER_ACTION +{ + PowerActionNone = 0, + PowerActionReserved, + PowerActionSleep, + PowerActionHibernate, + PowerActionShutdown, + PowerActionShutdownReset, + PowerActionShutdownOff, + PowerActionWarmEject +} POWER_ACTION, *PPOWER_ACTION; + +typedef enum _POWER_STATE_TYPE +{ + SystemPowerState = 0, + DevicePowerState +} POWER_STATE_TYPE, *PPOWER_STATE_TYPE; + +/* System power states */ +typedef enum _SYSTEM_POWER_STATE +{ + PowerSystemUnspecified = 0, + PowerSystemWorking, + PowerSystemSleeping1, + PowerSystemSleeping2, + PowerSystemSleeping3, + PowerSystemHibernate, + PowerSystemShutdown, + PowerSystemMaximum +} SYSTEM_POWER_STATE, *PSYSTEM_POWER_STATE; + +/* Power state union definition */ +typedef union _POWER_STATE +{ + SYSTEM_POWER_STATE SystemState; + DEVICE_POWER_STATE DeviceState; +} POWER_STATE, *PPOWER_STATE; + /* Processor IDLE times structure definition */ typedef struct _PROCESSOR_IDLE_TIMES { @@ -91,5 +145,24 @@ typedef struct _PROCESSOR_POWER_STATE ULONG LastC3UserTime; } PROCESSOR_POWER_STATE, *PPROCESSOR_POWER_STATE; +/* System power state context structure definition */ +typedef struct _SYSTEM_POWER_STATE_CONTEXT +{ + union + { + struct + { + ULONG Reserved1:8; + ULONG TargetSystemState:4; + ULONG EffectiveSystemState:4; + ULONG CurrentSystemState:4; + ULONG IgnoreHibernationPath:1; + ULONG PseudoTransition:1; + ULONG Reserved2:10; + }; + ULONG ContextAsUlong; + }; +} SYSTEM_POWER_STATE_CONTEXT, *PSYSTEM_POWER_STATE_CONTEXT; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_POTYPES_H */ diff --git a/sdk/xtdk/pstypes.h b/sdk/xtdk/pstypes.h index 6c606b2..e311957 100644 --- a/sdk/xtdk/pstypes.h +++ b/sdk/xtdk/pstypes.h @@ -10,25 +10,304 @@ #define __XTDK_PSTYPES_H #include -#include +#include +#include +#include +#include +#include +/* Quota bypass marker */ +#define PS_QUOTA_BYPASS_MARKER ((PEPROCESS_QUOTA_BLOCK)1) + +/* Current process & thread handles */ +#define PS_CURRENT_PROCESS_HANDLE ((HANDLE)(LONG_PTR)-1) +#define PS_CURRENT_THREAD_HANDLE ((HANDLE)(LONG_PTR)-2) + +/* Generic access rights mapping for process */ +#define PS_PROCESS_GENERIC_MAPPING {SE_STANDARD_RIGHTS_READ | \ + SE_PROCESS_QUERY_INFORMATION | \ + SE_PROCESS_VM_READ, \ + SE_STANDARD_RIGHTS_WRITE | \ + SE_PROCESS_CREATE_PROCESS | \ + SE_PROCESS_CREATE_THREAD | \ + SE_PROCESS_DUP_HANDLE | \ + SE_PROCESS_SET_INFORMATION | \ + SE_PROCESS_SET_QUOTA | \ + SE_PROCESS_SUSPEND_RESUME | \ + SE_PROCESS_TERMINATE | \ + SE_PROCESS_VM_OPERATION | \ + SE_PROCESS_VM_WRITE, \ + SE_STANDARD_RIGHTS_EXECUTE | \ + SE_PROCESS_ALL_ACCESS | \ + SE_SYNCHRONIZE} \ + +/* Generic access rights mapping for thread */ +#define PS_THREAD_GENERIC_MAPPING {SE_STANDARD_RIGHTS_READ | \ + SE_THREAD_GET_CONTEXT | \ + SE_THREAD_QUERY_INFORMATION, \ + SE_STANDARD_RIGHTS_WRITE | \ + SE_THREAD_ALERT | \ + SE_THREAD_SET_CONTEXT | \ + SE_THREAD_SET_INFORMATION | \ + SE_THREAD_SUSPEND_RESUME | \ + SE_THREAD_TERMINATE, \ + SE_STANDARD_RIGHTS_EXECUTE | \ + SE_THREAD_ALL_ACCESS | \ + SE_SYNCHRONIZE} + /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ +/* Process quota types */ +typedef enum _PS_QUOTA_TYPE +{ + PsNonPagedPool, + PsPagedPool, + PsPageFile, + PsQuotaTypes +} PS_QUOTA_TYPE, *PPS_QUOTA_TYPE; + /* Kernel's representation of a process object */ typedef struct _EPROCESS { KPROCESS ProcessControlBlock; - UINT Reserved0; + KPUSH_LOCK ProcessLock; + LARGE_INTEGER CreateTime; + LARGE_INTEGER ExitTime; + EX_RUNDOWN_REFERENCE RundownProtect; + HANDLE UniqueProcessId; + LIST_ENTRY ActiveProcessLinks; + SIZE_T QuotaUsage[PsQuotaTypes]; + SIZE_T QuotaPeak[PsQuotaTypes]; + PVOID DebugPort; + PVOID ExceptionPort; + PHANDLE_TABLE ObjectTable; + PVOID Job; + PVOID SectionObject; + PVOID SectionBaseAddress; + PEPROCESS_QUOTA_BLOCK QuotaBlock; + HANDLE InheritedFromUniqueProcessId; + PVOID DeviceMap; + CHAR ImageFileName[16]; + LIST_ENTRY ThreadListHead; + ACCESS_MASK GrantedAccess; + ULONG DefaultHardErrorProcessing; + PPEB ProcessEnvironmentBlock; + SECURITY_AUDIT_PROCESS_CREATION_INFO AuditProcessCreationInfo; + MMSUPPORT Vm; + union + { + struct + { + ULONG CreateReported:1; + ULONG NoDebugInherit:1; + ULONG ProcessExiting:1; + ULONG ProcessDelete:1; + ULONG Reserved1:1; + ULONG VmDeleted:1; + ULONG OutswapEnabled:1; + ULONG Outswapped:1; + ULONG ForkFailed:1; + ULONG Reserved2:1; + ULONG AddressSpaceInitialized:2; + ULONG SetTimerResolution:1; + ULONG BreakOnTermination:1; + ULONG DeprioritizeViews:1; + ULONG WriteWatch:1; + ULONG ProcessInSession:1; + ULONG OverrideAddressSpace:1; + ULONG HasAddressSpace:1; + ULONG LaunchPrefetched:1; + ULONG InjectInpageErrors:1; + ULONG VmTopDown:1; + ULONG ImageNotifyDone:1; + ULONG PdeUpdateNeeded:1; + ULONG Reserved3:1; + ULONG SmapAllowed:1; + ULONG ProcessInserted:1; + ULONG DefaultIoPriority:3; + ULONG Reserved4:1; + ULONG Reserved5:1; + }; + ULONG Flags; + }; + XTSTATUS ExitStatus; + UCHAR PriorityClass; } EPROCESS, *PEPROCESS; +/* Kernel's representation of a process quota entry*/ +typedef struct _EPROCESS_QUOTA_ENTRY +{ + SIZE_T Usage; + SIZE_T Limit; + SIZE_T Peak; + SIZE_T Return; +} EPROCESS_QUOTA_ENTRY, *PEPROCESS_QUOTA_ENTRY; + +/* Kernel's representation of a process quota block */ +typedef struct _EPROCESS_QUOTA_BLOCK +{ + EPROCESS_QUOTA_ENTRY QuotaEntry[PsQuotaTypes]; + LIST_ENTRY QuotaList; + ULONG ReferenceCount; + ULONG ProcessCount; +} EPROCESS_QUOTA_BLOCK, *PEPROCESS_QUOTA_BLOCK; + /* Kernel's representation of a thread object */ typedef struct _ETHREAD { KTHREAD ThreadControlBlock; - UINT Reserved0; + ACCESS_MASK GrantedAccess; } ETHREAD, *PETHREAD; +/* Kernel's representation of a process environment block */ +typedef struct _PEB +{ + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + union + { + BOOLEAN BitField; + struct + { + BOOLEAN ImageUsesLargePages:1; + BOOLEAN IsProtectedProcess:1; + BOOLEAN IsLegacyProcess:1; + BOOLEAN IsImageDynamicallyRelocated:1; + BOOLEAN SkipPatchingUser32Forwarders:1; + BOOLEAN SpareBits:3; + }; + }; + HANDLE Mutant; + PVOID ImageBaseAddress; + PLDR_PEB_DATA Ldr; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID AltThunkSListPtr; + PVOID SparePtr2; + ULONG EnvironmentUpdateCount; + PVOID KernelCallbackTable; + ULONG SystemReserved[1]; + ULONG SpareUlong; + PPEB_FREE_BLOCK FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[2]; + PVOID ReadOnlySharedMemoryBase; + PVOID HotpatchInformation; + PVOID *ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG GlobalFlag; + LARGE_INTEGER CriticalSectionTimeout; + ULONG_PTR HeapSegmentReserve; + ULONG_PTR HeapSegmentCommit; + ULONG_PTR HeapDeCommitTotalFreeThreshold; + ULONG_PTR HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID *ProcessHeaps; + PVOID ProcessStarterHelper; + ULONG ImageSubsystem; + ULONG ImageSubsystemMajorVersion; + ULONG ImageSubsystemMinorVersion; + ULONG_PTR ImageProcessAffinityMask; + PVOID TlsExpansionBitmap; + ULONG TlsExpansionBitmapBits[32]; + ULONG SessionId; + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + PVOID pShimData; + PVOID AppCompatInfo; + UNICODE_STRING CSDVersion; + ULONG_PTR MinimumStackCommit; + PVOID *FlsCallback; + LIST_ENTRY FlsListHead; + PVOID FlsBitmap; + ULONG FlsBitmapBits[4]; + ULONG FlsHighIndex; +} PEB, *PPEB; + +/* Process Environment Block Free Block structure definition */ +typedef struct _PEB_FREE_BLOCK +{ + PPEB_FREE_BLOCK Next; + ULONG Size; +} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK; + +/* Kernel's representation of a thread environment block */ +typedef struct _TEB +{ + THREAD_INFORMATION_BLOCK InformationBlock; + PVOID EnvironmentPointer; + CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + ULONG UserReserved[5]; + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + PVOID SystemReserved1[54]; + LONG ExceptionCode; + PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; + CLIENT_ID RealClientId; + ULONG LastStatusValue; + UNICODE_STRING StaticUnicodeString; + WCHAR StaticUnicodeBuffer[261]; + PVOID DeallocationStack; + PVOID TlsSlots[64]; + LIST_ENTRY TlsLinks; + PVOID ReservedForNtRpc; + PVOID DbgSsReserved[2]; + ULONG HardErrorMode; + PVOID Instrumentation[14]; + PVOID SubProcessTag; + PVOID EtwTraceData; + PVOID WinSockData; + BOOLEAN InDbgPrint; + BOOLEAN FreeStackOnTermination; + BOOLEAN HasFiberData; + UCHAR IdealProcessor; + ULONG GuaranteedStackBytes; + PVOID ReservedForPerf; + PVOID ReservedForOle; + ULONG WaitingOnLoaderLock; + ULONG_PTR SparePointer1; + ULONG_PTR SoftPatchPtr1; + ULONG_PTR SoftPatchPtr2; + PVOID *TlsExpansionSlots; + ULONG ImpersonationLocale; + ULONG IsImpersonating; + PVOID NlsCache; + PVOID ShimData; + ULONG HeapVirtualAffinity; + HANDLE CurrentTransactionHandle; + PTEB_ACTIVE_FRAME ActiveFrame; + PVOID FlsData; + BOOLEAN SafeThunkCall; + BOOLEAN BooleanSpare[3]; +} TEB, *PTEB; + +/* Thread Environment Block Active Frame structure definition */ +typedef struct _TEB_ACTIVE_FRAME +{ + ULONG Flags; + PTEB_ACTIVE_FRAME Previous; + PTEB_ACTIVE_FRAME_CONTEXT Context; +} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME; + +/* Thread Environment Block Active Frame Context structure definition */ +typedef struct _TEB_ACTIVE_FRAME_CONTEXT +{ + ULONG Flags; + LPSTR FrameName; +} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT; + #endif /* __XTOS_ASSEMBLER__ */ #endif /* __XTDK_PSTYPES_H */ diff --git a/sdk/xtdk/rtlfuncs.h b/sdk/xtdk/rtlfuncs.h index 33d50f2..7999ad2 100644 --- a/sdk/xtdk/rtlfuncs.h +++ b/sdk/xtdk/rtlfuncs.h @@ -123,6 +123,12 @@ RtlCopyString(IN PCHAR Destination, IN PCSTR Source, IN ULONG Length); +XTCLINK +XTAPI +VOID +RtlCopyUnicodeString(IN OUT PUNICODE_STRING Destination, + IN PCUNICODE_STRING Source); + XTCLINK XTAPI VOID @@ -187,6 +193,18 @@ XTCDECL VOID RtlInitializeListHead(IN PLIST_ENTRY ListHead); +XTCLINK +XTAPI +VOID +RtlInitializeUnicodeString(OUT PUNICODE_STRING Destination, + IN PCWSTR Source); + +XTCLINK +XTAPI +XTSTATUS +RtlInitializeUnicodeStringEx(OUT PUNICODE_STRING Destination, + IN PCWSTR Source); + XTCLINK XTCDECL VOID diff --git a/sdk/xtdk/rtltypes.h b/sdk/xtdk/rtltypes.h index 166c303..c2ba09e 100644 --- a/sdk/xtdk/rtltypes.h +++ b/sdk/xtdk/rtltypes.h @@ -4,6 +4,7 @@ * FILE: sdk/xtdk/rtltypes.h * DESCRIPTION: Runtime library structures definitions * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #ifndef __XTDK_RTLTYPES_H @@ -11,6 +12,7 @@ #include #include +#include ARCH_HEADER(xtstruct.h) /* UUID string lengths */ @@ -32,6 +34,23 @@ #define DOUBLE_SCIENTIFIC_PRECISION -4 #define DOUBLE_SIGN_BIT 0x8000000000000000ULL +/* Exception Record flags */ +#define EXCEPTION_CONTINUE_SEARCH 0x00 +#define EXCEPTION_NONCONTINUABLE 0x01 +#define EXCEPTION_UNWINDING 0x02 +#define EXCEPTION_EXIT_UNWIND 0x04 +#define EXCEPTION_STACK_INVALID 0x08 +#define EXCEPTION_NESTED_CALL 0x10 +#define EXCEPTION_TARGET_UNWIND 0x20 +#define EXCEPTION_COLLIDED_UNWIND 0x40 + +/* Exception Record accessors */ +#define EXCEPTION_CODE _exception_code() +#define EXCEPTION_INFORMATION (PEXCEPTION_POINTERS)_exception_info() + +/* Maximum number of lead bytes for NLS */ +#define NLS_MAXIMUM_LEADBYTES 12 + /* Print flag definitions */ #define PFL_ALWAYS_PRINT_SIGN 0x00000001 #define PFL_SPACE_FOR_PLUS 0x00000002 @@ -72,6 +91,74 @@ typedef XTSTATUS (*PWRITE_CHARACTER)(IN CHAR Character); typedef XTSTATUS (*PWRITE_WIDE_CHARACTER)(IN WCHAR Character); +/* Compressed data information structure definition */ +typedef struct _COMPRESSED_DATA_INFO +{ + USHORT CompressionFormatAndEngine; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved; + USHORT NumberOfChunks; + ULONG CompressedChunkSizes[1]; +} COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO; + +/* Code page table structure definition */ +typedef struct _CPTABLE_INFO +{ + USHORT CodePage; + USHORT MaximumCharacterSize; + USHORT DefaultChar; + USHORT UniDefaultChar; + USHORT TransDefaultChar; + USHORT TransUniDefaultChar; + USHORT DBCSCodePage; + UCHAR LeadByte[NLS_MAXIMUM_LEADBYTES]; + PUSHORT MultiByteTable; + PVOID WideCharTable; + PUSHORT DBCSRanges; + PUSHORT DBCSOffsets; +} CPTABLE_INFO, *PCPTABLE_INFO; + +/* Exception Pointers structure definition */ +typedef struct _EXCEPTION_POINTERS +{ + PEXCEPTION_RECORD ExceptionRecord; + PCONTEXT ContextRecord; +} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS; + +/* 128-bit buffer containing a unique identifier value */ +typedef struct _GUID +{ + UINT Data1; + USHORT Data2; + USHORT Data3; + UCHAR Data4[8]; +} GUID, *PGUID; + +/* 32-bit double linked list structure definition */ +typedef struct _LIST_ENTRY32 +{ + ULONG Flink; + ULONG Blink; +} LIST_ENTRY32, *PLIST_ENTRY32; + +/* 64-bit double linked list structure definition */ +typedef struct _LIST_ENTRY64 +{ + ULONGLONG Flink; + ULONGLONG Blink; +} LIST_ENTRY64, *PLIST_ENTRY64; + +/* NLS table structure definition */ +typedef struct _NLSTABLE_INFO +{ + CPTABLE_INFO OemTableInfo; + CPTABLE_INFO AnsiTableInfo; + PUSHORT UpperCaseTable; + PUSHORT LowerCaseTable; +} NLSTABLE_INFO, *PNLSTABLE_INFO; + /* Red-black tree node color enumeration list */ typedef enum _RTL_BALANCED_NODE_COLOR { @@ -95,6 +182,24 @@ typedef enum _RTL_VARIABLE_TYPE TypeWideString } RTL_VARIABLE_TYPE, *PRTL_VARIABLE_TYPE; +/* Activation context stack structure definition */ +typedef struct _ACTIVATION_CONTEXT_STACK +{ + PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame; + LIST_ENTRY FrameListCache; + ULONG Flags; + ULONG NextCookieSequenceNumber; + ULONG StackId; +} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; + +/* Activation context stack frame structure definition */ +typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME +{ + PRTL_ACTIVATION_CONTEXT_STACK_FRAME Previous; + PVOID ActivationContext; + ULONG Flags; +} RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME; + /* Runtime Library red-black tree balanced node structure definition */ typedef struct _RTL_BALANCED_NODE { @@ -156,6 +261,12 @@ typedef struct _RTL_SHA1_CONTEXT UCHAR Buffer[SHA1_BLOCK_SIZE]; } RTL_SHA1_CONTEXT, *PRTL_SHA1_CONTEXT; +/* Single linked list structure definition */ +typedef struct _SINGLE_LIST_ENTRY +{ + PSINGLE_LIST_ENTRY Next; +} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; + /* Runtime time fields structure definition */ typedef struct _TIME_FIELDS { diff --git a/sdk/xtdk/setypes.h b/sdk/xtdk/setypes.h new file mode 100644 index 0000000..7213a63 --- /dev/null +++ b/sdk/xtdk/setypes.h @@ -0,0 +1,398 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: sdk/xtdk/setypes.h + * DESCRIPTION: Kernel Security structures and definitions + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTDK_SETYPES_H +#define __XTDK_SETYPES_H + +#include +#include +#include + + +/* Privilege LUIDs */ +#define SE_LUID_MIN_WELL_KNOWN_PRIVILEGE (LUID){2, 0} +#define SE_LUID_CREATE_TOKEN_PRIVILEGE (LUID){2, 0} +#define SE_LUID_ASSIGNPRIMARYTOKEN_PRIVILEGE (LUID){3, 0} +#define SE_LUID_LOCK_MEMORY_PRIVILEGE (LUID){4, 0} +#define SE_LUID_INCREASE_QUOTA_PRIVILEGE (LUID){5, 0} +#define SE_LUID_MACHINE_ACCOUNT_PRIVILEGE (LUID){6, 0} +#define SE_LUID_TCB_PRIVILEGE (LUID){7, 0} +#define SE_LUID_SECURITY_PRIVILEGE (LUID){8, 0} +#define SE_LUID_TAKE_OWNERSHIP_PRIVILEGE (LUID){9, 0} +#define SE_LUID_LOAD_DRIVER_PRIVILEGE (LUID){10, 0} +#define SE_LUID_SYSTEM_PROFILE_PRIVILEGE (LUID){11, 0} +#define SE_LUID_SYSTEMTIME_PRIVILEGE (LUID){12, 0} +#define SE_LUID_PROF_SINGLE_PROCESS_PRIVILEGE (LUID){13, 0} +#define SE_LUID_INC_BASE_PRIORITY_PRIVILEGE (LUID){14, 0} +#define SE_LUID_CREATE_PAGEFILE_PRIVILEGE (LUID){15, 0} +#define SE_LUID_CREATE_PERMANENT_PRIVILEGE (LUID){16, 0} +#define SE_LUID_BACKUP_PRIVILEGE (LUID){17, 0} +#define SE_LUID_RESTORE_PRIVILEGE (LUID){18, 0} +#define SE_LUID_SHUTDOWN_PRIVILEGE (LUID){19, 0} +#define SE_LUID_DEBUG_PRIVILEGE (LUID){20, 0} +#define SE_LUID_AUDIT_PRIVILEGE (LUID){21, 0} +#define SE_LUID_SYSTEM_ENVIRONMENT_PRIVILEGE (LUID){22, 0} +#define SE_LUID_CHANGE_NOTIFY_PRIVILEGE (LUID){23, 0} +#define SE_LUID_REMOTE_SHUTDOWN_PRIVILEGE (LUID){24, 0} +#define SE_LUID_UNDOCK_PRIVILEGE (LUID){25, 0} +#define SE_LUID_SYNC_AGENT_PRIVILEGE (LUID){26, 0} +#define SE_LUID_ENABLE_DELEGATION_PRIVILEGE (LUID){27, 0} +#define SE_LUID_MANAGE_VOLUME_PRIVILEGE (LUID){28, 0} +#define SE_LUID_IMPERSONATE_PRIVILEGE (LUID){29, 0} +#define SE_LUID_CREATE_GLOBAL_PRIVILEGE (LUID){30, 0} +#define SE_LUID_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (LUID){31, 0} +#define SE_LUID_RELABEL_PRIVILEGE (LUID){32, 0} +#define SE_LUID_INC_WORKING_SET_PRIVILEGE (LUID){33, 0} +#define SE_LUID_TIME_ZONE_PRIVILEGE (LUID){34, 0} +#define SE_LUID_CREATE_SYMBOLIC_LINK_PRIVILEGE (LUID){35, 0} + +/* Standard Access Rights definitions */ +#define SE_DELETE 0x00010000L +#define SE_READ_CONTROL 0x00020000L +#define SE_WRITE_DAC 0x00040000L +#define SE_WRITE_OWNER 0x00080000L +#define SE_SYNCHRONIZE 0x00100000L +#define SE_STANDARD_RIGHTS_REQUIRED 0x000F0000L +#define SE_STANDARD_RIGHTS_READ SE_READ_CONTROL +#define SE_STANDARD_RIGHTS_WRITE SE_READ_CONTROL +#define SE_STANDARD_RIGHTS_EXECUTE SE_READ_CONTROL +#define SE_STANDARD_RIGHTS_ALL 0x001F0000L +#define SE_SPECIFIC_RIGHTS_ALL 0x0000FFFFL +#define SE_ACCESS_SYSTEM_SECURITY 0x01000000L +#define SE_MAXIMUM_ALLOWED 0x02000000L + +/* Generic access rights definitions */ +#define SE_GENERIC_ALL 0x10000000L +#define SE_GENERIC_EXECUTE 0x20000000L +#define SE_GENERIC_WRITE 0x40000000L +#define SE_GENERIC_READ 0x80000000L + +/* Process access rights definitions */ +#define SE_PROCESS_TERMINATE 0x0001 +#define SE_PROCESS_CREATE_THREAD 0x0002 +#define SE_PROCESS_SET_SESSIONID 0x0004 +#define SE_PROCESS_VM_OPERATION 0x0008 +#define SE_PROCESS_VM_READ 0x0010 +#define SE_PROCESS_VM_WRITE 0x0020 +#define SE_PROCESS_DUP_HANDLE 0x0040 +#define SE_PROCESS_CREATE_PROCESS 0x0080 +#define SE_PROCESS_SET_QUOTA 0x0100 +#define SE_PROCESS_SET_INFORMATION 0x0200 +#define SE_PROCESS_QUERY_INFORMATION 0x0400 +#define SE_PROCESS_SUSPEND_RESUME 0x0800 +#define SE_PROCESS_QUERY_LIMITED_INFORMATION 0x1000 + +/* Process full control access mask */ +#define SE_PROCESS_ALL_ACCESS (SE_STANDARD_RIGHTS_REQUIRED | SE_SYNCHRONIZE | 0xFFFF) + +/* Thread access rights definitions */ +#define SE_THREAD_TERMINATE 0x0001 +#define SE_THREAD_SUSPEND_RESUME 0x0002 +#define SE_THREAD_ALERT 0x0004 +#define SE_THREAD_GET_CONTEXT 0x0008 +#define SE_THREAD_SET_CONTEXT 0x0010 +#define SE_THREAD_SET_INFORMATION 0x0020 +#define SE_THREAD_QUERY_INFORMATION 0x0040 +#define SE_THREAD_SET_THREAD_TOKEN 0x0080 +#define SE_THREAD_IMPERSONATE 0x0100 +#define SE_THREAD_DIRECT_IMPERSONATION 0x0200 + +/* Thread full control access mask */ +#define SE_THREAD_ALL_ACCESS (SE_STANDARD_RIGHTS_REQUIRED | SE_SYNCHRONIZE | 0xFFFF) + +/* Object full control access mask */ +#define SE_OBJECT_TYPE_ALL_ACCESS (SE_STANDARD_RIGHTS_REQUIRED | 0x1) + +/* Default security quota */ +#define SE_DEFAULT_SECURITY_QUOTA 2048 + +#define SE_INITIAL_PRIVILEGE_COUNT 3 + +/* Token source length */ +#define SE_TOKEN_SOURCE_LENGTH 8 + +/* C/C++ specific code */ +#ifndef __XTOS_ASSEMBLER__ + +/* The classification type for a security proxy token */ +typedef enum _PROXY_CLASS +{ + ProxyFull = 0, + ProxyService, + ProxyTree, + ProxyDirectory +} PROXY_CLASS, *PPROXY_CLASS; + +/* Security impersonation levels */ +typedef enum _SECURITY_IMPERSONATION_LEVEL +{ + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation +} SECURITY_IMPERSONATION_LEVEL, *PSECURITY_IMPERSONATION_LEVEL; + +/* Security operation codes */ +typedef enum _SECURITY_OPERATION_CODE +{ + SetSecurityDescriptor, + QuerySecurityDescriptor, + DeleteSecurityDescriptor, + AssignSecurityDescriptor +} SECURITY_OPERATION_CODE, *PSECURITY_OPERATION_CODE; + +/* Access token types enumeration list */ +typedef enum _TOKEN_TYPE +{ + TokenPrimary = 1, + TokenImpersonation +} TOKEN_TYPE, *PTOKEN_TYPE; + +/* Access Control List structure definition */ +typedef struct _ACL +{ + UCHAR AclRevision; + UCHAR Reserved1; + USHORT AclSize; + USHORT AceCount; + USHORT Reserved2; +} ACL, *PACL; + +/* Bitfields for granular security audit policy categories */ +typedef struct _AUDIT_POLICY_CATEGORIES +{ + UCHAR System:4; + UCHAR Logon:4; + UCHAR ObjectAccess:4; + UCHAR PrivilegeUse:4; + UCHAR DetailedTracking:4; + UCHAR PolicyChange:4; + UCHAR AccountManagement:4; + UCHAR DirectoryServiceAccess:4; + UCHAR AccountLogon:4; +} AUDIT_POLICY_CATEGORIES, *PAUDIT_POLICY_CATEGORIES; + +/* Overlay structure for manipulating audit policy bit masks */ +typedef struct _AUDIT_POLICY_OVERLAY +{ + ULONGLONG PolicyBits:36; + ULONGLONG SetBit:1; +} AUDIT_POLICY_OVERLAY, *PAUDIT_POLICY_OVERLAY; + +/* Audit policy structure definition */ +typedef union _AUDIT_POLICY +{ + AUDIT_POLICY_CATEGORIES PolicyElements; + AUDIT_POLICY_OVERLAY PolicyOverlay; + ULONGLONG Overlay; +} AUDIT_POLICY, *PAUDIT_POLICY; + +/* Generic security mapping structure definition */ +typedef struct _GENERIC_MAPPING +{ + ULONG GenericRead; + ULONG GenericWrite; + ULONG GenericExecute; + ULONG GenericAll; +} GENERIC_MAPPING, *PGENERIC_MAPPING; + +/* LUID and attributes structure definition */ +typedef struct _LUID_AND_ATTRIBUTES +{ + LUID Luid; + ULONG Attributes; +} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES; + +/* Initial privilege set structure definition */ +typedef struct _INITIAL_PRIVILEGE_SET +{ + ULONG PrivilegeCount; + ULONG Control; + LUID_AND_ATTRIBUTES Privilege[SE_INITIAL_PRIVILEGE_COUNT]; +} INITIAL_PRIVILEGE_SET, * PINITIAL_PRIVILEGE_SET; + +/* Privilege set structure definition */ +typedef struct _PRIVILEGE_SET +{ + ULONG PrivilegeCount; + ULONG Control; + LUID_AND_ATTRIBUTES Privilege[1]; +} PRIVILEGE_SET, *PPRIVILEGE_SET; + +/* Process audit information structure definition */ +typedef struct _SECURITY_PROCESS_AUDIT_INFO +{ + PEPROCESS Process; + PEPROCESS ParentProcess; +} SECURITY_PROCESS_AUDIT_INFO, *PSECURITY_PROCESS_AUDIT_INFO; + +/* Security audit process creation information structure definition */ +typedef struct _SECURITY_AUDIT_PROCESS_CREATION_INFO +{ + POBJECT_NAME_INFORMATION ImageFileName; +} SECURITY_AUDIT_PROCESS_CREATION_INFO, *PSECURITY_AUDIT_PROCESS_CREATION_INFO; + +/* Identifier authority structure definition */ +typedef struct _SID_IDENTIFIER_AUTHORITY +{ + UCHAR Value[6]; +} SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; + +/* Security identifier structure definition */ +typedef struct _SID +{ + UCHAR Revision; + UCHAR SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + ULONG SubAuthority[1]; +} SID, *PSID; + +/* Security Identifier with its corresponding state attributes structure definition */ +typedef struct _SID_ATTRIBUTES +{ + PSID Sid; + ULONG Attributes; +} SID_ATTRIBUTES, *PSID_ATTRIBUTES; + +/* Token source structure definition */ +typedef struct _TOKEN_SOURCE +{ + CHAR SourceName[SE_TOKEN_SOURCE_LENGTH]; + LUID SourceIdentifier; +} TOKEN_SOURCE, *PTOKEN_SOURCE; + +/* Token control structure definition */ +typedef struct _TOKEN_CONTROL +{ + LUID TokenId; + LUID AuthenticationId; + LUID ModifiedId; + TOKEN_SOURCE TokenSource; +} TOKEN_CONTROL, *PTOKEN_CONTROL; + +/* Security quality of service structure definition */ +typedef struct _SECURITY_QUALITY_OF_SERVICE +{ + ULONG Length; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; + BOOLEAN EffectiveOnly; +} SECURITY_QUALITY_OF_SERVICE, *PSECURITY_QUALITY_OF_SERVICE; + +/* Security client context structure definition */ +typedef struct _SECURITY_CLIENT_CONTEXT +{ + SECURITY_QUALITY_OF_SERVICE SecurityQos; + PACCESS_TOKEN ClientToken; + BOOLEAN DirectlyAccessClientToken; + BOOLEAN DirectAccessEffectiveOnly; + BOOLEAN ServerIsRemote; + TOKEN_CONTROL ClientTokenControl; +} SECURITY_CLIENT_CONTEXT, *PSECURITY_CLIENT_CONTEXT; + +/* Security subject context structure definition */ +typedef struct _SECURITY_SUBJECT_CONTEXT +{ + PACCESS_TOKEN ClientToken; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + PACCESS_TOKEN PrimaryToken; + PVOID ProcessAuditId; +} SECURITY_SUBJECT_CONTEXT, *PSECURITY_SUBJECT_CONTEXT; + +/* Per-token audit generation information and access masks structure definition */ +typedef struct _SECURITY_TOKEN_AUDIT_DATA +{ + ULONG Length; + ULONG GrantMask; + ULONG DenyMask; +} SECURITY_TOKEN_AUDIT_DATA, *PSECURITY_TOKEN_AUDIT_DATA; + +/* Security proxy configuration and constraint data structure definition */ +typedef struct _SECURITY_TOKEN_PROXY_DATA +{ + ULONG Length; + PROXY_CLASS ProxyClass; + UNICODE_STRING PathInfo; + ULONG ContainerMask; + ULONG ObjectMask; +} SECURITY_TOKEN_PROXY_DATA, *PSECURITY_TOKEN_PROXY_DATA; + +/* Active references, device mappings, and tokens tracking data structure definition */ +typedef struct _SESSION_REFERENCES +{ + PSESSION_REFERENCES Next; + LUID LogonId; + ULONG ReferenceCount; + ULONG Flags; + PDEVICE_MAP DeviceMap; + LIST_ENTRY TokenList; +} SESSION_REFERENCES, *PSESSION_REFERENCES; + +/* Access state structure definition */ +typedef struct _ACCESS_STATE +{ + LUID OperationID; + BOOLEAN SecurityEvaluated; + BOOLEAN GenerateAudit; + BOOLEAN GenerateOnClose; + BOOLEAN PrivilegesAllocated; + ULONG Flags; + ACCESS_MASK RemainingDesiredAccess; + ACCESS_MASK PreviouslyGrantedAccess; + ACCESS_MASK OriginalDesiredAccess; + SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PVOID AuxData; + union + { + INITIAL_PRIVILEGE_SET InitialPrivilegeSet; + PRIVILEGE_SET PrivilegeSet; + } Privileges; + BOOLEAN AuditPrivileges; + UNICODE_STRING ObjectName; + UNICODE_STRING ObjectTypeName; +} ACCESS_STATE, *PACCESS_STATE; + +/* The core access token structure definition */ +typedef struct _TOKEN +{ + TOKEN_SOURCE TokenSource; + LUID TokenId; + LUID AuthenticationId; + LUID ParentTokenId; + LARGE_INTEGER ExpirationTime; + PERESOURCE TokenLock; + AUDIT_POLICY AuditPolicy; + LUID ModifiedId; + ULONG SessionId; + ULONG UserAndGroupCount; + ULONG RestrictedSidCount; + ULONG PrivilegeCount; + ULONG VariableLength; + ULONG DynamicCharged; + ULONG DynamicAvailable; + ULONG DefaultOwnerIndex; + PSID_ATTRIBUTES UserAndGroups; + PSID_ATTRIBUTES RestrictedSids; + PSID PrimaryGroup; + PLUID_AND_ATTRIBUTES Privileges; + PULONG DynamicPart; + PACL DefaultDacl; + TOKEN_TYPE TokenType; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + ULONG TokenFlags; + BOOLEAN TokenInUse; + PSECURITY_TOKEN_PROXY_DATA ProxyData; + PSECURITY_TOKEN_AUDIT_DATA AuditData; + PSESSION_REFERENCES LogonSession; + LUID OriginatingLogonSession; + ULONG VariablePart; +} TOKEN, *PTOKEN; + +#endif /* __XTOS_ASSEMBLER__ */ +#endif /* __XTDK_SETYPES_H */ diff --git a/sdk/xtdk/xtbase.h b/sdk/xtdk/xtbase.h index 2598f0b..5a4d2ac 100644 --- a/sdk/xtdk/xtbase.h +++ b/sdk/xtdk/xtbase.h @@ -17,6 +17,12 @@ /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ +/* Access mask */ +typedef ULONG ACCESS_MASK, *PACCESS_MASK; + +/* Device type */ +typedef ULONG DEVICE_TYPE; + /* Kernel affinity */ typedef ULONG_PTR KAFFINITY, *PKAFFINITY; @@ -32,6 +38,12 @@ typedef UCHAR KRUNLEVEL, *PKRUNLEVEL; /* Spin locks synchronization mechanism */ typedef ULONG_PTR KSPIN_LOCK, *PKSPIN_LOCK; +/* Locale identifier */ +typedef ULONG LCID; + +/* Access token */ +typedef PVOID PACCESS_TOKEN; + /* Page Frame Number count */ typedef ULONG PFN_COUNT; @@ -41,75 +53,14 @@ typedef ULONG_PTR PFN_NUMBER, *PPFN_NUMBER; /* Physical address */ typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; -/* 128-bit buffer containing a unique identifier value */ -typedef struct _GUID -{ - UINT Data1; - USHORT Data2; - USHORT Data3; - UCHAR Data4[8]; -} GUID, *PGUID; +/* Security descriptor */ +typedef PVOID PSECURITY_DESCRIPTOR; -/* Double linked list structure definition */ -typedef struct _LIST_ENTRY -{ - PLIST_ENTRY Flink; - PLIST_ENTRY Blink; -} LIST_ENTRY, *PLIST_ENTRY; +/* Security context tracking mode */ +typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE, *PSECURITY_CONTEXT_TRACKING_MODE; -/* 32-bit double linked list structure definition */ -typedef struct _LIST_ENTRY32 -{ - ULONG Flink; - ULONG Blink; -} LIST_ENTRY32, *PLIST_ENTRY32; - -/* 64-bit double linked list structure definition */ -typedef struct _LIST_ENTRY64 -{ - ULONGLONG Flink; - ULONGLONG Blink; -} LIST_ENTRY64, *PLIST_ENTRY64; - -/* Single linked list structure definition */ -typedef struct _SINGLE_LIST_ENTRY -{ - PSINGLE_LIST_ENTRY Next; -} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; - -/* Header for a sequenced single linked list union definition */ -typedef union _SINGLE_LIST_HEADER -{ - ULONGLONG Alignment; - struct - { - SINGLE_LIST_ENTRY Next; - USHORT Depth; - USHORT Sequence; - }; -} SINGLE_LIST_HEADER, *PSINGLE_LIST_HEADER; - -/* 128-bit 16-byte aligned XMM register */ -typedef struct _M128 -{ - ULONGLONG Low; - LONGLONG High; -} ALIGN(16) M128, *PM128; - -/* Dispatcher object header structure definition */ -typedef struct _DISPATCHER_HEADER -{ - UCHAR Type; - union - { - UCHAR Absolute; - UCHAR NpxIrql; - }; - UCHAR Inserted; - BOOLEAN DebugActive; - LONG SignalState; - LIST_ENTRY WaitListHead; -} DISPATCHER_HEADER, *PDISPATCHER_HEADER; +/* Security information */ +typedef ULONG SECURITY_INFORMATION, *PSECURITY_INFORMATION; #endif /* __XTOS_ASSEMBLER_ */ #endif /* __XTDK_XTBASE_H */ diff --git a/sdk/xtdk/xtcompat.h b/sdk/xtdk/xtcompat.h index 900618e..689cfa0 100644 --- a/sdk/xtdk/xtcompat.h +++ b/sdk/xtdk/xtcompat.h @@ -20,6 +20,11 @@ #define XTCLINK extern "C" #define XTSYMBOL(Name) __asm__(Name) + /* C++ attributes */ + #define MUSTCHECK [[nodiscard]] + #define NORETURN [[noreturn]] + #define UNUSED [[maybe_unused]] + /* C++ boolean type */ typedef bool BOOLEAN, *PBOOLEAN; #define TRUE true @@ -34,6 +39,11 @@ #define XTCLINK #define XTSYMBOL(Name) + /* C attributes */ + #define MUSTCHECK __attribute__((warn_unused_result)) + #define NORETURN __attribute__((noreturn)) + #define UNUSED __attribute__((unused)) + /* C boolean type */ typedef enum _BOOLEAN { diff --git a/sdk/xtdk/xtdefs.h b/sdk/xtdk/xtdefs.h index 35ab789..d58f278 100644 --- a/sdk/xtdk/xtdefs.h +++ b/sdk/xtdk/xtdefs.h @@ -34,6 +34,7 @@ #define MAXCHAR 0x7F #define MINSHORT 0x8000 #define MAXSHORT 0x7FFF +#define MAXUSHORT 0xFFFF #define MINLONG 0x80000000 #define MAXLONG 0x7FFFFFFF #define MAXULONG 0xFFFFFFFF diff --git a/sdk/xtdk/xtkmapi.h b/sdk/xtdk/xtkmapi.h index 0d82e1c..a2ef9b8 100644 --- a/sdk/xtdk/xtkmapi.h +++ b/sdk/xtdk/xtkmapi.h @@ -28,22 +28,27 @@ #include /* Low level data types headers */ +#include #include #include #include #include #include #include +#include #include +#include #include #include #include +#include /* Architecture-specific low level data types headers */ #include ARCH_HEADER(artypes.h) #include ARCH_HEADER(hltypes.h) #include ARCH_HEADER(ketypes.h) #include ARCH_HEADER(mmtypes.h) +#include ARCH_HEADER(rtltypes.h) /* XT routines */ #include diff --git a/sdk/xtdk/xtstatus.h b/sdk/xtdk/xtstatus.h index 0803ba2..1ac333d 100644 --- a/sdk/xtdk/xtstatus.h +++ b/sdk/xtdk/xtstatus.h @@ -48,6 +48,20 @@ /* XT status code definitions */ #define STATUS_SUCCESS ((XTSTATUS) 0x00000000L) +#define STATUS_WAIT_0 ((XTSTATUS) 0x00000000L) +#define STATUS_WAIT_1 ((XTSTATUS) 0x00000001L) +#define STATUS_WAIT_2 ((XTSTATUS) 0x00000002L) +#define STATUS_WAIT_3 ((XTSTATUS) 0x00000003L) +#define STATUS_WAIT_63 ((XTSTATUS) 0x0000003FL) +#define STATUS_ABANDONED ((XTSTATUS) 0x00000080L) +#define STATUS_ABANDONED_WAIT_0 ((XTSTATUS) 0x00000080L) +#define STATUS_ABANDONED_WAIT_63 ((XTSTATUS) 0x000000BFL) +#define STATUS_ALERTED ((XTSTATUS) 0x00000101L) +#define STATUS_TIMEOUT ((XTSTATUS) 0x00000102L) +#define STATUS_PENDING ((XTSTATUS) 0x00000103L) +#define STATUS_REPARSE ((XTSTATUS) 0x00000104L) +#define STATUS_DATATYPE_MISALIGNMENT ((XTSTATUS) 0x80000002L) +#define STATUS_WAKE_SYSTEM_DEBUGGER ((XTSTATUS) 0x80000007L) #define STATUS_END_OF_MEDIA ((XTSTATUS) 0x8000001EL) #define STATUS_RESOURCE_LOCKED ((XTSTATUS) 0xC0000000L) #define STATUS_UNSUCCESSFUL ((XTSTATUS) 0xC0000001L) @@ -59,15 +73,24 @@ #define STATUS_INVALID_PARAMETER ((XTSTATUS) 0xC000000DL) #define STATUS_END_OF_FILE ((XTSTATUS) 0xC0000011L) #define STATUS_NO_MEMORY ((XTSTATUS) 0xC0000017L) +#define STATUS_ACCESS_DENIED ((XTSTATUS) 0xC0000022L) +#define STATUS_BUFFER_TOO_SMALL ((XTSTATUS) 0xC0000023L) +#define STATUS_OBJECT_TYPE_MISMATCH ((XTSTATUS) 0xC0000024L) +#define STATUS_OBJECT_NAME_INVALID ((XTSTATUS) 0xC0000033L) +#define STATUS_OBJECT_NAME_COLLISION ((XTSTATUS) 0xC0000035L) #define STATUS_PORT_DISCONNECTED ((XTSTATUS) 0xC0000037L) #define STATUS_CRC_ERROR ((XTSTATUS) 0xC000003FL) +#define STATUS_QUOTA_EXCEEDED ((XTSTATUS) 0xC0000044L) +#define STATUS_PRIVILEGE_NOT_HELD ((XTSTATUS) 0xC0000061L) #define STATUS_FLOAT_OVERFLOW ((XTSTATUS) 0xC0000091L) #define STATUS_INTEGER_OVERFLOW ((XTSTATUS) 0xC0000095L) #define STATUS_INSUFFICIENT_RESOURCES ((XTSTATUS) 0xC000009AL) #define STATUS_DEVICE_NOT_READY ((XTSTATUS) 0xC00000A3L) #define STATUS_NOT_SUPPORTED ((XTSTATUS) 0xC00000BBL) -#define STATUS_TIMEOUT ((XTSTATUS) 0x00000102L) +#define STATUS_NAME_TOO_LONG ((XTSTATUS) 0xC0000106L) +#define STATUS_PAGEFILE_QUOTA_EXCEEDED ((XTSTATUS) 0xC000012CL) #define STATUS_IO_DEVICE_ERROR ((XTSTATUS) 0xC0000185L) +#define STATUS_MUTEX_LIMIT_EXCEEDED ((XTSTATUS) 0xC0000191L) #define STATUS_NOT_FOUND ((XTSTATUS) 0xC0000225L) #endif /* __XTDK_XTSTATUS_H */ diff --git a/sdk/xtdk/xtstruct.h b/sdk/xtdk/xtstruct.h index 712c240..218e193 100644 --- a/sdk/xtdk/xtstruct.h +++ b/sdk/xtdk/xtstruct.h @@ -17,6 +17,12 @@ /* Enumeration lists forward references */ typedef enum _ADJUST_REASON ADJUST_REASON, *PADJUST_REASON; +typedef enum _BUS_QUERY_ID_TYPE BUS_QUERY_ID_TYPE, *PBUS_QUERY_ID_TYPE; +typedef enum _DEVICE_POWER_STATE DEVICE_POWER_STATE, *PDEVICE_POWER_STATE; +typedef enum _DEVICE_RELATION_TYPE DEVICE_RELATION_TYPE, *PDEVICE_RELATION_TYPE; +typedef enum _DEVICE_TEXT_TYPE DEVICE_TEXT_TYPE, *PDEVICE_TEXT_TYPE; +typedef enum _DEVICE_USAGE_NOTIFICATION_TYPE DEVICE_USAGE_NOTIFICATION_TYPE, *PDEVICE_USAGE_NOTIFICATION_TYPE; +typedef enum _DIRECTORY_NOTIFY_INFORMATION_CLASS DIRECTORY_NOTIFY_INFORMATION_CLASS, *PDIRECTORY_NOTIFY_INFORMATION_CLASS; typedef enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION, *PEXCEPTION_DISPOSITION; typedef enum _EFI_ALLOCATE_TYPE EFI_ALLOCATE_TYPE, *PEFI_ALLOCATE_TYPE; typedef enum _EFI_FRAMEWORK_CPU_DESIGNATION EFI_FRAMEWORK_CPU_DESIGNATION, *PEFI_FRAMEWORK_CPU_DESIGNATION; @@ -41,8 +47,15 @@ typedef enum _EFI_TIMER_DELAY EFI_TIMER_DELAY, *PEFI_TIMER_DELAY; typedef enum _EFI_UART_PARITY_TYPE EFI_UART_PARITY_TYPE, *PEFI_UART_PARITY_TYPE; typedef enum _EFI_UART_STOP_BITS_TYPE EFI_UART_STOP_BITS_TYPE, *PEFI_UART_STOP_BITS_TYPE; typedef enum _EFI_UNIVERSA_GRAPHICS_BLT_OPERATION EFI_UNIVERSA_GRAPHICS_BLT_OPERATION, *PEFI_UNIVERSA_GRAPHICS_BLT_OPERATION; +typedef enum _FILE_INFORMATION_CLASS FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; +typedef enum _FS_INFORMATION_CLASS FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; typedef enum _HAL_APIC_MODE HAL_APIC_MODE, *PHAL_APIC_MODE; +typedef enum _INTERFACE_TYPE INTERFACE_TYPE, *PINTERFACE_TYPE; +typedef enum _IO_ALLOCATION_ACTION IO_ALLOCATION_ACTION, *PIO_ALLOCATION_ACTION; +typedef enum _IRQ_DEVICE_POLICY IRQ_DEVICE_POLICY, *PIRQ_DEVICE_POLICY; +typedef enum _IRQ_PRIORITY IRQ_PRIORITY, *PIRQ_PRIORITY; typedef enum _KAPC_ENVIRONMENT KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT; +typedef enum _KCONTINUE_STATUS KCONTINUE_STATUS, *PKCONTINUE_STATUS; typedef enum _KDPC_IMPORTANCE KDPC_IMPORTANCE, *PKDPC_IMPORTANCE; typedef enum _KEVENT_TYPE KEVENT_TYPE, *PKEVENT_TYPE; typedef enum _KOBJECTS KOBJECTS, *PKOBJECTS; @@ -51,19 +64,35 @@ typedef enum _KPROFILE_SOURCE KPROFILE_SOURCE, *PKPROFILE_SOURCE; typedef enum _KTHREAD_STATE KTHREAD_STATE, *PKTHREAD_STATE; typedef enum _KTIMER_TYPE KTIMER_TYPE, *PKTIMER_TYPE; typedef enum _KUBSAN_DATA_TYPE KUBSAN_DATA_TYPE, *PKUBSAN_DATA_TYPE; +typedef enum _KWAIT_REASON KWAIT_REASON, *PKWAIT_REASON; typedef enum _LOADER_MEMORY_TYPE LOADER_MEMORY_TYPE, *PLOADER_MEMORY_TYPE; typedef enum _MMPAGELISTS MMPAGELISTS, *PMMPAGELISTS; typedef enum _MMPFN_CACHE_ATTRIBUTE MMPFN_CACHE_ATTRIBUTE, *PMMPFN_CACHE_ATTRIBUTE; typedef enum _MMPOOL_TYPE MMPOOL_TYPE, *PMMPOOL_TYPE; typedef enum _MMSYSTEM_PTE_POOL_TYPE MMSYSTEM_PTE_POOL_TYPE, *PMMSYSTEM_PTE_POOL_TYPE; typedef enum _MODE MODE, *PMODE; +typedef enum _NONPAGED_LOOKASIDE_NUMBER NONPAGED_LOOKASIDE_NUMBER, *PNONPAGED_LOOKASIDE_NUMBER; +typedef enum _OBJECT_HEADER_INFO OBJECT_HEADER_INFO, *POBJECT_HEADER_INFO; +typedef enum _OBJECT_INFORMATION_CLASS OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; +typedef enum _OBJECT_OPEN_REASON OBJECT_OPEN_REASON, *POBJECT_OPEN_REASON; +typedef enum _POWER_ACTION POWER_ACTION, *PPOWER_ACTION; +typedef enum _POWER_STATE_TYPE POWER_STATE_TYPE, *PPOWER_STATE_TYPE; +typedef enum _PROXY_CLASS PROXY_CLASS, *PPROXY_CLASS; +typedef enum _PS_QUOTA_TYPE PS_QUOTA_TYPE, *PPS_QUOTA_TYPE; typedef enum _RTL_BALANCED_NODE_COLOR RTL_BALANCED_NODE_COLOR, *PRTL_BALANCED_NODE_COLOR; typedef enum _RTL_VARIABLE_TYPE RTL_VARIABLE_TYPE, *PRTL_VARIABLE_TYPE; +typedef enum _SECURITY_IMPERSONATION_LEVEL SECURITY_IMPERSONATION_LEVEL, *PSECURITY_IMPERSONATION_LEVEL; +typedef enum _SECURITY_OPERATION_CODE SECURITY_OPERATION_CODE, *PSECURITY_OPERATION_CODE; typedef enum _SYSTEM_FIRMWARE_TYPE SYSTEM_FIRMWARE_TYPE, *PSYSTEM_FIRMWARE_TYPE; +typedef enum _SYSTEM_POWER_STATE SYSTEM_POWER_STATE, *PSYSTEM_POWER_STATE; typedef enum _SYSTEM_RESOURCE_TYPE SYSTEM_RESOURCE_TYPE, *PSYSTEM_RESOURCE_TYPE; +typedef enum _TOKEN_TYPE TOKEN_TYPE, *PTOKEN_TYPE; typedef enum _WAIT_TYPE WAIT_TYPE, *PWAIT_TYPE; +typedef enum _WORK_QUEUE_TYPE WORK_QUEUE_TYPE, *PWORK_QUEUE_TYPE; /* Structures forward references */ +typedef struct _ACCESS_STATE ACCESS_STATE, *PACCESS_STATE; +typedef struct _ACL ACL, *PACL; typedef struct _ACPI_CACHE_LIST ACPI_CACHE_LIST, *PACPI_CACHE_LIST; typedef struct _ACPI_DESCRIPTION_HEADER ACPI_DESCRIPTION_HEADER, *PACPI_DESCRIPTION_HEADER; typedef struct _ACPI_FADT ACPI_FADT, *PACPI_FADT; @@ -79,12 +108,27 @@ typedef struct _ACPI_SUBTABLE_HEADER ACPI_SUBTABLE_HEADER, *PACPI_SUBTABLE_HEADE typedef struct _ACPI_SYSTEM_INFO ACPI_SYSTEM_INFO, *PACPI_SYSTEM_INFO; typedef struct _ACPI_TIMER_INFO ACPI_TIMER_INFO, *PACPI_TIMER_INFO; typedef struct _ACPI_XSDT ACPI_XSDT, *PACPI_XSDT; +typedef struct _ACTIVATION_CONTEXT_STACK ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; typedef struct _ANSI_STRING ANSI_STRING, *PANSI_STRING; typedef struct _ANSI_STRING32 ANSI_STRING32, *PANSI_STRING32; typedef struct _ANSI_STRING64 ANSI_STRING64, *PANSI_STRING64; +typedef struct _AUDIT_POLICY_CATEGORIES AUDIT_POLICY_CATEGORIES, *PAUDIT_POLICY_CATEGORIES; +typedef struct _AUDIT_POLICY_OVERLAY AUDIT_POLICY_OVERLAY, *PAUDIT_POLICY_OVERLAY; +typedef struct _CLIENT_ID CLIENT_ID, *PCLIENT_ID; +typedef struct _CM_FULL_RESOURCE_DESCRIPTOR CM_FULL_RESOURCE_DESCRIPTOR, *PCM_FULL_RESOURCE_DESCRIPTOR; +typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR; +typedef struct _CM_PARTIAL_RESOURCE_LIST CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST; +typedef struct _CM_RESOURCE_LIST CM_RESOURCE_LIST, *PCM_RESOURCE_LIST; +typedef struct _COMPRESSED_DATA_INFO COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO; typedef struct _CPPORT CPPORT, *PCPPORT; -typedef const struct _CMMPAGEMAP_ROUTINES CMMPAGEMAP_ROUTINES, *PCMMPAGEMAP_ROUTINES; +typedef struct _CPTABLE_INFO CPTABLE_INFO, *PCPTABLE_INFO; typedef struct _CSTRING CSTRING, *PCSTRING; +typedef struct _DEVICE_CAPABILITIES DEVICE_CAPABILITIES, *PDEVICE_CAPABILITIES; +typedef struct _DEVICE_MAP DEVICE_MAP, *PDEVICE_MAP; +typedef struct _DEVICE_OBJECT DEVICE_OBJECT, *PDEVICE_OBJECT; +typedef struct _DEVOBJ_EXTENSION DEVOBJ_EXTENSION, *PDEVOBJ_EXTENSION; +typedef struct _DRIVER_EXTENSION DRIVER_EXTENSION, *PDRIVER_EXTENSION; +typedef struct _DRIVER_OBJECT DRIVER_OBJECT, *PDRIVER_OBJECT; typedef struct _EFI_1394_DEVICE_PATH EFI_1394_DEVICE_PATH, *PEFI_1394_DEVICE_PATH; typedef struct _EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR, *PEFI_ACPI_ADDRESS_SPACE_DESCRIPTOR; typedef struct _EFI_ACPI_ADR_DEVICE_PATH EFI_ACPI_ADR_DEVICE_PATH, *PEFI_ACPI_ADR_DEVICE_PATH; @@ -240,27 +284,55 @@ typedef struct _EFI_VENDOR_DEVICE_PATH EFI_VENDOR_DEVICE_PATH, *PEFI_VENDOR_DEVI typedef struct _EFI_VLAN_DEVICE_PATH EFI_VLAN_DEVICE_PATH, *PEFI_VLAN_DEVICE_PATH; typedef struct _EFI_WORD_REGS EFI_WORD_REGS, *PEFI_WORD_REGS; typedef struct _EPROCESS EPROCESS, *PEPROCESS; +typedef struct _EPROCESS_QUOTA_BLOCK EPROCESS_QUOTA_BLOCK, *PEPROCESS_QUOTA_BLOCK; +typedef struct _EPROCESS_QUOTA_ENTRY EPROCESS_QUOTA_ENTRY, *PEPROCESS_QUOTA_ENTRY; +typedef struct _ERESOURCE ERESOURCE, *PERESOURCE; typedef struct _ETHREAD ETHREAD, *PETHREAD; -typedef struct _EX_RUNDOWN_REFERENCE EX_RUNDOWN_REFERENCE, *PEX_RUNDOWN_REFERENCE; +typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS, *PEXCEPTION_POINTERS; typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD, *PEXCEPTION_RECORD; typedef struct _EXCEPTION_REGISTRATION_RECORD EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD; +typedef struct _FAST_IO_DISPATCH FAST_IO_DISPATCH, *PFAST_IO_DISPATCH; +typedef struct _FILE_BASIC_INFORMATION FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; +typedef struct _FILE_GET_QUOTA_INFORMATION FILE_GET_QUOTA_INFORMATION, *PFILE_GET_QUOTA_INFORMATION; +typedef struct _FILE_NETWORK_OPEN_INFORMATION FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; +typedef struct _FILE_OBJECT FILE_OBJECT, *PFILE_OBJECT; +typedef struct _FILE_STANDARD_INFORMATION FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; typedef struct _FIRMWARE_INFORMATION_BLOCK FIRMWARE_INFORMATION_BLOCK, *PFIRMWARE_INFORMATION_BLOCK; typedef struct _FLOAT128 FLOAT128, *PFLOAT128; +typedef struct _GENERAL_LOOKASIDE GENERAL_LOOKASIDE, *PGENERAL_LOOKASIDE; typedef struct _GENERIC_ADDRESS GENERIC_ADDRESS, *PGENERIC_ADDRESS; +typedef struct _GENERIC_MAPPING GENERIC_MAPPING, *PGENERIC_MAPPING; typedef struct _GUID GUID, *PGUID; +typedef struct _HANDLE_TABLE_ENTRY HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY; +typedef struct _HANDLE_TABLE_ENTRY_INFO HANDLE_TABLE_ENTRY_INFO, *PHANDLE_TABLE_ENTRY_INFO; +typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE; typedef struct _HL_FRAMEBUFFER_DATA HL_FRAMEBUFFER_DATA, *PHL_FRAMEBUFFER_DATA; typedef struct _HL_SCROLL_REGION_DATA HL_SCROLL_REGION_DATA, *PHL_SCROLL_REGION_DATA; +typedef struct _INITIAL_PRIVILEGE_SET INITIAL_PRIVILEGE_SET, *PINITIAL_PRIVILEGE_SET; +typedef struct _INTERFACE INTERFACE, *PINTERFACE; +typedef struct _IO_COMPLETION_CONTEXT IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT; +typedef struct _IO_RESOURCE_DESCRIPTOR IO_RESOURCE_DESCRIPTOR, *PIO_RESOURCE_DESCRIPTOR; +typedef struct _IO_RESOURCE_LIST IO_RESOURCE_LIST, *PIO_RESOURCE_LIST; +typedef struct _IO_RESOURCE_REQUIREMENTS_LIST IO_RESOURCE_REQUIREMENTS_LIST, *PIO_RESOURCE_REQUIREMENTS_LIST; +typedef struct _IO_SECURITY_CONTEXT IO_SECURITY_CONTEXT, *PIO_SECURITY_CONTEXT; +typedef struct _IO_STACK_LOCATION IO_STACK_LOCATION, *PIO_STACK_LOCATION; +typedef struct _IO_STATUS_BLOCK IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +typedef struct _IO_TIMER IO_TIMER, *PIO_TIMER; +typedef struct _IRP IRP, *PIRP; +typedef struct _KAFFINITY_MAP KAFFINITY_MAP, *PKAFFINITY_MAP; typedef struct _KAPC KAPC, *PKAPC; typedef struct _KAPC_STATE KAPC_STATE, *PKAPC_STATE; typedef struct _KD_DEBUG_MODE KD_DEBUG_MODE, *PKD_DEBUG_MODE; typedef struct _KD_DISPATCH_TABLE KD_DISPATCH_TABLE, *PKD_DISPATCH_TABLE; typedef struct _KDPC KDPC, *PKDPC; typedef struct _KDPC_DATA KDPC_DATA, *PKDPC_DATA; +typedef struct _KDEVICE_QUEUE_ENTRY KDEVICE_QUEUE_ENTRY, *PKDEVICE_QUEUE_ENTRY; typedef struct _KERNEL_INITIALIZATION_BLOCK KERNEL_INITIALIZATION_BLOCK, *PKERNEL_INITIALIZATION_BLOCK; typedef struct _KEVENT KEVENT, *PKEVENT; -typedef struct _KGATE KGATE, *PKGATE; typedef struct _KLOCK_QUEUE_HANDLE KLOCK_QUEUE_HANDLE, *PKLOCK_QUEUE_HANDLE; +typedef struct _KMUTEX KMUTEX, *PKMUTEX; typedef struct _KPROCESS KPROCESS, *PKPROCESS; +typedef struct _KPUSH_LOCK_WAIT_BLOCK KPUSH_LOCK_WAIT_BLOCK, *PKPUSH_LOCK_WAIT_BLOCK; typedef struct _KQUEUE KQUEUE, *PKQUEUE; typedef struct _KSEMAPHORE KSEMAPHORE, *PKSEMAPHORE; typedef struct _KSERVICE_DESCRIPTOR_TABLE KSERVICE_DESCRIPTOR_TABLE, *PKSERVICE_DESCRIPTOR_TABLE; @@ -281,18 +353,59 @@ typedef struct _KUBSAN_TYPE_MISMATCH_DATA KUBSAN_TYPE_MISMATCH_DATA, *PKUBSAN_TY typedef struct _KUBSAN_TYPE_MISMATCH_DATA_V1 KUBSAN_TYPE_MISMATCH_DATA_V1, *PKUBSAN_TYPE_MISMATCH_DATA_V1; typedef struct _KWAIT_BLOCK KWAIT_BLOCK, *PKWAIT_BLOCK; typedef struct _LDR_DATA_TABLE_ENTRY LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; +typedef struct _LDR_PEB_DATA LDR_PEB_DATA, *PLDR_PEB_DATA; typedef struct _LIST_ENTRY LIST_ENTRY, *PLIST_ENTRY; typedef struct _LIST_ENTRY32 LIST_ENTRY32, *PLIST_ENTRY32; typedef struct _LIST_ENTRY64 LIST_ENTRY64, *PLIST_ENTRY64; typedef struct _LOADER_GRAPHICS_INFORMATION_BLOCK LOADER_GRAPHICS_INFORMATION_BLOCK, *PLOADER_GRAPHICS_INFORMATION_BLOCK; typedef struct _LOADER_INFORMATION_BLOCK LOADER_INFORMATION_BLOCK, *PLOADER_INFORMATION_BLOCK; typedef struct _LOADER_MEMORY_DESCRIPTOR LOADER_MEMORY_DESCRIPTOR, *PLOADER_MEMORY_DESCRIPTOR; +typedef struct _LOOKASIDE_LIST LOOKASIDE_LIST, *PLOOKASIDE_LIST; +typedef struct _LOOKASIDE_LIST_EX LOOKASIDE_LIST_EX, *PLOOKASIDE_LIST_EX; +typedef struct _LPCP_NONPAGED_PORT_QUEUE LPCP_NONPAGED_PORT_QUEUE, *PLPCP_NONPAGED_PORT_QUEUE; +typedef struct _LPCP_PORT_OBJECT LPCP_PORT_OBJECT, *PLPCP_PORT_OBJECT; +typedef struct _LPCP_PORT_QUEUE LPCP_PORT_QUEUE, *PLPCP_PORT_QUEUE; +typedef struct _LUID LUID, *PLUID; +typedef struct _LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES; typedef struct _M128 M128, *PM128; +typedef struct _MAILSLOT_CREATE_PARAMETERS MAILSLOT_CREATE_PARAMETERS, *PMAILSLOT_CREATE_PARAMETERS; +typedef struct _MDL MDL, *PMDL; typedef struct _MMCOLOR_TABLES MMCOLOR_TABLES, *PMMCOLOR_TABLES; typedef struct _MMFREE_POOL_ENTRY MMFREE_POOL_ENTRY, *PMMFREE_POOL_ENTRY; typedef struct _MMMEMORY_LAYOUT MMMEMORY_LAYOUT, *PMMMEMORY_LAYOUT; typedef struct _MMPFNENTRY MMPFNENTRY, *PMMPFNENTRY; typedef struct _MMPFNLIST MMPFNLIST, *PMMPFNLIST; +typedef struct _MMSUPPORT MMSUPPORT, *PMMSUPPORT; +typedef struct _MMSUPPORT_FLAGS MMSUPPORT_FLAGS, *PMMSUPPORT_FLAGS; +typedef struct _MMWSLE_HASH MMWSLE_HASH, *PMMWSLE_HASH; +typedef struct _NAMED_PIPE_CREATE_PARAMETERS NAMED_PIPE_CREATE_PARAMETERS, *PNAMED_PIPE_CREATE_PARAMETERS; +typedef struct _NLSTABLE_INFO NLSTABLE_INFO, *PNLSTABLE_INFO; +typedef struct _NONPAGED_LOOKASIDE_LIST NONPAGED_LOOKASIDE_LIST, *PNONPAGED_LOOKASIDE_LIST; +typedef struct _OBJECT_ATTRIBUTES OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; +typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION; +typedef struct _OBJECT_CREATOR_INFO OBJECT_CREATOR_INFO, *POBJECT_CREATOR_INFO; +typedef struct _OBJECT_DIRECTORY OBJECT_DIRECTORY, *POBJECT_DIRECTORY; +typedef struct _OBJECT_DIRECTORY_ENTRY OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY; +typedef struct _OBJECT_DUMP_CONTROL OBJECT_DUMP_CONTROL, *POBJECT_DUMP_CONTROL; +typedef struct _OBJECT_HANDLE_COUNT_DATABASE OBJECT_HANDLE_COUNT_DATABASE, *POBJECT_HANDLE_COUNT_DATABASE; +typedef struct _OBJECT_HANDLE_COUNT_ENTRY OBJECT_HANDLE_COUNT_ENTRY, *POBJECT_HANDLE_COUNT_ENTRY; +typedef struct _OBJECT_HANDLE_COUNT_INFORMATION OBJECT_HANDLE_COUNT_INFORMATION, *POBJECT_HANDLE_COUNT_INFORMATION; +typedef struct _OBJECT_HANDLE_INFO OBJECT_HANDLE_INFO, *POBJECT_HANDLE_INFO; +typedef struct _OBJECT_HANDLE_INFORMATION OBJECT_HANDLE_INFORMATION, *POBJECT_HANDLE_INFORMATION; +typedef struct _OBJECT_HEADER OBJECT_HEADER, *POBJECT_HEADER; +typedef struct _OBJECT_HEADER_CREATOR_INFO OBJECT_HEADER_CREATOR_INFO, *POBJECT_HEADER_CREATOR_INFO; +typedef struct _OBJECT_HEADER_NAME_INFO OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO; +typedef struct _OBJECT_HEADER_QUOTA_INFO OBJECT_HEADER_QUOTA_INFO, *POBJECT_HEADER_QUOTA_INFO; +typedef struct _OBJECT_LOOKUP_CONTEXT OBJECT_LOOKUP_CONTEXT, *POBJECT_LOOKUP_CONTEXT; +typedef struct _OBJECT_NAME_INFO OBJECT_NAME_INFO, *POBJECT_NAME_INFO; +typedef struct _OBJECT_NAME_INFORMATION OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; +typedef struct _OBJECT_OPTIONAL_HEADER_LAYOUT OBJECT_OPTIONAL_HEADER_LAYOUT, *POBJECT_OPTIONAL_HEADER_LAYOUT; +typedef struct _OBJECT_PROCESS_INFO OBJECT_PROCESS_INFO, *POBJECT_PROCESS_INFO; +typedef struct _OBJECT_QUOTA_INFO OBJECT_QUOTA_INFO, *POBJECT_QUOTA_INFO; +typedef struct _OBJECT_TYPE OBJECT_TYPE, *POBJECT_TYPE; +typedef struct _OBJECT_TYPE_INITIALIZER OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; +typedef struct _OWNER_ENTRY OWNER_ENTRY, *POWNER_ENTRY; +typedef struct _PAGED_LOOKASIDE_LIST PAGED_LOOKASIDE_LIST, *PPAGED_LOOKASIDE_LIST; typedef struct _PCAT_FIRMWARE_INFORMATION PCAT_FIRMWARE_INFORMATION, *PPCAT_FIRMWARE_INFORMATION; typedef struct _PCI_BRIDGE_CONTROL_REGISTER PCI_BRIDGE_CONTROL_REGISTER, *PPCI_BRIDGE_CONTROL_REGISTER; typedef struct _PCI_COMMON_CONFIG PCI_COMMON_CONFIG, *PPCI_COMMON_CONFIG; @@ -301,6 +414,8 @@ typedef struct _PCI_DEVICE_HEADER_TYPE_REGION PCI_DEVICE_HEADER_TYPE_REGION, *PP typedef struct _PCI_DEVICE_INDEPENDENT_REGION PCI_DEVICE_INDEPENDENT_REGION, *PPCI_DEVICE_INDEPENDENT_REGION; typedef struct _PCI_TYPE0_DEVICE PCI_TYPE0_DEVICE, *PPCI_TYPE0_DEVICE; typedef struct _PCI_TYPE1_DEVICE PCI_TYPE1_DEVICE, *PPCI_TYPE1_DEVICE; +typedef struct _PEB PEB, *PPEB; +typedef struct _PEB_FREE_BLOCK PEB_FREE_BLOCK, *PPEB_FREE_BLOCK; typedef struct _PECOFF_IMAGE_BASE_RELOCATION PECOFF_IMAGE_BASE_RELOCATION, *PPECOFF_IMAGE_BASE_RELOCATION; typedef struct _PECOFF_IMAGE_DATA PECOFF_IMAGE_DATA, *PPECOFF_IMAGE_DATA; typedef struct _PECOFF_IMAGE_DATA_DIRECTORY PECOFF_IMAGE_DATA_DIRECTORY, *PPECOFF_IMAGE_DATA_DIRECTORY; @@ -326,26 +441,56 @@ typedef struct _PHYSICAL_MEMORY_RUN PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN; typedef struct _POOL_HEADER POOL_HEADER, *PPOOL_HEADER; typedef struct _POOL_TRACKING_BIG_ALLOCATIONS POOL_TRACKING_BIG_ALLOCATIONS, *PPOOL_TRACKING_BIG_ALLOCATIONS; typedef struct _POOL_TRACKING_TABLE POOL_TRACKING_TABLE, *PPOOL_TRACKING_TABLE; +typedef struct _POWER_SEQUENCE POWER_SEQUENCE, *PPOWER_SEQUENCE; +typedef struct _PRIVILEGE_SET PRIVILEGE_SET, *PPRIVILEGE_SET; typedef struct _PROCESSOR_IDENTITY PROCESSOR_IDENTITY, *PPROCESSOR_IDENTITY; typedef struct _PROCESSOR_POWER_STATE PROCESSOR_POWER_STATE, *PPROCESSOR_POWER_STATE; +typedef struct _QUAD QUAD, *PQUAD; +typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME; typedef struct _RTL_BALANCED_NODE RTL_BALANCED_NODE, *PRTL_BALANCED_NODE; typedef struct _RTL_BITMAP RTL_BITMAP, *PRTL_BITMAP; typedef struct _RTL_PRINT_CONTEXT RTL_PRINT_CONTEXT, *PRTL_PRINT_CONTEXT; typedef struct _RTL_PRINT_FORMAT_PROPERTIES RTL_PRINT_FORMAT_PROPERTIES, *PRTL_PRINT_FORMAT_PROPERTIES; typedef struct _RTL_RB_TREE RTL_RB_TREE, *PRTL_RB_TREE; +typedef struct _SCSI_REQUEST_BLOCK SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK; +typedef struct _SECTION_OBJECT_POINTERS SECTION_OBJECT_POINTERS, *PSECTION_OBJECT_POINTERS; +typedef struct _SECURITY_AUDIT_PROCESS_CREATION_INFO SECURITY_AUDIT_PROCESS_CREATION_INFO, *PSECURITY_AUDIT_PROCESS_CREATION_INFO; +typedef struct _SECURITY_CLIENT_CONTEXT SECURITY_CLIENT_CONTEXT, *PSECURITY_CLIENT_CONTEXT; +typedef struct _SECURITY_PROCESS_AUDIT_INFO SECURITY_PROCESS_AUDIT_INFO, *PSECURITY_PROCESS_AUDIT_INFO; +typedef struct _SECURITY_QUALITY_OF_SERVICE SECURITY_QUALITY_OF_SERVICE, *PSECURITY_QUALITY_OF_SERVICE; +typedef struct _SECURITY_SUBJECT_CONTEXT SECURITY_SUBJECT_CONTEXT, *PSECURITY_SUBJECT_CONTEXT; +typedef struct _SECURITY_TOKEN_AUDIT_DATA SECURITY_TOKEN_AUDIT_DATA, *PSECURITY_TOKEN_AUDIT_DATA; +typedef struct _SECURITY_TOKEN_PROXY_DATA SECURITY_TOKEN_PROXY_DATA, *PSECURITY_TOKEN_PROXY_DATA; +typedef struct _SESSION_REFERENCES SESSION_REFERENCES, *PSESSION_REFERENCES; +typedef struct _SID SID, *PSID; +typedef struct _SID_ATTRIBUTES SID_ATTRIBUTES, *PSID_ATTRIBUTES; +typedef struct _SID_IDENTIFIER_AUTHORITY SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY; typedef struct _SINGLE_LIST_ENTRY SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; typedef struct _SMBIOS_TABLE_HEADER SMBIOS_TABLE_HEADER, *PSMBIOS_TABLE_HEADER; typedef struct _SMBIOS3_TABLE_HEADER SMBIOS3_TABLE_HEADER, *PSMBIOS3_TABLE_HEADER; typedef struct _STRING STRING, *PSTRING; typedef struct _STRING32 STRING32, *PSTRING32; typedef struct _STRING64 STRING64, *PSTRING64; +typedef struct _SYSTEM_HANDLE_INFORMATION SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; +typedef struct _SYSTEM_HANDLE_INFORMATION_EX SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO; +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; +typedef struct _SYSTEM_POWER_STATE_CONTEXT SYSTEM_POWER_STATE_CONTEXT, *PSYSTEM_POWER_STATE_CONTEXT; +typedef struct _TEB TEB, *PTEB; +typedef struct _TEB_ACTIVE_FRAME TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME; +typedef struct _TEB_ACTIVE_FRAME_CONTEXT TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT; typedef struct _THREAD_INFORMATION_BLOCK THREAD_INFORMATION_BLOCK, *PTHREAD_INFORMATION_BLOCK; typedef struct _TIME_FIELDS TIME_FIELDS, *PTIME_FIELDS; typedef struct _TIMER_ROUTINES TIMER_ROUTINES, *PTIMER_ROUTINES; +typedef struct _TOKEN TOKEN, *PTOKEN; +typedef struct _TOKEN_CONTROL TOKEN_CONTROL, *PTOKEN_CONTROL; +typedef struct _TOKEN_SOURCE TOKEN_SOURCE, *PTOKEN_SOURCE; typedef struct _UEFI_FIRMWARE_INFORMATION UEFI_FIRMWARE_INFORMATION, *PUEFI_FIRMWARE_INFORMATION; typedef struct _UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING; typedef struct _UNICODE_STRING32 UNICODE_STRING32, *PUNICODE_STRING32; typedef struct _UNICODE_STRING64 UNICODE_STRING64, *PUNICODE_STRING64; +typedef struct _VPB VPB, *PVPB; +typedef struct _WORK_QUEUE_ITEM WORK_QUEUE_ITEM, *PWORK_QUEUE_ITEM; typedef struct _XTBL_BOOT_PARAMETERS XTBL_BOOT_PARAMETERS, *PXTBL_BOOT_PARAMETERS; typedef struct _XTBL_BOOT_PROTOCOL XTBL_BOOT_PROTOCOL, *PXTBL_BOOT_PROTOCOL; typedef struct _XTBL_BOOTMENU_ITEM XTBL_BOOTMENU_ITEM, *PXTBL_BOOTMENU_ITEM; @@ -366,6 +511,7 @@ typedef struct _XTBL_PAGE_MAPPING XTBL_PAGE_MAPPING, *PXTBL_PAGE_MAPPING; typedef struct _XTBL_STATUS XTBL_STATUS, *PXTBL_STATUS; /* Unions forward references */ +typedef union _AUDIT_POLICY AUDIT_POLICY, *PAUDIT_POLICY; typedef union _EFI_DEV_PATH EFI_DEV_PATH, *PEFI_DEV_PATH; typedef union _EFI_DEV_PATH_PTR EFI_DEV_PATH_PTR, *PEFI_DEV_PATH_PTR; typedef union _EFI_FRAMEWORK_MP_HEALTH_FLAGS EFI_FRAMEWORK_MP_HEALTH_FLAGS, *PEFI_FRAMEWORK_MP_HEALTH_FLAGS; @@ -374,8 +520,12 @@ typedef union _EFI_HASH_OUTPUT EFI_HASH_OUTPUT, *PEFI_HASH_OUTPUT; typedef union _EFI_IA32_REGISTER_SET EFI_IA32_REGISTER_SET, *PEFI_IA32_REGISTER_SET; typedef union _EFI_IP_ADDRESS EFI_IP_ADDRESS, *PEFI_IP_ADDRESS; typedef union _EFI_PXE_BASE_CODE_PACKET EFI_PXE_BASE_CODE_PACKET, *PEFI_PXE_BASE_CODE_PACKET; +typedef union _EX_RUNDOWN_REFERENCE EX_RUNDOWN_REFERENCE, *PEX_RUNDOWN_REFERENCE; +typedef union _KPUSH_LOCK KPUSH_LOCK, *PKPUSH_LOCK; typedef union _LARGE_INTEGER LARGE_INTEGER, *PLARGE_INTEGER; -typedef union _SINGLE_LIST_HEADER SINGLE_LIST_HEADER, *PSINGLE_LIST_HEADER; +typedef union _OBJECT_HANDLE OBJECT_HANDLE, *POBJECT_HANDLE; +typedef union _OBJECT_HEADER_HANDLE_INFO OBJECT_HEADER_HANDLE_INFO, *POBJECT_HEADER_HANDLE_INFO; +typedef union _POWER_STATE POWER_STATE, *PPOWER_STATE; typedef union _ULARGE_INTEGER ULARGE_INTEGER, *PULARGE_INTEGER; #endif /* __XTOS_ASSEMBLER__ */ diff --git a/sdk/xtdk/xttypes.h b/sdk/xtdk/xttypes.h index 14e6e89..4325f6a 100644 --- a/sdk/xtdk/xttypes.h +++ b/sdk/xtdk/xttypes.h @@ -11,6 +11,7 @@ #include #include +#include /* C/C++ specific code */ @@ -156,6 +157,41 @@ typedef LPCUWSTR PCUTSTR, LPCUTSTR; /* Variadic ABI types */ typedef __builtin_va_list VA_LIST, *PVA_LIST; +/* ANSI string structure */ +typedef struct _ANSI_STRING +{ + USHORT Length; + USHORT MaximumLength; + PSTR Buffer; +} ANSI_STRING, *PANSI_STRING; +typedef const ANSI_STRING *PCANSI_STRING; + +/* 32-bit ANSI string structure */ +typedef struct _ANSI_STRING32 +{ + USHORT Length; + USHORT MaximumLength; + ULONG Buffer; +} ANSI_STRING32, *PANSI_STRING32; +typedef const ANSI_STRING32 *PCANSI_STRING32; + +/* 64-bit ANSI string structure */ +typedef struct _ANSI_STRING64 +{ + USHORT Length; + USHORT MaximumLength; + ULONGLONG Buffer; +} ANSI_STRING64, *PANSI_STRING64; +typedef const ANSI_STRING64 *PCANSI_STRING64; + +/* Constant counted string structure */ +typedef struct _CSTRING +{ + USHORT Length; + USHORT MaximumLength; + PCCHAR Buffer; +} CSTRING, *PCSTRING; + /* 128-bit floats structure */ typedef struct _FLOAT128 { @@ -191,21 +227,32 @@ typedef union _LARGE_INTEGER LONGLONG QuadPart; } LARGE_INTEGER, *PLARGE_INTEGER; -/* 64-bit unsigned integer union */ -typedef union _ULARGE_INTEGER +/* Double linked list structure definition */ +typedef struct _LIST_ENTRY { - struct - { - ULONG LowPart; - ULONG HighPart; - }; - struct - { - ULONG LowPart; - ULONG HighPart; - } u; - ULONGLONG QuadPart; -} ULARGE_INTEGER, *PULARGE_INTEGER; + PLIST_ENTRY Flink; + PLIST_ENTRY Blink; +} LIST_ENTRY, *PLIST_ENTRY; + +/* Locally Unique Identifier structure definition */ +typedef struct _LUID +{ + ULONG LowPart; + LONG HighPart; +} LUID, *PLUID; + +/* 128-bit 16-byte aligned XMM register */ +typedef struct _M128 +{ + ULONGLONG Low; + LONGLONG High; +} ALIGN(16) M128, *PM128; + +/* Quadruple-word alignment structure definition */ +typedef struct _QUAD +{ + unsigned long long Alignment; +} QUAD, *PQUAD; /* Counted string structure */ typedef struct _STRING @@ -231,40 +278,21 @@ typedef struct _STRING64 ULONGLONG Buffer; } STRING64, *PSTRING64; -/* Constant counted string structure */ -typedef struct _CSTRING +/* 64-bit unsigned integer union */ +typedef union _ULARGE_INTEGER { - USHORT Length; - USHORT MaximumLength; - PCCHAR Buffer; -} CSTRING, *PCSTRING; - -/* ANSI string structure */ -typedef struct _ANSI_STRING -{ - USHORT Length; - USHORT MaximumLength; - PSTR Buffer; -} ANSI_STRING, *PANSI_STRING; -typedef const ANSI_STRING *PCANSI_STRING; - -/* 32-bit ANSI string structure */ -typedef struct _ANSI_STRING32 -{ - USHORT Length; - USHORT MaximumLength; - ULONG Buffer; -} ANSI_STRING32, *PANSI_STRING32; -typedef const ANSI_STRING32 *PCANSI_STRING32; - -/* 64-bit ANSI string structure */ -typedef struct _ANSI_STRING64 -{ - USHORT Length; - USHORT MaximumLength; - ULONGLONG Buffer; -} ANSI_STRING64, *PANSI_STRING64; -typedef const ANSI_STRING64 *PCANSI_STRING64; + struct + { + ULONG LowPart; + ULONG HighPart; + }; + struct + { + ULONG LowPart; + ULONG HighPart; + } u; + ULONGLONG QuadPart; +} ULARGE_INTEGER, *PULARGE_INTEGER; /* UNICODE string structure */ typedef struct _UNICODE_STRING diff --git a/xtoskrnl/CMakeLists.txt b/xtoskrnl/CMakeLists.txt index 6851e26..a9dfd59 100644 --- a/xtoskrnl/CMakeLists.txt +++ b/xtoskrnl/CMakeLists.txt @@ -14,8 +14,12 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/ar/${ARCH}/data.cc ${XTOSKRNL_SOURCE_DIR}/ar/${ARCH}/procsup.cc ${XTOSKRNL_SOURCE_DIR}/ar/${ARCH}/traps.cc + ${XTOSKRNL_SOURCE_DIR}/ex/data.cc ${XTOSKRNL_SOURCE_DIR}/ex/exports.cc + ${XTOSKRNL_SOURCE_DIR}/ex/laslist.cc + ${XTOSKRNL_SOURCE_DIR}/ex/resource.cc ${XTOSKRNL_SOURCE_DIR}/ex/rundown.cc + ${XTOSKRNL_SOURCE_DIR}/ex/workitem.cc ${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/cpu.cc ${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/firmware.cc ${XTOSKRNL_SOURCE_DIR}/hl/${ARCH}/ioport.cc @@ -31,30 +35,38 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/hl/fbdev.cc ${XTOSKRNL_SOURCE_DIR}/hl/init.cc ${XTOSKRNL_SOURCE_DIR}/hl/ioreg.cc + ${XTOSKRNL_SOURCE_DIR}/kd/${ARCH}/debug.cc ${XTOSKRNL_SOURCE_DIR}/kd/data.cc ${XTOSKRNL_SOURCE_DIR}/kd/dbgio.cc + ${XTOSKRNL_SOURCE_DIR}/kd/debug.cc ${XTOSKRNL_SOURCE_DIR}/kd/exports.cc ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/dispatch.cc ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/krnlinit.cc ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/kthread.cc ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/proc.cc + ${XTOSKRNL_SOURCE_DIR}/ke/affinity.cc ${XTOSKRNL_SOURCE_DIR}/ke/apc.cc ${XTOSKRNL_SOURCE_DIR}/ke/bootinfo.cc ${XTOSKRNL_SOURCE_DIR}/ke/crash.cc ${XTOSKRNL_SOURCE_DIR}/ke/data.cc ${XTOSKRNL_SOURCE_DIR}/ke/dispatch.cc + ${XTOSKRNL_SOURCE_DIR}/ke/dispobj.cc ${XTOSKRNL_SOURCE_DIR}/ke/dpc.cc ${XTOSKRNL_SOURCE_DIR}/ke/event.cc ${XTOSKRNL_SOURCE_DIR}/ke/exports.cc + ${XTOSKRNL_SOURCE_DIR}/ke/ipi.cc ${XTOSKRNL_SOURCE_DIR}/ke/kprocess.cc ${XTOSKRNL_SOURCE_DIR}/ke/krnlinit.cc ${XTOSKRNL_SOURCE_DIR}/ke/kthread.cc ${XTOSKRNL_SOURCE_DIR}/ke/kubsan.cc + ${XTOSKRNL_SOURCE_DIR}/ke/pushlock.cc ${XTOSKRNL_SOURCE_DIR}/ke/runlevel.cc + ${XTOSKRNL_SOURCE_DIR}/ke/schedule.cc ${XTOSKRNL_SOURCE_DIR}/ke/semphore.cc ${XTOSKRNL_SOURCE_DIR}/ke/shdata.cc ${XTOSKRNL_SOURCE_DIR}/ke/spinlock.cc ${XTOSKRNL_SOURCE_DIR}/ke/sysres.cc + ${XTOSKRNL_SOURCE_DIR}/ke/sysserv.cc ${XTOSKRNL_SOURCE_DIR}/ke/systime.cc ${XTOSKRNL_SOURCE_DIR}/ke/timer.cc ${XTOSKRNL_SOURCE_DIR}/mm/${ARCH}/mmgr.cc @@ -74,26 +86,51 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/mm/paging.cc ${XTOSKRNL_SOURCE_DIR}/mm/pfn.cc ${XTOSKRNL_SOURCE_DIR}/mm/pool.cc + ${XTOSKRNL_SOURCE_DIR}/mm/probe.cc ${XTOSKRNL_SOURCE_DIR}/mm/pte.cc + ${XTOSKRNL_SOURCE_DIR}/mm/quota.cc + ${XTOSKRNL_SOURCE_DIR}/ob/data.cc + ${XTOSKRNL_SOURCE_DIR}/ob/devmap.cc + ${XTOSKRNL_SOURCE_DIR}/ob/handle.cc + ${XTOSKRNL_SOURCE_DIR}/ob/hndltlb.cc + ${XTOSKRNL_SOURCE_DIR}/ob/lifecycl.cc + ${XTOSKRNL_SOURCE_DIR}/ob/obdir.cc + ${XTOSKRNL_SOURCE_DIR}/ob/obmgr.cc + ${XTOSKRNL_SOURCE_DIR}/ob/security.cc + ${XTOSKRNL_SOURCE_DIR}/ob/typereg.cc ${XTOSKRNL_SOURCE_DIR}/po/idle.cc + ${XTOSKRNL_SOURCE_DIR}/ps/data.cc + ${XTOSKRNL_SOURCE_DIR}/ps/process.cc + ${XTOSKRNL_SOURCE_DIR}/ps/psmgr.cc + ${XTOSKRNL_SOURCE_DIR}/ps/quota.cc + ${XTOSKRNL_SOURCE_DIR}/ps/thread.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/atomic.cc ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/dispatch.cc ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/exsup.cc ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/intrin.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/slist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/atomic.cc ${XTOSKRNL_SOURCE_DIR}/rtl/bitmap.cc ${XTOSKRNL_SOURCE_DIR}/rtl/data.cc ${XTOSKRNL_SOURCE_DIR}/rtl/endian.cc ${XTOSKRNL_SOURCE_DIR}/rtl/exports.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/exsup.cc ${XTOSKRNL_SOURCE_DIR}/rtl/guid.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/lifo.cc ${XTOSKRNL_SOURCE_DIR}/rtl/llist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/math.cc ${XTOSKRNL_SOURCE_DIR}/rtl/memory.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/nls.cc ${XTOSKRNL_SOURCE_DIR}/rtl/rbtree.cc ${XTOSKRNL_SOURCE_DIR}/rtl/sha1.cc - ${XTOSKRNL_SOURCE_DIR}/rtl/slist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/string.cc ${XTOSKRNL_SOURCE_DIR}/rtl/time.cc - ${XTOSKRNL_SOURCE_DIR}/rtl/widestr.cc) + ${XTOSKRNL_SOURCE_DIR}/rtl/unicode.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/widestr.cc + ${XTOSKRNL_SOURCE_DIR}/se/access.cc + ${XTOSKRNL_SOURCE_DIR}/se/audit.cc + ${XTOSKRNL_SOURCE_DIR}/se/descript.cc + ${XTOSKRNL_SOURCE_DIR}/se/privileg.cc) # Set module definition SPEC file set_specfile(xtoskrnl.spec xtoskrnl.exe) diff --git a/xtoskrnl/README.md b/xtoskrnl/README.md index 4e0cb31..d5ddcfd 100644 --- a/xtoskrnl/README.md +++ b/xtoskrnl/README.md @@ -40,6 +40,7 @@ corresponding C++ namespace in which the subsystem's classes and routines reside * Ke - Core Kernel Library * Mm - Memory Manager * Po - Plug&Play and Power Manager + * Ps - Process and Thread Manager * Rtl - Runtime library ### AR: Architecture Library @@ -76,6 +77,12 @@ This subsystem handles power management events, such as shutdown or standby. It supporting device detection and installation at boot time. Furthermore, it is responsible for starting and stopping devices on demand. +### PS: Process and Thread Manager +This subsystem is responsible for managing the lifecycle of processes and threads within the operating system. It +handles the creation, termination, and state tracking of these execution units. Furthermore, it provides the high-level +executive abstractions required to allocate system resources, manage process boundaries, and coordinate with the core +kernel for thread execution. + ### RTL: Runtime Library The Runtime Library provides a kernel-mode implementation of common C library functions. It includes many utility routines, for use by other kernel components. diff --git a/xtoskrnl/ar/amd64/archsup.S b/xtoskrnl/ar/amd64/archsup.S index 080ea12..2142c6e 100644 --- a/xtoskrnl/ar/amd64/archsup.S +++ b/xtoskrnl/ar/amd64/archsup.S @@ -467,9 +467,11 @@ ApEnterLongMode: /* Save the pointer to PROCESSOR_START_BLOCK */ movq %rdi, %rcx - pushq %rdi - /* Call the EntryPoint routine */ + /* Allocate 32 bytes of shadow space */ + subq $32, %rsp + + /* Fetch the EntryPoint address and call the routine */ movq PROCESSOR_START_BLOCK_EntryPoint(%rdi), %rax call *%rax diff --git a/xtoskrnl/ar/amd64/cpufunc.cc b/xtoskrnl/ar/amd64/cpufunc.cc index f0c6933..df04cc9 100644 --- a/xtoskrnl/ar/amd64/cpufunc.cc +++ b/xtoskrnl/ar/amd64/cpufunc.cc @@ -617,6 +617,56 @@ AR::CpuFunctions::ReadWriteBarrier(VOID) : "memory"); } +/** + * Performs a Bit Scan Forward instruction to locate the most significant set bit. + * + * @param Index + * Receives the zero-based index of the highest set bit when one is found. + * + * @param Mask + * Supplies the bitmap to scan. + * + * @return This routine returns TRUE when a set bit was found, otherwise FALSE. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +AR::CpuFunctions::ScanForwardBit(OUT PULONG Index, + IN ULONG Mask) +{ + /* Defer to the BSF instruction */ + __asm__("bsfl %[Mask], %[Index]" : [Index] "=r" (*Index) : [Mask] "mr" (Mask)); + + /* Report whether the input had any bit set */ + return Mask ? TRUE : FALSE; +} + +/** + * Performs a Bit Scan Reverse instruction to locate the most significant set bit. + * + * @param Index + * Receives the zero-based index of the highest set bit when one is found. + * + * @param Mask + * Supplies the bitmap to scan. + * + * @return This routine returns TRUE when a set bit was found, otherwise FALSE. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +AR::CpuFunctions::ScanReverseBit(OUT PULONG Index, + IN ULONG Mask) +{ + /* Defer to the BSR instruction */ + __asm__("bsrl %[Mask], %[Index]" : [Index] "=r" (*Index) : [Mask] "mr" (Mask)); + + /* Report whether the input had any bit set */ + return Mask ? TRUE : FALSE; +} + /** * Instructs the processor to set the interrupt flag. * diff --git a/xtoskrnl/ar/amd64/procsup.cc b/xtoskrnl/ar/amd64/procsup.cc index 3dc708f..0820df8 100644 --- a/xtoskrnl/ar/amd64/procsup.cc +++ b/xtoskrnl/ar/amd64/procsup.cc @@ -28,7 +28,7 @@ XTAPI VOID AR::ProcessorSupport::GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType, OUT PVOID *TrampolineCode, - OUT PULONG_PTR TrampolineSize) + OUT PULONG TrampolineSize) { /* Get trampoline information */ switch(TrampolineType) @@ -320,30 +320,28 @@ AR::ProcessorSupport::InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock) } /* Setup IDT handlers for known interrupts and traps */ - SetIdtGate(ProcessorBlock->IdtBase, 0x00, (PVOID)ArTrapEntry[0x00], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x01, (PVOID)ArTrapEntry[0x01], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x00, (PVOID)ArTrapEntry[0x00], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x01, (PVOID)ArTrapEntry[0x01], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); SetIdtGate(ProcessorBlock->IdtBase, 0x02, (PVOID)ArTrapEntry[0x02], KGDT_R0_CODE, KIDT_IST_NMI, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x03, (PVOID)ArTrapEntry[0x03], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x04, (PVOID)ArTrapEntry[0x04], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x05, (PVOID)ArTrapEntry[0x05], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x06, (PVOID)ArTrapEntry[0x06], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x07, (PVOID)ArTrapEntry[0x07], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x08, (PVOID)ArTrapEntry[0x08], KGDT_R0_CODE, KIDT_IST_PANIC, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x09, (PVOID)ArTrapEntry[0x09], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x0A, (PVOID)ArTrapEntry[0x0A], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x0B, (PVOID)ArTrapEntry[0x0B], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x0C, (PVOID)ArTrapEntry[0x0C], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x0D, (PVOID)ArTrapEntry[0x0D], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x0E, (PVOID)ArTrapEntry[0x0E], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x10, (PVOID)ArTrapEntry[0x10], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x11, (PVOID)ArTrapEntry[0x11], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x12, (PVOID)ArTrapEntry[0x12], KGDT_R0_CODE, KIDT_IST_MCA, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x13, (PVOID)ArTrapEntry[0x13], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_TRAP_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x03, (PVOID)ArTrapEntry[0x03], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x04, (PVOID)ArTrapEntry[0x04], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x05, (PVOID)ArTrapEntry[0x05], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x06, (PVOID)ArTrapEntry[0x06], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x07, (PVOID)ArTrapEntry[0x07], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x08, (PVOID)ArTrapEntry[0x08], KGDT_R0_CODE, KIDT_IST_PANIC, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x09, (PVOID)ArTrapEntry[0x09], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x0A, (PVOID)ArTrapEntry[0x0A], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x0B, (PVOID)ArTrapEntry[0x0B], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x0C, (PVOID)ArTrapEntry[0x0C], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x0D, (PVOID)ArTrapEntry[0x0D], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x0E, (PVOID)ArTrapEntry[0x0E], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x10, (PVOID)ArTrapEntry[0x10], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x11, (PVOID)ArTrapEntry[0x11], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x12, (PVOID)ArTrapEntry[0x12], KGDT_R0_CODE, KIDT_IST_MCA, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x13, (PVOID)ArTrapEntry[0x13], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); SetIdtGate(ProcessorBlock->IdtBase, 0x1F, (PVOID)ArTrapEntry[0x1F], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x2C, (PVOID)ArTrapEntry[0x2C], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x2D, (PVOID)ArTrapEntry[0x2D], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_TRAP_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0x2F, (PVOID)ArTrapEntry[0x2F], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); - SetIdtGate(ProcessorBlock->IdtBase, 0xE1, (PVOID)ArInterruptEntry[0xE1], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING0, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x2C, (PVOID)ArTrapEntry[0x2C], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_INTERRUPT_GATE); + SetIdtGate(ProcessorBlock->IdtBase, 0x2D, (PVOID)ArTrapEntry[0x2D], KGDT_R0_CODE, KIDT_IST_RESERVED, KIDT_ACCESS_RING3, AMD64_INTERRUPT_GATE); } /** @@ -477,8 +475,9 @@ AR::ProcessorSupport::InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBl /* Set initial MXCSR register value */ ProcessorBlock->Prcb.MxCsr = INITIAL_MXCSR; - /* Set initial runlevel */ + /* Set initial runlevel and mark processor as started */ ProcessorBlock->RunLevel = PASSIVE_LEVEL; + ProcessorBlock->Started = TRUE; } /** diff --git a/xtoskrnl/ar/amd64/traps.cc b/xtoskrnl/ar/amd64/traps.cc index e37b67a..8ff9987 100644 --- a/xtoskrnl/ar/amd64/traps.cc +++ b/xtoskrnl/ar/amd64/traps.cc @@ -171,14 +171,6 @@ AR::Traps::DispatchTrap(IN PKTRAP_FRAME TrapFrame) /* Debug-Service-Request raised */ HandleTrap2D(TrapFrame); break; - case 0x2F: - /* Software Interrupt at DISPATCH level */ - HandleTrap2F(TrapFrame); - break; - case 0xE1: - /* InterProcessor Interrupt (IPI) */ - HandleTrapE1(TrapFrame); - break; default: /* Unknown/Unexpected trap */ HandleTrapFF(TrapFrame); @@ -608,40 +600,6 @@ AR::Traps::HandleTrap2D(IN PKTRAP_FRAME TrapFrame) KE::Crash::Panic(0x2D); } -/** - * Handles the trap 0x2F when a software interrupt gets generated at DISPATCH_LEVEL. - * - * @param TrapFrame - * Supplies a kernel trap frame pushed by common trap handler on the stack. - * - * @return This routine does not return any value. - * - * @since XT 1.0 - */ -XTCDECL -VOID -AR::Traps::HandleTrap2F(IN PKTRAP_FRAME TrapFrame) -{ - DebugPrint(L"Unhandled software interrupt at DISPATCH level (0x2F)!\n"); -} - -/** - * Handles the trap 0xE1 when InterProcessor Interrupt (IPI) occurs. - * - * @param TrapFrame - * Supplies a kernel trap frame pushed by common trap handler on the stack. - * - * @return This routine does not return any value. - * - * @since XT 1.0 - */ -XTCDECL -VOID -AR::Traps::HandleTrapE1(IN PKTRAP_FRAME TrapFrame) -{ - DebugPrint(L"Unhandled IPI interrupt (0xE1)!\n"); -} - /** * Handles the trap 0xFF when Unexpected Interrupt occurs. * diff --git a/xtoskrnl/ar/i686/cpufunc.cc b/xtoskrnl/ar/i686/cpufunc.cc index 784d184..b1465e0 100644 --- a/xtoskrnl/ar/i686/cpufunc.cc +++ b/xtoskrnl/ar/i686/cpufunc.cc @@ -587,6 +587,56 @@ AR::CpuFunctions::ReadWriteBarrier(VOID) : "memory"); } +/** + * Performs a Bit Scan Forward instruction to locate the most significant set bit. + * + * @param Index + * Receives the zero-based index of the highest set bit when one is found. + * + * @param Mask + * Supplies the bitmap to scan. + * + * @return This routine returns TRUE when a set bit was found, otherwise FALSE. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +AR::CpuFunctions::ScanForwardBit(OUT PULONG Index, + IN ULONG Mask) +{ + /* Defer to the BSF instruction */ + __asm__("bsfl %[Mask], %[Index]" : [Index] "=r" (*Index) : [Mask] "mr" (Mask)); + + /* Report whether the input had any bit set */ + return Mask ? TRUE : FALSE; +} + +/** + * Performs a Bit Scan Reverse instruction to locate the most significant set bit. + * + * @param Index + * Receives the zero-based index of the highest set bit when one is found. + * + * @param Mask + * Supplies the bitmap to scan. + * + * @return This routine returns TRUE when a set bit was found, otherwise FALSE. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +AR::CpuFunctions::ScanReverseBit(OUT PULONG Index, + IN ULONG Mask) +{ + /* Defer to the BSR instruction */ + __asm__("bsrl %[Mask], %[Index]" : [Index] "=r" (*Index) : [Mask] "mr" (Mask)); + + /* Report whether the input had any bit set */ + return Mask ? TRUE : FALSE; +} + /** * Instructs the processor to set the interrupt flag. * diff --git a/xtoskrnl/ar/i686/procsup.cc b/xtoskrnl/ar/i686/procsup.cc index 98e55e6..57312db 100644 --- a/xtoskrnl/ar/i686/procsup.cc +++ b/xtoskrnl/ar/i686/procsup.cc @@ -28,7 +28,7 @@ XTAPI VOID AR::ProcessorSupport::GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType, OUT PVOID *TrampolineCode, - OUT PULONG_PTR TrampolineSize) + OUT PULONG TrampolineSize) { /* Get trampoline information */ switch(TrampolineType) @@ -465,8 +465,9 @@ AR::ProcessorSupport::InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBl ProcessorBlock->Prcb.IdleThread = &(KE::KThread::GetInitialThread())->ThreadControlBlock; ProcessorBlock->Prcb.NextThread = NULLPTR; - /* Set initial runlevel */ + /* Set initial runlevel and mark processor as started */ ProcessorBlock->RunLevel = PASSIVE_LEVEL; + ProcessorBlock->Started = TRUE; } /** diff --git a/xtoskrnl/ex/data.cc b/xtoskrnl/ex/data.cc new file mode 100644 index 0000000..36e021a --- /dev/null +++ b/xtoskrnl/ex/data.cc @@ -0,0 +1,43 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ex/data.cc + * DESCRIPTION: Kernel Executive global and static data + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/* Tracks all active non-paged lookaside lists in the system */ +LIST_ENTRY EX::LookasideList::NonPagedLookasideListHead; + +/* Spinlock protecting the integrity of the NonPagedLookasideListHead */ +KSPIN_LOCK EX::LookasideList::NonPagedLookasideListLock; + +/* Array of standard system lookaside lists for non-paged pool allocations */ +GENERAL_LOOKASIDE EX::LookasideList::NonPagedPoolLookasideLists[POOL_LOOKASIDE_LISTS]; + +/* Tracks all active paged lookaside lists in the system */ +LIST_ENTRY EX::LookasideList::PagedLookasideListHead; + +/* Spinlock protecting the integrity of the PagedLookasideListHead */ +KSPIN_LOCK EX::LookasideList::PagedLookasideListLock; + +/* Array of standard system lookaside lists for paged pool allocations */ +GENERAL_LOOKASIDE EX::LookasideList::PagedPoolLookasideLists[POOL_LOOKASIDE_LISTS]; + +/* Tracks all standard pool lookaside lists */ +LIST_ENTRY EX::LookasideList::PoolLookasideListHead; + +/* Tracks dynamic system lookaside lists */ +LIST_ENTRY EX::LookasideList::SystemLookasideListHead; + +/* Specifies the default timeout interval for resource wait operations */ +LARGE_INTEGER EX::Resources::ResourcesTimeOut; + +/* Tracks all initialized structures currently active in the system */ +LIST_ENTRY EX::Resources::SystemResourcesList; + +/* The global spinlock that protects the system resources list */ +KSPIN_LOCK EX::Resources::SystemResourcesLock; diff --git a/xtoskrnl/ex/laslist.cc b/xtoskrnl/ex/laslist.cc new file mode 100644 index 0000000..074df27 --- /dev/null +++ b/xtoskrnl/ex/laslist.cc @@ -0,0 +1,457 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ex/laslist.cc + * DESCRIPTION: Lookaside Lists support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Attempts to allocate a fixed-size buffer from the specified non-paged lookaside list. + * + * @param LookasideList + * Supplies a pointer to the non-paged lookaside list. + * + * @return Returns a pointer to the allocated buffer, or NULLPTR if the allocation fails. + * + * @since XT 1.0 + */ +XTAPI +PVOID +EX::LookasideList::AllocateFromLookasideList(IN PNONPAGED_LOOKASIDE_LIST LookasideList) +{ + PVOID Buffer; + + /* Increment the total number of allocation requests */ + LookasideList->Global.TotalAllocates++; + + /* Attempt to pop an entry from the lookaside list */ + Buffer = RTL::Atomic::PopEntrySingleList(&LookasideList->Global.ListHead); + if(!Buffer) + { + /* Increment the miss counter */ + LookasideList->Global.AllocateMisses++; + + /* Fallback to standard pool allocator */ + (LookasideList->Global.Allocate)(LookasideList->Global.Type, LookasideList->Global.Size, + &Buffer, LookasideList->Global.Tag); + } + + /* Return the allocated buffer */ + return Buffer; +} + +/** + * Attempts to allocate a fixed-size buffer from the specified paged lookaside list. + * + * @param LookasideList + * Supplies a pointer to the paged lookaside list. + * + * @return Returns a pointer to the allocated buffer, or NULLPTR if the allocation fails. + * + * @since XT 1.0 + */ +XTAPI +PVOID +EX::LookasideList::AllocateFromLookasideList(IN PPAGED_LOOKASIDE_LIST LookasideList) +{ + PVOID Buffer; + + /* Increment the total number of allocation requests */ + LookasideList->Global.TotalAllocates++; + + /* Attempt to pop an entry from the lookaside list */ + Buffer = RTL::Atomic::PopEntrySingleList(&LookasideList->Global.ListHead); + if(!Buffer) + { + /* Increment the miss counter */ + LookasideList->Global.AllocateMisses++; + + /* Fallback to standard pool allocator */ + (LookasideList->Global.Allocate)(LookasideList->Global.Type, LookasideList->Global.Size, + &Buffer, LookasideList->Global.Tag); + } + + /* Return the allocated buffer */ + return Buffer; +} + +/** + * Allocates a memory block from the specified per-processor lookaside list. + * + * @param Number + * Supplies the index of the lookaside list to allocate from. + * + * @return This routine returns a pointer to the allocated memory block, or NULLPTR if allocation fails. + * + * @since XT 1.0 + */ +XTAPI +PVOID +EX::LookasideList::AllocateFromPerProcessorList(IN NONPAGED_LOOKASIDE_NUMBER Number) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + PGENERAL_LOOKASIDE Lookaside; + PVOID Entry; + + /* Retrieve the current Processor Control Block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Target the processor's local lookaside list and increment the tracking metric */ + Lookaside = Prcb->LookasideList[Number].Local; + Lookaside->TotalAllocates++; + + /* Attempt a pop from the local list */ + Entry = RTL::Atomic::PopEntrySingleList(&Lookaside->ListHead); + if(Entry != NULLPTR) + { + /* Return the retrieved a pre-allocated block */ + return Entry; + } + + /* Record a local cache miss */ + Lookaside->AllocateMisses++; + Lookaside->TotalAllocates++; + + /* Switch the target to the shared global lookaside list */ + Lookaside = Prcb->LookasideList[Number].Global; + + /* Attempt a pop from the global list */ + Entry = RTL::Atomic::PopEntrySingleList(&Lookaside->ListHead); + if(Entry != NULLPTR) + { + /* Return the retrieved a pre-allocated block */ + return Entry; + } + + /* Both caches are saturated, record a miss */ + Lookaside->AllocateMisses++; + + /* Invoke the pool allocator */ + (Lookaside->Allocate)(Lookaside->Type, Lookaside->Size, &Entry, Lookaside->Tag); + + /* Return the newly allocated block */ + return Entry; +} + +/** + * Returns a previously allocated memory block to the specified non-paged lookaside list. + * + * @param LookasideList + * Supplies a pointer to the non-paged lookaside list. + * + * @param Entry + * Supplies a pointer to the memory block being freed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::LookasideList::FreeToLookasideList(IN PNONPAGED_LOOKASIDE_LIST LookasideList, + IN PVOID Entry) +{ + /* Increment the tracking metric */ + LookasideList->Global.TotalFrees++; + + /* Verify if the lookaside list has reached its maximum capacity threshold */ + if(RTL::SinglyList::QueryListDepth(&LookasideList->Global.ListHead) >= LookasideList->Global.Depth) + { + /* The list is full, record a capacity miss */ + LookasideList->Global.FreeMisses++; + (LookasideList->Global.Free)(Entry); + } + else + { + /* Push the block onto the lookaside list */ + RTL::Atomic::PushEntrySingleList(&LookasideList->Global.ListHead, (PSINGLE_LIST_ENTRY)Entry); + } +} + +/** + * Returns a previously allocated memory block to the specified paged lookaside list. + * + * @param LookasideList + * Supplies a pointer to the paged lookaside list. + * + * @param Entry + * Supplies a pointer to the memory block being freed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::LookasideList::FreeToLookasideList(IN PPAGED_LOOKASIDE_LIST LookasideList, + IN PVOID Entry) +{ + /* Increment the tracking metric */ + LookasideList->Global.TotalFrees++; + + /* Verify if the lookaside list has reached its maximum capacity threshold */ + if(RTL::SinglyList::QueryListDepth(&LookasideList->Global.ListHead) >= LookasideList->Global.Depth) + { + /* The list is full, record a capacity miss */ + LookasideList->Global.FreeMisses++; + (LookasideList->Global.Free)(Entry); + } + else + { + /* Push the block onto the lookaside list */ + RTL::Atomic::PushEntrySingleList(&LookasideList->Global.ListHead, (PSINGLE_LIST_ENTRY)Entry); + } +} + +/** + * Frees a memory block back to the specified per-processor lookaside list. + * + * @param Number + * Supplies the index of the lookaside list receiving the freed block. + * + * @param Entry + * Supplies a pointer to the memory block being freed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::LookasideList::FreeToPerProcessorList(IN NONPAGED_LOOKASIDE_NUMBER Number, + IN PVOID Entry) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + PGENERAL_LOOKASIDE Lookaside; + + /* Retrieve the Processor Control Block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Acquire the local lookaside list and increment its total free counter */ + Lookaside = (PGENERAL_LOOKASIDE)Prcb->LookasideList[Number].Local; + Lookaside->TotalFrees++; + + /* Check if the local lookaside list has available capacity */ + if(RTL::SinglyList::QueryListDepth(&Lookaside->ListHead) < Lookaside->Depth) + { + /* Push the buffer onto the local list and exit */ + RTL::Atomic::PushEntrySingleList(&Lookaside->ListHead, (PSINGLE_LIST_ENTRY)Entry); + return; + } + + /* Local list is full, record the miss */ + Lookaside->FreeMisses++; + + /* Acquire the global lookaside list and increment its free counter */ + Lookaside = (PGENERAL_LOOKASIDE)Prcb->LookasideList[Number].Global; + Lookaside->TotalFrees++; + + /* Check if the global lookaside list has available capacity */ + if(RTL::SinglyList::QueryListDepth(&Lookaside->ListHead) < Lookaside->Depth) + { + /* Push the buffer onto the global list and exit */ + RTL::Atomic::PushEntrySingleList(&Lookaside->ListHead, (PSINGLE_LIST_ENTRY)Entry); + return; + } + + /* Global list is full, record the miss */ + Lookaside->FreeMisses++; + + /* Free directly to the system pool */ + Lookaside->Free(Entry); +} + +/** + * Initializes a generic lookaside list and inserts it into the tracking list. + * + * @param LookasideList + * Supplies a pointer to the general lookaside list structure to initialize. + * + * @param PoolType + * Supplies the type of memory pool to be allocated. + * + * @param Size + * Supplies the size, in bytes, of the entries to be allocated from the lookaside list. + * + * @param Tag + * Supplies the pool tag to be used for allocations. + * + * @param MaxDepth + * Supplies the maximum number of entries the lookaside list should hold. + * + * @param ListHead + * Supplies a pointer to the linked list header used to track this lookaside list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::LookasideList::InitializeLookasideList(IN OUT PGENERAL_LOOKASIDE LookasideList, + IN MMPOOL_TYPE PoolType, + IN ULONG Size, + IN ULONG Tag, + IN USHORT MaxDepth, + IN PLIST_ENTRY ListHead) +{ + /* Initialize the singly linked list header and insert it into the tracking list */ + RTL::SinglyList::InitializeListHead(&LookasideList->ListHead); + RTL::LinkedList::InsertTailList(ListHead, &LookasideList->ListEntry); + + /* Initialize lookaside list properties */ + LookasideList->Allocate = &MM::Allocator::AllocatePool; + LookasideList->AllocateHits = 0; + LookasideList->Depth = 2; + LookasideList->Free = &MM::Allocator::FreePool; + LookasideList->FreeHits = 0; + LookasideList->LastAllocateHits = 0; + LookasideList->LastTotalAllocates = 0; + LookasideList->MaximumDepth = MaxDepth; + LookasideList->Size = Size; + LookasideList->Tag = Tag; + LookasideList->TotalAllocates = 0; + LookasideList->TotalFrees = 0; + LookasideList->Type = PoolType; +} + +/** + * Initializes the per-processor lookaside list pointers. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::LookasideList::InitializePointers(VOID) +{ + PGENERAL_LOOKASIDE LookasideList; + PKPROCESSOR_CONTROL_BLOCK Prcb; + ULONG Index, Offset; + XTSTATUS Status; + + /* Retrieve the processor control block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Allocate a contiguous memory block for lookaside lists */ + Status = MM::Allocator::AllocatePool(NonPagedPool, sizeof(GENERAL_LOOKASIDE) * POOL_LOOKASIDE_LISTS * 2, + (PVOID*)&LookasideList, TAG_MM_MEMORY_POOL); + + /* Initialize both non-paged and paged lookaside lists for all pool indexes */ + for(Index = 0; Index < POOL_LOOKASIDE_LISTS; Index++) + { + /* Wire the global pointer for the non-paged lookaside list */ + Prcb->NonPagedLookasideList[Index].Global = &NonPagedPoolLookasideLists[Index]; + + /* Check if the contiguous allocation was successful */ + if(Status == STATUS_SUCCESS && LookasideList) + { + /* Map the pointer to the first half of the contiguous block */ + Prcb->NonPagedLookasideList[Index].Local = &LookasideList[Index]; + + /* Initialize the local non-paged list */ + EX::LookasideList::InitializeLookasideList(&LookasideList[Index], NonPagedPool, + (Index + 1) * 8, TAG_MM_MEMORY_POOL, + 256, &PoolLookasideListHead); + } + else + { + /* Allocation failed, use shared global list */ + Prcb->NonPagedLookasideList[Index].Local = &NonPagedPoolLookasideLists[Index]; + } + + /* Wire the global pointer for the paged lookaside list */ + Prcb->PagedLookasideList[Index].Global = &PagedPoolLookasideLists[Index]; + + /* Check if the contiguous allocation was successful */ + if(Status == STATUS_SUCCESS && LookasideList) + { + /* Calculate the offset into the second half of the contiguous memory block */ + Offset = POOL_LOOKASIDE_LISTS + Index; + + /* Map the pointer to the second half of the contiguous block */ + Prcb->PagedLookasideList[Index].Local = &LookasideList[Offset]; + + /* Initialize the local paged list */ + EX::LookasideList::InitializeLookasideList(&LookasideList[Offset], PagedPool, + (Index + 1) * 8, TAG_MM_MEMORY_POOL, + 256, &PoolLookasideListHead); + } + else + { + /* Allocation failed, use shared global list */ + Prcb->PagedLookasideList[Index].Local = &PagedPoolLookasideLists[Index]; + } + } +} + +/** + * Initializes global system lookaside lists and their synchronization primitives. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::LookasideList::InitializeSystemLookasideLists(VOID) +{ + ULONG Index; + + /* Initialize spinlocks for protecting lookaside list operations */ + KE::SpinLock::InitializeSpinLock(&NonPagedLookasideListLock); + KE::SpinLock::InitializeSpinLock(&PagedLookasideListLock); + + /* Initialize global list heads for tracking various types of lookaside lists */ + RTL::LinkedList::InitializeListHead(&NonPagedLookasideListHead); + RTL::LinkedList::InitializeListHead(&PagedLookasideListHead); + RTL::LinkedList::InitializeListHead(&PoolLookasideListHead); + RTL::LinkedList::InitializeListHead(&SystemLookasideListHead); + + /* Initialize standard pool lookaside lists */ + for(Index = 0; Index < POOL_LOOKASIDE_LISTS; Index++) + { + /* Initialize non-paged pool lookaside list */ + InitializeLookasideList(&NonPagedPoolLookasideLists[Index], NonPagedPool, (Index + 1) * 8, + TAG_MM_MEMORY_POOL, 256, &PoolLookasideListHead); + + /* Initialize paged pool lookaside list */ + InitializeLookasideList(&PagedPoolLookasideLists[Index], PagedPool, (Index + 1) * 8, + TAG_MM_MEMORY_POOL, 256, &PoolLookasideListHead); + } +} + +/** + * Retrieves the head of the pool lookaside list tracker. + * + * @return This routine returns a pointer to the global pool lookaside list head. + * + * @since XT 1.0 + */ +XTAPI +PLIST_ENTRY +EX::LookasideList::GetPoolLookasideListHead(VOID) +{ + /* Return the head of the pool lookaside list */ + return &PoolLookasideListHead; +} + +/** + * Retrieves the head of the system-wide lookaside list tracker. + * + * @return This routine returns a pointer to the global system lookaside list head. + * + * @since XT 1.0 + */ +XTAPI +PLIST_ENTRY +EX::LookasideList::GetSystemLookasideListHead(VOID) +{ + /* Return the head of the pool lookaside list */ + return &SystemLookasideListHead; +} diff --git a/xtoskrnl/ex/resource.cc b/xtoskrnl/ex/resource.cc new file mode 100644 index 0000000..a1115be --- /dev/null +++ b/xtoskrnl/ex/resource.cc @@ -0,0 +1,169 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ex/resource.cc + * DESCRIPTION: Exclusive resource synchronization support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Deletes a system resource and frees its associated memory allocations. + * + * @param Resource + * Supplies a pointer to the resource to be deleted. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +EX::Resources::DeleteResource(IN PERESOURCE Resource) +{ + /* Start a guarded code block */ + { + /* Raise runlevel to DISPATCH level and acquire system resources lock */ + KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); + KE::QueuedSpinLockGuard Guard(&SystemResourcesLock); + + /* Remove the resource from the system resource list */ + RTL::LinkedList::RemoveEntryList(&Resource->SystemResourcesList); + } + + /* Check if exclusive waiters event exists */ + if(Resource->ExclusiveWaiters) + { + /* Free the exclusive waiters event */ + MM::Allocator::FreePool(Resource->ExclusiveWaiters); + } + + /* Check if owner table exists */ + if(Resource->OwnerTable) + { + /* Free the owner table */ + MM::Allocator::FreePool(Resource->OwnerTable); + } + + /* Check if shared waiters semaphore exists */ + if(Resource->SharedWaiters) + { + /* Free the shared waiters semaphore */ + MM::Allocator::FreePool(Resource->SharedWaiters); + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Initializes a system resource object. + * + * @param Resource + * Supplies a pointer to the resource structure to be initialized. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +EX::Resources::InitializeResource(IN PERESOURCE Resource) +{ + /* Clear the entire resource structure */ + RTL::Memory::ZeroMemory(Resource, sizeof(ERESOURCE)); + + /* Initialize the spinlock used for managing this resource */ + KE::SpinLock::InitializeSpinLock(&Resource->SpinLock); + + /* Raise runlevel to DISPATCH level and acquire the global system resources lock */ + KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); + KE::QueuedSpinLockGuard Guard(&SystemResourcesLock); + + /* Insert the resource into the global tracking list */ + RTL::LinkedList::InsertTailList(&SystemResourcesList, &Resource->SystemResourcesList); + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Initializes the global system resource structures and synchronization primitives. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::Resources::InitializeSystemResources(VOID) +{ + /* Set the default timeout for resource operations to 4 seconds relative to now */ + ResourcesTimeOut.QuadPart = -40000000LL; + + /* Initialize the global system resources list and its protecting spinlock */ + RTL::LinkedList::InitializeListHead(&SystemResourcesList); + KE::SpinLock::InitializeSpinLock(&SystemResourcesLock); +} + +/** + * Reinitializes an existing resource object, resetting its state and synchronization primitives. + * + * @param Resource + * Supplies a pointer to the resource structure to be reinitialized. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +EX::Resources::ReinitializeResource(IN PERESOURCE Resource) +{ + ULONG Index; + + /* Zero the active count and flags */ + Resource->ActiveCount = 0; + Resource->ActiveEntries = 0; + Resource->Flag = 0; + + /* Zero the contention count and counters */ + Resource->ContentionCount = 0; + Resource->NumberOfSharedWaiters = 0; + Resource->NumberOfExclusiveWaiters = 0; + + /* Zero the owner entry */ + Resource->OwnerEntry.OwnerThread = 0; + Resource->OwnerEntry.TableSize = 0; + + /* Check if exclusive waiters event exists */ + if(Resource->ExclusiveWaiters) + { + /* Reinitialize the event */ + KE::Event::InitializeEvent(Resource->ExclusiveWaiters, SynchronizationEvent, FALSE); + } + + /* Check if owner table exists */ + if(Resource->OwnerTable) + { + /* Iterate over the owner table */ + for(Index = 1; Index < Resource->OwnerTable->TableSize; Index++) + { + /* Zero the owner table */ + Resource->OwnerTable[Index].OwnerCount = 0; + Resource->OwnerTable[Index].OwnerThread = 0; + } + } + + /* Check if shared waiters semaphore exists */ + if(Resource->SharedWaiters) + { + /* Reinitialize the semaphore */ + KE::Semaphore::InitializeSemaphore(Resource->SharedWaiters, 0, MAXLONG); + } + + /* Return success */ + return STATUS_SUCCESS; +} diff --git a/xtoskrnl/ex/rundown.cc b/xtoskrnl/ex/rundown.cc index 2582517..cef9d10 100644 --- a/xtoskrnl/ex/rundown.cc +++ b/xtoskrnl/ex/rundown.cc @@ -4,6 +4,7 @@ * FILE: xtoskrnl/ex/rundown.cc * DESCRIPTION: Rundown protection mechanism * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #include @@ -22,6 +23,28 @@ XTFASTCALL BOOLEAN EX::Rundown::AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) +{ + /* Acquire protection */ + return AcquireProtection(Descriptor, 1); +} + +/** + * Acquires the rundown protection for given descriptor. + * + * @param Descriptor + * Supplies a pointer to the rundown block descriptor. + * + * @param Count + * Supplies the number of times the protection should be acquired. + * + * @return This routine returns TRUE if protection acquired successfully, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +EX::Rundown::AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor, + IN ULONG Count) { ULONG_PTR CurrentValue, NewValue; @@ -39,7 +62,7 @@ EX::Rundown::AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) } /* Attempt to increment the usage count */ - NewValue = CurrentValue + 2; + NewValue = CurrentValue + 2 * Count; /* Exchange the value */ NewValue = (ULONG_PTR)RTL::Atomic::CompareExchangePointer(&Descriptor->Ptr, (PVOID)NewValue, @@ -71,6 +94,7 @@ XTFASTCALL VOID EX::Rundown::CompleteProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) { + /* Mark the descriptor as completely run down */ RTL::Atomic::ExchangePointer(&Descriptor->Ptr, (PVOID)EX_RUNDOWN_ACTIVE); } @@ -106,6 +130,7 @@ XTFASTCALL VOID EX::Rundown::ReInitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) { + /* Reset the descriptor to its initial state */ RTL::Atomic::ExchangePointer(&Descriptor->Ptr, NULLPTR); } @@ -122,39 +147,71 @@ EX::Rundown::ReInitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) XTFASTCALL VOID EX::Rundown::ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor) +{ + /* Release protection */ + ReleaseProtection(Descriptor, 1); +} + +/** + * Releases the rundown protection for given descriptor. + * + * @param Descriptor + * Supplies a pointer to the descriptor to be initialized. + * + * @param Count + * Supplies the number of references to release. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +EX::Rundown::ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor, + IN ULONG Count) { ULONG_PTR CurrentValue, NewValue; PEX_RUNDOWN_WAIT_BLOCK WaitBlock; + /* Read the current state of the rundown descriptor */ CurrentValue = Descriptor->Count; + /* Enter a CAS loop */ while(TRUE) { + /* Check if the rundown is currently active */ if(CurrentValue & 0x1) { + /* Extract the pointer to the wait block */ WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(CurrentValue & ~0x1); + /* Decrement the pending reference count */ if(!RTL::Atomic::Decrement64((PLONG_PTR)&WaitBlock->Count)) { + /* Signal the event to wake up the teardown thread */ KE::Event::SetEvent(&WaitBlock->WakeEvent, 0, FALSE); } + /* Break the loop */ break; } else { /* Attempt to decrement the usage count */ - NewValue = CurrentValue - 2; + NewValue = CurrentValue - 2 * Count; /* Exchange the value */ NewValue = (ULONG_PTR)RTL::Atomic::CompareExchangePointer(&Descriptor->Ptr, (PVOID)NewValue, (PVOID)CurrentValue); + /* Check if the atomic swap succeeded without interference from other processors */ if(NewValue == CurrentValue) { + /* Reference count is decremented, break the loop */ break; } + /* Collision detected, update current state and retry */ CurrentValue = NewValue; } } diff --git a/xtoskrnl/ex/workitem.cc b/xtoskrnl/ex/workitem.cc new file mode 100644 index 0000000..2248b38 --- /dev/null +++ b/xtoskrnl/ex/workitem.cc @@ -0,0 +1,62 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ex/workitem.cc + * DESCRIPTION: Asynchronous Work Queue Items and System Worker Thread Management + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Initializes a work queue item. + * + * @param Item + * Supplies a pointer to the work queue item to be initialized. + * + * @param Routine + * Supplies the worker routine to be executed. + * + * @param Context + * Supplies the context parameter to pass to the worker routine. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::WorkItem::InitializeWorkItem(IN PWORK_QUEUE_ITEM Item, + IN PWORKER_THREAD_ROUTINE Routine, + IN PVOID Context) +{ + /* Initialize the work item fields */ + Item->WorkerRoutine = Routine; + Item->Parameter = Context; + + /* Initialize the list entry links */ + Item->List.Flink = NULLPTR; +} + +/** + * Queues a work item to be executed by a system worker thread. + * + * @param WorkItem + * Supplies a pointer to the initialized work queue item. + * + * @param QueueType + * Supplies the type of work queue to insert the item into. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +EX::WorkItem::QueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, + IN WORK_QUEUE_TYPE QueueType) +{ + /* Not implemented */ + UNIMPLEMENTED; +} diff --git a/xtoskrnl/hl/data.cc b/xtoskrnl/hl/data.cc index f20821d..9a8052c 100644 --- a/xtoskrnl/hl/data.cc +++ b/xtoskrnl/hl/data.cc @@ -28,7 +28,7 @@ ACPI_SYSTEM_INFO HL::Acpi::SystemInfo; ACPI_TIMER_INFO HL::Acpi::TimerInfo; /* Represents the number of active processors */ -KAFFINITY HL::Cpu::ActiveProcessors; +PKAFFINITY_MAP HL::Cpu::ActiveProcessors; /* Metadata detailing the linear frame buffer geometry */ HL_FRAMEBUFFER_DATA HL::FrameBuffer::FrameBufferData; diff --git a/xtoskrnl/hl/fbdev.cc b/xtoskrnl/hl/fbdev.cc index d049b56..72126b0 100644 --- a/xtoskrnl/hl/fbdev.cc +++ b/xtoskrnl/hl/fbdev.cc @@ -409,7 +409,7 @@ HL::FrameBuffer::EnableShadowBuffer(VOID) /* Allocate non-paged memory for the shadow buffer */ Status = MM::Allocator::AllocatePool(NonPagedPool, FrameBufferSize, - &ScreenShadowBuffer, SIGNATURE32('F', 'B', 'U', 'F')); + &ScreenShadowBuffer, TAG_HL_FRAMEBUFFER); if(Status != STATUS_SUCCESS) { /* Allocation failed, return status code */ diff --git a/xtoskrnl/hl/x86/cpu.cc b/xtoskrnl/hl/x86/cpu.cc index 10b41f9..0054433 100644 --- a/xtoskrnl/hl/x86/cpu.cc +++ b/xtoskrnl/hl/x86/cpu.cc @@ -9,6 +9,21 @@ #include +/** + * Retrieves the system-wide active processor affinity map. + * + * @return This routine returns a pointer to the KAFFINITY_MAP structure representing the active processors. + * + * @since XT 1.0 + */ +XTAPI +PKAFFINITY_MAP +HL::Cpu::GetActiveProcessors(VOID) +{ + /* Return active processors map */ + return ActiveProcessors; +} + /** * Initializes the processor. * @@ -24,7 +39,6 @@ VOID HL::Cpu::InitializeProcessor(VOID) { PKPROCESSOR_BLOCK ProcessorBlock; - KAFFINITY Affinity; /* Get current processor block */ ProcessorBlock = KE::Processor::GetCurrentProcessorBlock(); @@ -33,17 +47,46 @@ HL::Cpu::InitializeProcessor(VOID) ProcessorBlock->StallScaleFactor = INITIAL_STALL_FACTOR; ProcessorBlock->Idr = 0xFFFFFFFF; - /* Set processor affinity */ - Affinity = (KAFFINITY) 1 << ProcessorBlock->CpuNumber; - - /* Apply affinity to a set of processors */ - ActiveProcessors |= Affinity; + /* Check if active processors map is initialized */ + if(ActiveProcessors != NULLPTR) + { + /* Register this CPU in the global active processors map */ + KE::Affinity::AtomicSetProcessorAffinity(ActiveProcessors, ProcessorBlock->CpuNumber); + } /* Initialize APIC for this processor */ HL::Pic::InitializePic(); /* Set the APIC running level */ - HL::RunLevel::SetRunLevel(KE::Processor::GetCurrentProcessorBlock()->RunLevel); + HL::RunLevel::SetRunLevel(ProcessorBlock->RunLevel); +} + +/** + * Initializes the global processor affinity map for active processors and registers Bootstrap Processor (BSP). + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +HL::Cpu::InitializeProcessorAffinity(VOID) +{ + XTSTATUS Status; + + /* Allocate an array of pointers */ + Status = KE::Affinity::CreateAffinityMap(KE::Processor::GetInstalledCpus(), &ActiveProcessors); + if(Status != STATUS_SUCCESS) + { + /* Failed to allocate memory, return error */ + return Status; + } + + /* Register BSP in the global active processors map */ + KE::Affinity::SetProcessorAffinity(ActiveProcessors, 0); + + /* Return success */ + return STATUS_SUCCESS; } /** @@ -57,9 +100,9 @@ XTAPI XTSTATUS HL::Cpu::StartAllProcessors(VOID) { - ULONG CpuNumber, Index, MaxCpus, SipiVector, Timeout, TrampolinePages; - PVOID CpuStructures, TrampolineAddress, TrampolineCode; - ULONG_PTR AllocationSize, TrampolineCodeSize; + ULONG ApPages, CpuNumber, Index, MaxCpus, SipiVector, Timeout, TrampolineCodeSize; + PVOID ApVirtualAddress, CpuStructures, TrampolineCode; + PHYSICAL_ADDRESS ApPhysicalAddress; PPROCESSOR_START_BLOCK StartBlock; PKPROCESSOR_BLOCK ProcessorBlock; PACPI_SYSTEM_INFO SysInfo; @@ -108,27 +151,34 @@ HL::Cpu::StartAllProcessors(VOID) return STATUS_UNSUCCESSFUL; } - /* Compute trampoline memory allocation size (trampoline + processor start block + temporary stack) */ - AllocationSize = TrampolineCodeSize + sizeof(PROCESSOR_START_BLOCK) + 512; - TrampolinePages = (ULONG)(ROUND_UP(AllocationSize, MM_PAGE_SIZE) / MM_PAGE_SIZE); - - /* Allocate real mode memory for AP trampoline */ - Status = MM::HardwarePool::AllocateRealModeMemory(TrampolinePages, &TrampolineAddress); + /* Allocate low memory for AP trampoline code */ + Status = MM::HardwarePool::AllocateLowMemory(&ApPhysicalAddress, &ApVirtualAddress); if(Status != STATUS_SUCCESS) { /* Failed to allocate memory, print error message and return error */ - DebugPrint(L"Failed to allocate %lu pages for AP Trampoline!\n", TrampolinePages); + DebugPrint(L"Failed to allocate low memory for AP Trampoline!\n"); return Status; } /* Copy trampoline code to low memory */ - RTL::Memory::CopyMemory(TrampolineAddress, TrampolineCode, TrampolineCodeSize); + RTL::Memory::CopyMemory(ApVirtualAddress, TrampolineCode, TrampolineCodeSize); + + /* Compute number of pages for trampoline */ + ApPages = MM::HardwarePool::CalculateRealModeAllocationPages(TrampolineCodeSize); + + /* Temporarily identity map trampoline address */ + Status = MM::HardwarePool::MapRealModeMemory(ApPhysicalAddress, ApPages); + if(Status != STATUS_SUCCESS) + { + /* Failed to map memory, return error */ + return Status; + } /* Get start block address relative to trampoline address */ - StartBlock = (PPROCESSOR_START_BLOCK)((PUCHAR)TrampolineAddress + TrampolineCodeSize); + StartBlock = (PPROCESSOR_START_BLOCK)((PUCHAR)ApVirtualAddress + TrampolineCodeSize); /* Get SIPI vector */ - SipiVector = (ULONG)((ULONG_PTR)TrampolineAddress >> 12); + SipiVector = (ULONG)(ApPhysicalAddress.QuadPart >> APIC_VECTOR_SIPI_SHIFT); /* Loop over all CPUs */ CpuNumber = 0; @@ -155,8 +205,8 @@ HL::Cpu::StartAllProcessors(VOID) Status = MM::KernelPool::AllocateProcessorStructures(&CpuStructures); if(Status != STATUS_SUCCESS) { - /* Failed to allocate memory, unmap memory and return error */ - MM::HardwarePool::UnmapHardwareMemory(TrampolineAddress, TrampolinePages, TRUE); + /* Failed to allocate memory, unmap temporary identity mapping and return error */ + MM::HardwarePool::UnmapRealModeMemory(ApPhysicalAddress, ApPages); return Status; } @@ -214,7 +264,7 @@ HL::Cpu::StartAllProcessors(VOID) } } - /* Unmap trampoline memory and return success */ - MM::HardwarePool::UnmapHardwareMemory(TrampolineAddress, TrampolinePages, TRUE); + /* Unmap temporary identity mapping and return success */ + MM::HardwarePool::UnmapRealModeMemory(ApPhysicalAddress, ApPages); return STATUS_SUCCESS; } diff --git a/xtoskrnl/hl/x86/pic.cc b/xtoskrnl/hl/x86/pic.cc index b5de283..61ae043 100644 --- a/xtoskrnl/hl/x86/pic.cc +++ b/xtoskrnl/hl/x86/pic.cc @@ -311,7 +311,7 @@ XTCDECL VOID HL::Pic::HandleApicErrorInterrupt(IN PKTRAP_FRAME TrapFrame) { - ULONG ErrorStatus; + UNUSED ULONG ErrorStatus; /* Write 0 to the ESR register to trigger an internal state update, then read the latched status */ WriteApicRegister(APIC_ESR, 0); diff --git a/xtoskrnl/includes/ar/amd64/cpufunc.hh b/xtoskrnl/includes/ar/amd64/cpufunc.hh index 0d0a43c..b717095 100644 --- a/xtoskrnl/includes/ar/amd64/cpufunc.hh +++ b/xtoskrnl/includes/ar/amd64/cpufunc.hh @@ -42,6 +42,10 @@ namespace AR STATIC XTCDECL ULONGLONG ReadTimeStampCounter(VOID); STATIC XTCDECL ULONGLONG ReadTimeStampCounterProcessor(OUT PULONG TscAux); STATIC XTCDECL VOID ReadWriteBarrier(VOID); + STATIC XTCDECL BOOLEAN ScanForwardBit(OUT PULONG Index, + IN ULONG Mask); + STATIC XTCDECL BOOLEAN ScanReverseBit(OUT PULONG Index, + IN ULONG Mask); STATIC XTCDECL VOID SetInterruptFlag(VOID); STATIC XTCDECL VOID StoreGlobalDescriptorTable(OUT PVOID Destination); STATIC XTCDECL VOID StoreInterruptDescriptorTable(OUT PVOID Destination); diff --git a/xtoskrnl/includes/ar/amd64/procsup.hh b/xtoskrnl/includes/ar/amd64/procsup.hh index 21404e4..e18c65b 100644 --- a/xtoskrnl/includes/ar/amd64/procsup.hh +++ b/xtoskrnl/includes/ar/amd64/procsup.hh @@ -30,7 +30,7 @@ namespace AR STATIC XTAPI PVOID GetBootStack(VOID); STATIC XTAPI VOID GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType, OUT PVOID *TrampolineCode, - OUT PULONG_PTR TrampolineSize); + OUT PULONG TrampolineSize); STATIC XTAPI VOID InitializeProcessor(IN PVOID ProcessorStructures); STATIC XTAPI VOID InitializeProcessorStructures(IN PVOID ProcessorStructures, OUT PKGDTENTRY *Gdt, diff --git a/xtoskrnl/includes/ar/amd64/traps.hh b/xtoskrnl/includes/ar/amd64/traps.hh index 2481ea8..fc6fe6a 100644 --- a/xtoskrnl/includes/ar/amd64/traps.hh +++ b/xtoskrnl/includes/ar/amd64/traps.hh @@ -51,8 +51,6 @@ namespace AR STATIC XTCDECL VOID HandleTrap1F(IN PKTRAP_FRAME TrapFrame); STATIC XTCDECL VOID HandleTrap2C(IN PKTRAP_FRAME TrapFrame); STATIC XTCDECL VOID HandleTrap2D(IN PKTRAP_FRAME TrapFrame); - STATIC XTCDECL VOID HandleTrap2F(IN PKTRAP_FRAME TrapFrame); - STATIC XTCDECL VOID HandleTrapE1(IN PKTRAP_FRAME TrapFrame); STATIC XTCDECL VOID HandleTrapFF(IN PKTRAP_FRAME TrapFrame); }; } diff --git a/xtoskrnl/includes/ar/i686/cpufunc.hh b/xtoskrnl/includes/ar/i686/cpufunc.hh index 28cfdb1..3e5b3b3 100644 --- a/xtoskrnl/includes/ar/i686/cpufunc.hh +++ b/xtoskrnl/includes/ar/i686/cpufunc.hh @@ -41,6 +41,10 @@ namespace AR STATIC XTCDECL ULONGLONG ReadTimeStampCounter(VOID); STATIC XTCDECL ULONGLONG ReadTimeStampCounterProcessor(OUT PULONG TscAux); STATIC XTCDECL VOID ReadWriteBarrier(VOID); + STATIC XTCDECL BOOLEAN ScanForwardBit(OUT PULONG Index, + IN ULONG Mask); + STATIC XTCDECL BOOLEAN ScanReverseBit(OUT PULONG Index, + IN ULONG Mask); STATIC XTCDECL VOID SetInterruptFlag(VOID); STATIC XTCDECL VOID StoreGlobalDescriptorTable(OUT PVOID Destination); STATIC XTCDECL VOID StoreInterruptDescriptorTable(OUT PVOID Destination); diff --git a/xtoskrnl/includes/ar/i686/procsup.hh b/xtoskrnl/includes/ar/i686/procsup.hh index d7cd16d..1886f13 100644 --- a/xtoskrnl/includes/ar/i686/procsup.hh +++ b/xtoskrnl/includes/ar/i686/procsup.hh @@ -33,7 +33,7 @@ namespace AR STATIC XTAPI PVOID GetBootStack(VOID); STATIC XTAPI VOID GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType, OUT PVOID *TrampolineCode, - OUT PULONG_PTR TrampolineSize); + OUT PULONG TrampolineSize); STATIC XTAPI VOID InitializeProcessor(IN PVOID ProcessorStructures); STATIC XTAPI VOID InitializeProcessorStructures(IN PVOID ProcessorStructures, OUT PKGDTENTRY *Gdt, diff --git a/xtoskrnl/includes/ex.hh b/xtoskrnl/includes/ex.hh index 747bd2f..a4c31ec 100644 --- a/xtoskrnl/includes/ex.hh +++ b/xtoskrnl/includes/ex.hh @@ -11,6 +11,9 @@ #include +#include +#include #include +#include #endif /* __XTOSKRNL_EX_HH */ diff --git a/xtoskrnl/includes/ex/laslist.hh b/xtoskrnl/includes/ex/laslist.hh new file mode 100644 index 0000000..dbd3aa1 --- /dev/null +++ b/xtoskrnl/includes/ex/laslist.hh @@ -0,0 +1,53 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ex/laslist.hh + * DESCRIPTION: Lookaside Lists support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_EX_LASLIST_HH +#define __XTOSKRNL_EX_LASLIST_HH + +#include + + +/* Kernel Executive */ +namespace EX +{ + class LookasideList + { + private: + STATIC LIST_ENTRY NonPagedLookasideListHead; + STATIC KSPIN_LOCK NonPagedLookasideListLock; + STATIC GENERAL_LOOKASIDE NonPagedPoolLookasideLists[POOL_LOOKASIDE_LISTS]; + STATIC LIST_ENTRY PagedLookasideListHead; + STATIC KSPIN_LOCK PagedLookasideListLock; + STATIC GENERAL_LOOKASIDE PagedPoolLookasideLists[POOL_LOOKASIDE_LISTS]; + STATIC LIST_ENTRY PoolLookasideListHead; + STATIC LIST_ENTRY SystemLookasideListHead; + + public: + STATIC XTAPI PVOID AllocateFromLookasideList(IN PNONPAGED_LOOKASIDE_LIST LookasideList); + STATIC XTAPI PVOID AllocateFromLookasideList(IN PPAGED_LOOKASIDE_LIST LookasideList); + STATIC XTAPI PVOID AllocateFromPerProcessorList(IN NONPAGED_LOOKASIDE_NUMBER Number); + STATIC XTAPI VOID FreeToLookasideList(IN PNONPAGED_LOOKASIDE_LIST LookasideList, + IN PVOID Entry); + STATIC XTAPI VOID FreeToLookasideList(IN PPAGED_LOOKASIDE_LIST LookasideList, + IN PVOID Entry); + STATIC XTAPI VOID FreeToPerProcessorList(IN NONPAGED_LOOKASIDE_NUMBER Number, + IN PVOID Entry); + STATIC XTAPI VOID InitializeLookasideList(IN OUT PGENERAL_LOOKASIDE LookasideList, + IN MMPOOL_TYPE PoolType, + IN ULONG Size, + IN ULONG Tag, + IN USHORT MaxDepth, + IN PLIST_ENTRY ListHead); + STATIC XTAPI VOID InitializePointers(VOID); + STATIC XTAPI VOID InitializeSystemLookasideLists(VOID); + STATIC XTAPI PLIST_ENTRY GetPoolLookasideListHead(VOID); + STATIC XTAPI PLIST_ENTRY GetSystemLookasideListHead(VOID); + }; +} + +#endif /* __XTOSKRNL_EX_LASLIST_HH */ diff --git a/xtoskrnl/includes/ex/resource.hh b/xtoskrnl/includes/ex/resource.hh new file mode 100644 index 0000000..1492da4 --- /dev/null +++ b/xtoskrnl/includes/ex/resource.hh @@ -0,0 +1,33 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ex/resource.hh + * DESCRIPTION: Exclusive resource synchronization support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_EX_RESOURCE_HH +#define __XTOSKRNL_EX_RESOURCE_HH + +#include + + +/* Kernel Executive */ +namespace EX +{ + class Resources + { + private: + STATIC LARGE_INTEGER ResourcesTimeOut; + STATIC LIST_ENTRY SystemResourcesList; + STATIC KSPIN_LOCK SystemResourcesLock; + + public: + STATIC XTAPI XTSTATUS DeleteResource(IN PERESOURCE Resource); + STATIC XTAPI XTSTATUS InitializeResource(IN PERESOURCE Resource); + STATIC XTAPI VOID InitializeSystemResources(VOID); + STATIC XTAPI XTSTATUS ReinitializeResource(IN PERESOURCE Resource); + }; +} + +#endif /* __XTOSKRNL_EX_RESOURCES_HH */ diff --git a/xtoskrnl/includes/ex/rundown.hh b/xtoskrnl/includes/ex/rundown.hh index b7d617f..4101204 100644 --- a/xtoskrnl/includes/ex/rundown.hh +++ b/xtoskrnl/includes/ex/rundown.hh @@ -12,17 +12,21 @@ #include -/* Architecture-specific Library */ +/* Kernel Executive */ namespace EX { class Rundown { public: STATIC XTFASTCALL BOOLEAN AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); + STATIC XTFASTCALL BOOLEAN AcquireProtection(IN PEX_RUNDOWN_REFERENCE Descriptor, + IN ULONG Count); STATIC XTFASTCALL VOID CompleteProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID InitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID ReInitializeProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); STATIC XTFASTCALL VOID ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor); + STATIC XTFASTCALL VOID ReleaseProtection(IN PEX_RUNDOWN_REFERENCE Descriptor, + IN ULONG Count); STATIC XTFASTCALL VOID WaitForProtectionRelease(IN PEX_RUNDOWN_REFERENCE Descriptor); }; } diff --git a/xtoskrnl/includes/ex/workitem.hh b/xtoskrnl/includes/ex/workitem.hh new file mode 100644 index 0000000..0ba88c0 --- /dev/null +++ b/xtoskrnl/includes/ex/workitem.hh @@ -0,0 +1,29 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ex/workitem.hh + * DESCRIPTION: Asynchronous Work Queue Items and System Worker Thread Management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_EX_WORKITEM_HH +#define __XTOSKRNL_EX_WORKITEM_HH + +#include + + +/* Kernel Executive */ +namespace EX +{ + class WorkItem + { + public: + STATIC XTAPI VOID InitializeWorkItem(IN PWORK_QUEUE_ITEM Item, + IN PWORKER_THREAD_ROUTINE Routine, + IN PVOID Context); + STATIC XTAPI VOID QueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, + IN WORK_QUEUE_TYPE QueueType); + }; +} + +#endif /* __XTOSKRNL_EX_WORKITEM_HH */ diff --git a/xtoskrnl/includes/hl/cpu.hh b/xtoskrnl/includes/hl/cpu.hh index e75d011..1b80a2d 100644 --- a/xtoskrnl/includes/hl/cpu.hh +++ b/xtoskrnl/includes/hl/cpu.hh @@ -18,10 +18,12 @@ namespace HL class Cpu { private: - STATIC KAFFINITY ActiveProcessors; + STATIC PKAFFINITY_MAP ActiveProcessors; public: + STATIC XTAPI PKAFFINITY_MAP GetActiveProcessors(VOID); STATIC XTAPI VOID InitializeProcessor(VOID); + STATIC XTAPI XTSTATUS InitializeProcessorAffinity(VOID); STATIC XTAPI XTSTATUS StartAllProcessors(VOID); }; } diff --git a/xtoskrnl/includes/kd.hh b/xtoskrnl/includes/kd.hh index 859cfc7..dc91213 100644 --- a/xtoskrnl/includes/kd.hh +++ b/xtoskrnl/includes/kd.hh @@ -13,5 +13,6 @@ #include #include +#include #endif /* __XTOSKRNL_KD_HH */ diff --git a/xtoskrnl/includes/kd/debug.hh b/xtoskrnl/includes/kd/debug.hh new file mode 100644 index 0000000..35d2196 --- /dev/null +++ b/xtoskrnl/includes/kd/debug.hh @@ -0,0 +1,38 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/kd/debug.hh + * DESCRIPTION: Kernel Debugger + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_KD_DEBUG_HH +#define __XTOSKRNL_KD_DEBUG_HH + +#include + + +/* Kernel Debugger */ +namespace KD +{ + class Debugger + { + public: + STATIC PKD_PRINT_ROUTINE KdPrint; + + private: + STATIC BOOLEAN Active; + + public: + STATIC XTAPI BOOLEAN DebuggerActive(VOID); + STATIC XTAPI VOID EnterDebugger(IN PKTRAP_FRAME TrapFrame); + STATIC XTAPI KCONTINUE_STATUS SwitchProcessor(VOID); + + private: + STATIC XTAPI BOOLEAN ProcessCpuStateChange(IN PEXCEPTION_RECORD ExceptionRecord, + IN OUT PCONTEXT Context, + IN BOOLEAN SecondChanceException); + }; +} + +#endif /* __XTOSKRNL_KD_DEBUG_HH */ diff --git a/xtoskrnl/includes/ke.hh b/xtoskrnl/includes/ke.hh index 3bd4419..f64abbf 100644 --- a/xtoskrnl/includes/ke.hh +++ b/xtoskrnl/includes/ke.hh @@ -11,23 +11,29 @@ #include +#include #include #include #include #include +#include #include #include #include +#include #include #include #include #include #include +#include #include +#include #include #include #include #include +#include #include #include diff --git a/xtoskrnl/includes/ke/affinity.hh b/xtoskrnl/includes/ke/affinity.hh new file mode 100644 index 0000000..f4c2594 --- /dev/null +++ b/xtoskrnl/includes/ke/affinity.hh @@ -0,0 +1,49 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ke/affinity.hh + * DESCRIPTION: XT kernel processor affinity management support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_KE_AFFINITY_HH +#define __XTOSKRNL_KE_AFFINITY_HH + +#include + + +/* Kernel Library */ +namespace KE +{ + class Affinity + { + public: + STATIC XTFASTCALL VOID AtomicSetProcessorAffinity(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber); + STATIC XTFASTCALL VOID CalculateAffinityMapSize(IN ULONG CpuCount, + OUT PULONG RequiredMapSize, + OUT PULONG RequiredBlockCount); + STATIC XTFASTCALL BOOLEAN CheckProcessorAffinity(IN PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber); + STATIC XTFASTCALL VOID ClearAffinityMap(IN OUT PKAFFINITY_MAP AffinityMap); + STATIC XTFASTCALL VOID ClearProcessorAffinity(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber); + + STATIC XTAPI XTSTATUS CopyAffinity(OUT PKAFFINITY_MAP Destination, + IN PKAFFINITY_MAP Source); + STATIC XTAPI XTSTATUS CreateAffinityMap(IN ULONG CpuCount, + OUT PKAFFINITY_MAP* AffinityMap); + STATIC XTAPI VOID DestroyAffinityMap(IN PKAFFINITY_MAP AffinityMap); + STATIC XTAPI ULONG FindNextLeftSetProcessor(IN ULONG ThreadSeed, + IN PKAFFINITY_MAP AffinityMap); + STATIC XTAPI ULONG FindNextRightSetProcessor(IN ULONG ThreadSeed, + IN PKAFFINITY_MAP AffinityMap); + STATIC XTAPI XTSTATUS InitializeAffinityMap(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG BufferSize); + STATIC XTFASTCALL VOID SetAllProcessorsAffinity(IN OUT PKAFFINITY_MAP AffinityMap); + STATIC XTFASTCALL VOID SetProcessorAffinity(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber); + }; +} + +#endif /* __XTOSKRNL_KE_AFFINITY_HH */ diff --git a/xtoskrnl/includes/ke/apc.hh b/xtoskrnl/includes/ke/apc.hh index fc6c0cc..8f82892 100644 --- a/xtoskrnl/includes/ke/apc.hh +++ b/xtoskrnl/includes/ke/apc.hh @@ -18,6 +18,11 @@ namespace KE class Apc { public: + STATIC XTAPI VOID CheckApcDelivery(VOID); + STATIC XTAPI VOID DeliverApc(IN KPROCESSOR_MODE ProcessorMode, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame); + STATIC XTCDECL VOID HandleApcInterrupt(IN PKTRAP_FRAME TrapFrame); STATIC XTAPI VOID InitializeApc(IN PKAPC Apc, IN PKTHREAD Thread, IN KAPC_ENVIRONMENT Environment, diff --git a/xtoskrnl/includes/ke/crash.hh b/xtoskrnl/includes/ke/crash.hh index fa808ce..1cd288b 100644 --- a/xtoskrnl/includes/ke/crash.hh +++ b/xtoskrnl/includes/ke/crash.hh @@ -17,7 +17,16 @@ namespace KE { class Crash { + private: + STATIC PKPROCESSOR_CONTROL_BLOCK FreezeOwner; + STATIC BOOLEAN KernelPanic; + STATIC KRUNLEVEL RunLevel; + public: + STATIC XTAPI VOID FreezeCurrentExecution(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame); + STATIC XTAPI BOOLEAN FreezeExecution(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame); STATIC XTAPI VOID HaltSystem(VOID); STATIC XTAPI VOID Panic(IN ULONG Code); STATIC XTAPI VOID Panic(IN ULONG Code, @@ -25,6 +34,8 @@ namespace KE IN ULONG_PTR Parameter2, IN ULONG_PTR Parameter3, IN ULONG_PTR Parameter4); + STATIC XTAPI BOOLEAN SystemCrashed(VOID); + STATIC XTAPI VOID ThawExecution(IN BOOLEAN Interrupts); }; } diff --git a/xtoskrnl/includes/ke/dispatch.hh b/xtoskrnl/includes/ke/dispatch.hh index 5d65064..6da5a9d 100644 --- a/xtoskrnl/includes/ke/dispatch.hh +++ b/xtoskrnl/includes/ke/dispatch.hh @@ -18,13 +18,25 @@ namespace KE class Dispatcher { public: + STATIC XTAPI VOID EnterIdleLoop(VOID); STATIC XTFASTCALL VOID ExitDispatcher(IN KRUNLEVEL OldRunLevel); + STATIC XTCDECL VOID HandleDispatchInterrupt(IN PKTRAP_FRAME TrapFrame); STATIC XTFASTCALL BOOLEAN SwitchContext(IN PKTHREAD CurrentThread, IN KRUNLEVEL RunLevel); + STATIC XTAPI XTSTATUS WaitForSingleObject(IN PVOID Object, + IN KWAIT_REASON WaitReason, + IN KPROCESSOR_MODE WaitMode, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout); STATIC XTAPI VOID UpdateRunTime(IN PKTRAP_FRAME TrapFrame, IN KRUNLEVEL RunLevel); private: + STATIC XTFASTCALL PLARGE_INTEGER ComputeWaitInterval(IN PLARGE_INTEGER OriginalDueTime, + IN PLARGE_INTEGER PreviousDueTime, + IN OUT PLARGE_INTEGER NewDueTime); + STATIC XTFASTCALL XTSTATUS SatisfyWaitingObject(IN PDISPATCHER_HEADER Object, + IN PKTHREAD Thread); STATIC XTFASTCALL BOOLEAN SwitchThreadContext(IN PKTHREAD CurrentThread, IN BOOLEAN ApcBypass); STATIC XTFASTCALL BOOLEAN SwitchThreadStack(IN PKTHREAD CurrentThread, diff --git a/xtoskrnl/includes/ke/dispobj.hh b/xtoskrnl/includes/ke/dispobj.hh new file mode 100644 index 0000000..569fdf1 --- /dev/null +++ b/xtoskrnl/includes/ke/dispobj.hh @@ -0,0 +1,29 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ke/dispobj.hh + * DESCRIPTION: Kernel Thread Dispatcher Objects + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_KE_DISPOBJ_HH +#define __XTOSKRNL_KE_DISPOBJ_HH + +#include + + +/* Kernel Library */ +namespace KE +{ + class DispatcherObject + { + public: + STATIC XTFASTCALL VOID SatisfyWaitingMutexObject(IN PKMUTEX MutexObject, + IN PKTHREAD Thread); + STATIC XTFASTCALL VOID SatisfyWaitingNonMutexObject(IN PDISPATCHER_HEADER MutexObject); + STATIC XTFASTCALL VOID SatisfyWaitingObject(IN PDISPATCHER_HEADER MutexObject, + IN PKTHREAD Thread); + }; +} + +#endif /* __XTOSKRNL_KE_DISPOBJ_HH */ diff --git a/xtoskrnl/includes/ke/event.hh b/xtoskrnl/includes/ke/event.hh index 74cdd4c..3b61da9 100644 --- a/xtoskrnl/includes/ke/event.hh +++ b/xtoskrnl/includes/ke/event.hh @@ -25,6 +25,8 @@ namespace KE STATIC XTAPI LONG SetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait); + STATIC XTAPI VOID SetEventBoostPriority(IN PKEVENT Event, + IN OUT PKTHREAD* WaitingThread); }; } diff --git a/xtoskrnl/includes/ke/guard.hh b/xtoskrnl/includes/ke/guard.hh index 27bd824..8934050 100644 --- a/xtoskrnl/includes/ke/guard.hh +++ b/xtoskrnl/includes/ke/guard.hh @@ -10,26 +10,168 @@ #define __XTOSKRNL_KE_GUARD_HH #include +#include +#include +#include #include + /* Kernel Library */ namespace KE { + class CriticalRegionGuard + { + private: + BOOLEAN Owned; + PKTHREAD SystemThread; + + public: + CriticalRegionGuard(IN PKTHREAD Thread = NULLPTR, + IN BOOLEAN Acquire = TRUE) + { + Owned = Acquire; + SystemThread = Thread; + if(Owned) + { + if(!SystemThread) + { + SystemThread = KE::Processor::GetCurrentThread(); + } + KE::KThread::EnterCriticalRegion(SystemThread); + } + } + + ~CriticalRegionGuard() + { + if(Owned) + { + KE::KThread::LeaveCriticalRegion(SystemThread); + } + } + + CriticalRegionGuard(const CriticalRegionGuard&) = delete; + CriticalRegionGuard& operator=(const CriticalRegionGuard&) = delete; + }; + + class GuardedRegionGuard + { + private: + BOOLEAN Owned; + PKTHREAD SystemThread; + + public: + GuardedRegionGuard(IN PKTHREAD Thread = NULLPTR, + IN BOOLEAN Acquire = TRUE) + { + Owned = Acquire; + SystemThread = Thread; + if(Owned) + { + if(!SystemThread) + { + SystemThread = KE::Processor::GetCurrentThread(); + } + KE::KThread::EnterGuardedRegion(SystemThread); + } + } + + ~GuardedRegionGuard() + { + if(Owned) + { + KE::KThread::LeaveGuardedRegion(SystemThread); + } + } + + GuardedRegionGuard(const GuardedRegionGuard&) = delete; + GuardedRegionGuard& operator=(const GuardedRegionGuard&) = delete; + }; + + class PushLockExclusiveGuard + { + private: + PKPUSH_LOCK Lock; + BOOLEAN Owned; + + public: + PushLockExclusiveGuard(IN PKPUSH_LOCK PushLock, + IN BOOLEAN Acquire = TRUE) + { + Lock = PushLock; + Owned = Acquire; + if(Owned) + { + KE::PushLock::AcquireExclusivePushLock(Lock); + } + } + + ~PushLockExclusiveGuard() + { + if(Owned) + { + KE::PushLock::ReleaseExclusivePushLock(Lock); + } + } + + PushLockExclusiveGuard(const PushLockExclusiveGuard&) = delete; + PushLockExclusiveGuard& operator=(const PushLockExclusiveGuard&) = delete; + }; + + class PushLockSharedGuard + { + private: + PKPUSH_LOCK Lock; + BOOLEAN Owned; + + public: + PushLockSharedGuard(IN PKPUSH_LOCK PushLock, + IN BOOLEAN Acquire = TRUE) + { + Lock = PushLock; + Owned = Acquire; + if(Owned) + { + KE::PushLock::AcquireSharedPushLock(Lock); + } + } + + ~PushLockSharedGuard() + { + if(Owned) + { + KE::PushLock::ReleaseSharedPushLock(Lock); + } + } + + PushLockSharedGuard(const PushLockSharedGuard&) = delete; + PushLockSharedGuard& operator=(const PushLockSharedGuard&) = delete; + }; + class QueuedSpinLockGuard { private: - KSPIN_LOCK_QUEUE_LEVEL QueuedLockLevel; + KLOCK_QUEUE_HANDLE LockQueueHandle; + PKSPIN_LOCK Lock; + BOOLEAN Owned; public: - QueuedSpinLockGuard(IN OUT KSPIN_LOCK_QUEUE_LEVEL LockLevel) + QueuedSpinLockGuard(IN OUT PKSPIN_LOCK SpinLock, + IN BOOLEAN Acquire = TRUE) { - QueuedLockLevel = LockLevel; - KE::SpinLock::AcquireQueuedSpinLock(QueuedLockLevel); + Lock = SpinLock; + Owned = Acquire; + if(Owned) + { + KE::SpinLock::AcquireQueuedSpinLock(Lock, &LockQueueHandle); + } } ~QueuedSpinLockGuard() { - KE::SpinLock::ReleaseQueuedSpinLock(QueuedLockLevel); + if(Owned) + { + KE::SpinLock::ReleaseQueuedSpinLock(&LockQueueHandle); + } } QueuedSpinLockGuard(const QueuedSpinLockGuard&) = delete; @@ -40,22 +182,61 @@ namespace KE { private: PKSPIN_LOCK Lock; + BOOLEAN Owned; public: - SpinLockGuard(IN OUT PKSPIN_LOCK SpinLock) + SpinLockGuard(IN OUT PKSPIN_LOCK SpinLock, + IN BOOLEAN Acquire = TRUE) { Lock = SpinLock; - KE::SpinLock::AcquireSpinLock(Lock); + Owned = Acquire; + if(Owned) + { + KE::SpinLock::AcquireSpinLock(Lock); + } } ~SpinLockGuard() { - KE::SpinLock::ReleaseSpinLock(Lock); + if(Owned) + { + KE::SpinLock::ReleaseSpinLock(Lock); + } } SpinLockGuard(const SpinLockGuard&) = delete; SpinLockGuard& operator=(const SpinLockGuard&) = delete; }; + + class SystemQueuedSpinLockGuard + { + private: + KSPIN_LOCK_QUEUE_LEVEL QueuedLockLevel; + BOOLEAN Owned; + + public: + SystemQueuedSpinLockGuard(IN OUT KSPIN_LOCK_QUEUE_LEVEL LockLevel, + IN BOOLEAN Acquire = TRUE) + { + QueuedLockLevel = LockLevel; + Owned = Acquire; + if(Owned) + { + KE::SpinLock::AcquireQueuedSpinLock(QueuedLockLevel); + } + } + + ~SystemQueuedSpinLockGuard() + { + if(Owned) + { + KE::SpinLock::ReleaseQueuedSpinLock(QueuedLockLevel); + } + } + + SystemQueuedSpinLockGuard(const SystemQueuedSpinLockGuard&) = delete; + SystemQueuedSpinLockGuard& operator=(const SystemQueuedSpinLockGuard&) = delete; + }; } #endif /* __XTOSKRNL_KE_GUARD_HH */ diff --git a/xtoskrnl/includes/ke/ipi.hh b/xtoskrnl/includes/ke/ipi.hh new file mode 100644 index 0000000..cffcee7 --- /dev/null +++ b/xtoskrnl/includes/ke/ipi.hh @@ -0,0 +1,31 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ke/ipi.hh + * DESCRIPTION: Interprocessor interrupt support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_KE_IPI_HH +#define __XTOSKRNL_KE_IPI_HH + +#include + + +/* Kernel Library */ +namespace KE +{ + class Ipi + { + public: + STATIC XTCDECL VOID HandleIpiInterrupt(IN PKTRAP_FRAME TrapFrame); + STATIC XTAPI BOOLEAN HandleIpiService(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame); + STATIC XTAPI VOID SendBroadcastIpi(IN ULONG Request, + IN BOOLEAN Self); + STATIC XTAPI VOID SendIpi(IN ULONG Request, + IN PKAFFINITY_MAP TargetSet); + }; +} + +#endif /* __XTOSKRNL_KE_IPI_HH */ diff --git a/xtoskrnl/includes/ke/kprocess.hh b/xtoskrnl/includes/ke/kprocess.hh index ae7c370..4bff84f 100644 --- a/xtoskrnl/includes/ke/kprocess.hh +++ b/xtoskrnl/includes/ke/kprocess.hh @@ -21,10 +21,13 @@ namespace KE STATIC EPROCESS InitialProcess; public: + STATIC XTAPI PKPROCESS GetIdleProcess(VOID); STATIC XTAPI PEPROCESS GetInitialProcess(VOID); + STATIC XTAPI XTSTATUS InitializeIdleProcess(IN OUT PKPROCESS IdleProcess, + IN PULONG_PTR DirectoryTable); STATIC XTAPI VOID InitializeProcess(IN OUT PKPROCESS Process, IN KPRIORITY Priority, - IN KAFFINITY Affinity, + IN PKAFFINITY_MAP AffinityMap, IN PULONG_PTR DirectoryTable, IN BOOLEAN Alignment); }; diff --git a/xtoskrnl/includes/ke/krnlinit.hh b/xtoskrnl/includes/ke/krnlinit.hh index 351890f..0984ff0 100644 --- a/xtoskrnl/includes/ke/krnlinit.hh +++ b/xtoskrnl/includes/ke/krnlinit.hh @@ -24,6 +24,7 @@ namespace KE private: STATIC XTAPI VOID BootstrapKernel(VOID); + STATIC XTAPI VOID InitializeInterruptHandlers(VOID); STATIC XTAPI VOID InitializeKernel(VOID); }; } diff --git a/xtoskrnl/includes/ke/kthread.hh b/xtoskrnl/includes/ke/kthread.hh index 288ce99..2e291ab 100644 --- a/xtoskrnl/includes/ke/kthread.hh +++ b/xtoskrnl/includes/ke/kthread.hh @@ -21,7 +21,16 @@ namespace KE STATIC ETHREAD InitialThread; public: + STATIC XTAPI VOID AttachThread(IN PKTHREAD Thread); + STATIC XTFASTCALL VOID EnterCriticalRegion(); + STATIC XTFASTCALL VOID EnterCriticalRegion(IN PKTHREAD Thread); + STATIC XTFASTCALL VOID EnterGuardedRegion(); + STATIC XTFASTCALL VOID EnterGuardedRegion(IN PKTHREAD Thread); STATIC XTAPI PETHREAD GetInitialThread(VOID); + STATIC XTAPI XTSTATUS InitializeIdleThread(IN PKPROCESS IdleProcess, + IN OUT PKTHREAD IdleThread, + IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PVOID Stack); STATIC XTAPI XTSTATUS InitializeThread(IN PKPROCESS Process, IN OUT PKTHREAD Thread, IN PKSYSTEM_ROUTINE SystemRoutine, @@ -30,15 +39,20 @@ namespace KE IN PCONTEXT Context, IN PVOID EnvironmentBlock, IN PVOID Stack, - IN BOOLEAN StartThread); - STATIC XTAPI VOID StartThread(IN PKTHREAD Thread); + IN BOOLEAN AttachToProcess); + STATIC XTFASTCALL VOID LeaveCriticalRegion(); + STATIC XTFASTCALL VOID LeaveCriticalRegion(IN PKTHREAD Thread); + STATIC XTFASTCALL VOID LeaveGuardedRegion(); + STATIC XTFASTCALL VOID LeaveGuardedRegion(IN PKTHREAD Thread); private: + STATIC XTAPI VOID HandleSystemThreadExit(VOID); STATIC XTAPI VOID InitializeThreadContext(IN PKTHREAD Thread, IN PKSYSTEM_ROUTINE SystemRoutine, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, IN PCONTEXT ContextRecord); + STATIC XTAPI VOID RunThread(VOID); STATIC XTAPI VOID SuspendNop(IN PKAPC Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, @@ -48,6 +62,7 @@ namespace KE STATIC XTAPI VOID SuspendThread(IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2); + STATIC XTAPI VOID SwitchToUserMode(VOID); }; } diff --git a/xtoskrnl/includes/ke/proc.hh b/xtoskrnl/includes/ke/proc.hh index 082c3d0..8e5eafc 100644 --- a/xtoskrnl/includes/ke/proc.hh +++ b/xtoskrnl/includes/ke/proc.hh @@ -26,12 +26,25 @@ namespace KE STATIC XTAPI PKPROCESSOR_CONTROL_BLOCK GetCurrentProcessorControlBlock(VOID); STATIC XTAPI ULONG GetCurrentProcessorNumber(VOID); STATIC XTAPI PKTHREAD GetCurrentThread(VOID); + STATIC XTAPI ULONG GetInstalledCpus(VOID); STATIC XTAPI PKPROCESSOR_BLOCK GetProcessorBlock(IN ULONG CpuNumber); STATIC XTAPI XTSTATUS InitializeProcessorBlocks(); STATIC XTAPI VOID RegisterHardwareId(IN ULONG HardwareId); STATIC XTAPI VOID RegisterProcessorBlock(ULONG CpuNumber, PKPROCESSOR_BLOCK ProcessorBlock); - STATIC XTAPI VOID SaveProcessorState(OUT PKPROCESSOR_STATE CpuState); + STATIC XTAPI VOID RestoreProcessorContext(IN OUT PKTRAP_FRAME TrapFrame, + IN OUT PKEXCEPTION_FRAME ExceptionFrame, + IN PCONTEXT ContextFrame, + IN ULONG ContextFlags); + STATIC XTAPI VOID RestoreProcessorControlState(IN PKPROCESSOR_STATE CpuState); + STATIC XTAPI VOID RestoreProcessorState(OUT PKTRAP_FRAME TrapFrame, + OUT PKEXCEPTION_FRAME ExceptionFrame); + STATIC XTAPI VOID SaveProcessorContext(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PCONTEXT ContextRecord); + STATIC XTAPI VOID SaveProcessorControlState(OUT PKPROCESSOR_STATE CpuState); + STATIC XTAPI VOID SaveProcessorState(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame); }; } diff --git a/xtoskrnl/includes/ke/pushlock.hh b/xtoskrnl/includes/ke/pushlock.hh new file mode 100644 index 0000000..91ed987 --- /dev/null +++ b/xtoskrnl/includes/ke/pushlock.hh @@ -0,0 +1,48 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ke/pushlock.hh + * DESCRIPTION: XT Kernel Push Lock support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_KE_PUSHLOCK_HH +#define __XTOSKRNL_KE_PUSHLOCK_HH + +#include + + +/* Kernel Library */ +namespace KE +{ + class PushLock + { + public: + STATIC XTFASTCALL VOID AcquireExclusivePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID AcquireSharedPushLock(PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID AcquireWaitExclusivePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID AcquireWaitSharedPushLock(IN OUT PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID BlockPushLock(IN PKPUSH_LOCK PushLock, + IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock); + STATIC XTFASTCALL BOOLEAN ConvertSharedPushLockToExclusive(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID InitializePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID ReleaseExclusivePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID ReleasePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID ReleaseSharedPushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID ReleaseWaitExclusivePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID ReleaseWaitSharedPushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID ReleaseWaitPushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL BOOLEAN TryAcquireExclusivePushLock(PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID TryWakePushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID UnblockPushLock(IN PKPUSH_LOCK PushLock, + IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock); + STATIC XTFASTCALL VOID WaitOnPushLock(IN PKPUSH_LOCK PushLock); + STATIC XTFASTCALL VOID WakePushLockWaiters(IN PKPUSH_LOCK PushLock, IN KPUSH_LOCK OldState); + + private: + STATIC XTINLINE VOID OptimizePushLockList(IN PKPUSH_LOCK PushLock, IN KPUSH_LOCK OldValue); + STATIC XTINLINE VOID SpinPushLock(IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock); + }; +} + +#endif /* __XTOSKRNL_KE_PUSHLOCK_HH */ diff --git a/xtoskrnl/includes/ke/runlevel.hh b/xtoskrnl/includes/ke/runlevel.hh index 82685c9..ab4251d 100644 --- a/xtoskrnl/includes/ke/runlevel.hh +++ b/xtoskrnl/includes/ke/runlevel.hh @@ -27,17 +27,26 @@ namespace KE { private: KRUNLEVEL PreviousRunLevel; + BOOLEAN Switched; public: - LowerRunLevel(KRUNLEVEL RunLevel) + LowerRunLevel(IN KRUNLEVEL RunLevel, + IN BOOLEAN ChangeLevel = TRUE) { PreviousRunLevel = KE::RunLevel::GetCurrentRunLevel(); - KE::RunLevel::LowerRunLevel(RunLevel); + Switched = ChangeLevel; + if(Switched) + { + KE::RunLevel::LowerRunLevel(RunLevel); + } } ~LowerRunLevel() { - KE::RunLevel::RaiseRunLevel(PreviousRunLevel); + if(Switched) + { + KE::RunLevel::RaiseRunLevel(PreviousRunLevel); + } } LowerRunLevel(const LowerRunLevel&) = delete; @@ -48,17 +57,26 @@ namespace KE { private: KRUNLEVEL PreviousRunLevel; + BOOLEAN Switched; public: - RaiseRunLevel(KRUNLEVEL RunLevel) + RaiseRunLevel(IN KRUNLEVEL RunLevel, + IN BOOLEAN ChangeLevel = TRUE) { PreviousRunLevel = KE::RunLevel::GetCurrentRunLevel(); - KE::RunLevel::RaiseRunLevel(RunLevel); + Switched = ChangeLevel; + if(Switched) + { + KE::RunLevel::RaiseRunLevel(RunLevel); + } } ~RaiseRunLevel() { - KE::RunLevel::LowerRunLevel(PreviousRunLevel); + if(Switched) + { + KE::RunLevel::LowerRunLevel(PreviousRunLevel); + } } RaiseRunLevel(const RaiseRunLevel&) = delete; diff --git a/xtoskrnl/includes/ke/schedule.hh b/xtoskrnl/includes/ke/schedule.hh new file mode 100644 index 0000000..fbbdf8d --- /dev/null +++ b/xtoskrnl/includes/ke/schedule.hh @@ -0,0 +1,30 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ke/schedule.hh + * DESCRIPTION: XT Kernel Thread Scheduler + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_KE_SCHEDULE_HH +#define __XTOSKRNL_KE_SCHEDULE_HH + +#include + + +/* Kernel Library */ +namespace KE +{ + class Scheduler + { + public: + STATIC XTFASTCALL VOID InsertDeferredReadyList(IN PKTHREAD Thread); + STATIC XTAPI VOID ProcessQuantumEnd(VOID); + STATIC XTAPI VOID ProcessReadyThread(IN PKTHREAD Thread); + STATIC XTFASTCALL VOID QueueReadyThread(IN PKTHREAD Thread, + IN PKPROCESSOR_CONTROL_BLOCK Prcb); + STATIC XTAPI VOID ReadyThread(IN PKTHREAD Thread); + }; +} + +#endif /* __XTOSKRNL_KE_SCHEDULE_HH */ diff --git a/xtoskrnl/includes/ke/spinlock.hh b/xtoskrnl/includes/ke/spinlock.hh index c510ae8..bfe1d1b 100644 --- a/xtoskrnl/includes/ke/spinlock.hh +++ b/xtoskrnl/includes/ke/spinlock.hh @@ -36,13 +36,20 @@ namespace KE public: STATIC XTFASTCALL VOID AcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel); + STATIC XTFASTCALL VOID AcquireQueuedSpinLock(IN PKSPIN_LOCK SpinLock, + IN PKLOCK_QUEUE_HANDLE LockQueueHandle); STATIC XTFASTCALL VOID AcquireSpinLock(IN OUT PKSPIN_LOCK SpinLock); STATIC XTAPI VOID InitializeAllLocks(); STATIC XTAPI VOID InitializeLockQueues(); STATIC XTAPI VOID InitializeSpinLock(IN PKSPIN_LOCK SpinLock); STATIC XTFASTCALL VOID ReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel); + STATIC XTFASTCALL VOID ReleaseQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockQueueHandle); STATIC XTFASTCALL VOID ReleaseSpinLock(IN OUT PKSPIN_LOCK SpinLock); STATIC XTFASTCALL BOOLEAN TestSpinLock(IN PKSPIN_LOCK SpinLock); + + private: + STATIC XTFASTCALL VOID AcquireQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue); + STATIC XTFASTCALL VOID ReleaseQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue); }; } diff --git a/xtoskrnl/includes/ke/sysserv.hh b/xtoskrnl/includes/ke/sysserv.hh new file mode 100644 index 0000000..442580b --- /dev/null +++ b/xtoskrnl/includes/ke/sysserv.hh @@ -0,0 +1,25 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ke/sysserv.hh + * DESCRIPTION: System Services Descriptor Table + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_KE_SYSSERV_HH +#define __XTOSKRNL_KE_SYSSERV_HH + +#include + + +/* Kernel Library */ +namespace KE +{ + class SystemServices + { + public: + STATIC XTAPI PKSERVICE_DESCRIPTOR_TABLE GetSystemServicesDescriptorTable(VOID); + }; +} + +#endif /* __XTOSKRNL_KE_SYSSERV_HH */ diff --git a/xtoskrnl/includes/ke/systime.hh b/xtoskrnl/includes/ke/systime.hh index a804331..abac170 100644 --- a/xtoskrnl/includes/ke/systime.hh +++ b/xtoskrnl/includes/ke/systime.hh @@ -25,6 +25,7 @@ namespace KE STATIC ULONG TimeAdjustment; public: + STATIC XTAPI VOID GetInterruptTime(OUT PLARGE_INTEGER InterruptTime); STATIC XTAPI VOID GetSystemTime(OUT PLARGE_INTEGER SystemTime); STATIC XTAPI VOID SetSystemTime(IN PLARGE_INTEGER NewTime, OUT PLARGE_INTEGER OldTime, diff --git a/xtoskrnl/includes/ke/timer.hh b/xtoskrnl/includes/ke/timer.hh index 55a5b6f..85647a4 100644 --- a/xtoskrnl/includes/ke/timer.hh +++ b/xtoskrnl/includes/ke/timer.hh @@ -17,6 +17,9 @@ namespace KE { class Timer { + private: + STATIC LIST_ENTRY TimerTableListHead[KTIMER_TABLE_SIZE]; + public: STATIC XTAPI BOOLEAN CancelTimer(IN PKTIMER Timer); STATIC XTAPI VOID ClearTimer(IN PKTIMER Timer); @@ -28,6 +31,9 @@ namespace KE IN LARGE_INTEGER DueTime, IN LONG Period, IN PKDPC Dpc); + STATIC XTAPI VOID VerifySystemTimerExpiration(IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PKTRAP_FRAME TrapFrame, + IN LARGE_INTEGER Time); private: STATIC XTAPI VOID RemoveTimer(IN OUT PKTIMER Timer); diff --git a/xtoskrnl/includes/mm.hh b/xtoskrnl/includes/mm.hh index 1e3e841..1d41839 100644 --- a/xtoskrnl/includes/mm.hh +++ b/xtoskrnl/includes/mm.hh @@ -24,5 +24,8 @@ #include #include #include +#include +#include +#include #endif /* __XTOSKRNL_MM_HH */ diff --git a/xtoskrnl/includes/mm/amd64/pagemap.hh b/xtoskrnl/includes/mm/amd64/pagemap.hh index 59e91b8..e62e5c9 100644 --- a/xtoskrnl/includes/mm/amd64/pagemap.hh +++ b/xtoskrnl/includes/mm/amd64/pagemap.hh @@ -52,6 +52,7 @@ namespace MM XTAPI PMMPXE GetPxeAddress(IN PVOID Address); XTAPI ULONG GetPxeOffset(IN PVOID Address); VIRTUAL XTAPI PVOID GetPxeVirtualAddress(IN PMMPXE PxePointer) = 0; + VIRTUAL ULONG_PTR GetUserProbeAddress(VOID) = 0; XTAPI BOOLEAN GetXpaStatus(); VIRTUAL XTAPI VOID InitializePageMapInfo(VOID) = 0; XTAPI BOOLEAN PteValid(IN PMMPTE PtePointer); @@ -80,6 +81,7 @@ namespace MM XTAPI PVOID GetPpeVirtualAddress(IN PMMPPE PpePointer); XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer); XTAPI PVOID GetPxeVirtualAddress(IN PMMPXE PxePointer); + XTAPI ULONG_PTR GetUserProbeAddress(VOID); XTAPI VOID InitializePageMapInfo(VOID); }; @@ -90,6 +92,7 @@ namespace MM XTAPI PVOID GetPpeVirtualAddress(IN PMMPPE PpePointer); XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer); XTAPI PVOID GetPxeVirtualAddress(IN PMMPXE PxePointer); + XTAPI ULONG_PTR GetUserProbeAddress(VOID); XTAPI VOID InitializePageMapInfo(VOID); }; } diff --git a/xtoskrnl/includes/mm/amd64/paging.hh b/xtoskrnl/includes/mm/amd64/paging.hh index 6f927bb..e1be0d9 100644 --- a/xtoskrnl/includes/mm/amd64/paging.hh +++ b/xtoskrnl/includes/mm/amd64/paging.hh @@ -49,6 +49,7 @@ namespace MM STATIC XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer); STATIC XTAPI PMMPXE GetPxeAddress(IN PVOID Address); STATIC XTAPI PVOID GetPxeVirtualAddress(IN PMMPXE PxePointer); + STATIC XTAPI ULONG_PTR GetUserProbeAddress(VOID); STATIC XTAPI BOOLEAN GetXpaStatus(VOID); STATIC XTAPI VOID InitializePageMapSupport(VOID); STATIC XTAPI XTSTATUS MapVirtualAddress(IN PVOID VirtualAddress, diff --git a/xtoskrnl/includes/mm/hlpool.hh b/xtoskrnl/includes/mm/hlpool.hh index 41daac4..a4bb43d 100644 --- a/xtoskrnl/includes/mm/hlpool.hh +++ b/xtoskrnl/includes/mm/hlpool.hh @@ -20,6 +20,8 @@ namespace MM private: STATIC LOADER_MEMORY_DESCRIPTOR HardwareAllocationDescriptors[MM_HARDWARE_ALLOCATION_DESCRIPTORS]; STATIC PVOID HardwareHeapStart; + STATIC PHYSICAL_ADDRESS LowMemoryPhysicalAddress; + STATIC PVOID LowMemoryVirtualAddress; STATIC ULONG UsedHardwareAllocationDescriptors; public: @@ -27,12 +29,19 @@ namespace MM IN BOOLEAN Aligned, IN ULONGLONG MaximumAddress, OUT PPHYSICAL_ADDRESS Buffer); - STATIC XTAPI XTSTATUS AllocateRealModeMemory(IN PFN_NUMBER PageCount, - OUT PVOID *MemoryAddress); + STATIC XTAPI XTSTATUS AllocateLowMemory(OUT PPHYSICAL_ADDRESS PhysicalAddress, + OUT PVOID *VirtualAddress); + STATIC XTAPI ULONG CalculateRealModeAllocationPages(IN ULONG TrampolineCodeSize); + STATIC XTAPI XTSTATUS FreeHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress, + IN PFN_NUMBER PageCount); + STATIC XTAPI XTSTATUS FreeRealModeMemory(IN PVOID VirtualAddress, + IN PFN_NUMBER PageCount); STATIC XTAPI XTSTATUS MapHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress, IN PFN_NUMBER PageCount, IN BOOLEAN FlushTlb, OUT PVOID *VirtualAddress); + STATIC XTAPI XTSTATUS MapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG Size); STATIC XTAPI VOID MarkHardwareMemoryWriteThrough(IN PVOID VirtualAddress, IN PFN_NUMBER PageCount); STATIC XTAPI VOID RemapHardwareMemory(IN PVOID VirtualAddress, @@ -41,6 +50,8 @@ namespace MM STATIC XTAPI XTSTATUS UnmapHardwareMemory(IN PVOID VirtualAddress, IN PFN_NUMBER PageCount, IN BOOLEAN FlushTlb); + STATIC XTAPI VOID UnmapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG Size); }; } diff --git a/xtoskrnl/includes/mm/i686/pagemap.hh b/xtoskrnl/includes/mm/i686/pagemap.hh index a9edba9..989fc99 100644 --- a/xtoskrnl/includes/mm/i686/pagemap.hh +++ b/xtoskrnl/includes/mm/i686/pagemap.hh @@ -46,6 +46,7 @@ namespace MM VIRTUAL XTAPI ULONG GetPteSoftwarePrototype(IN PMMPTE PtePointer) = 0; VIRTUAL XTAPI ULONG GetPteSoftwareTransition(IN PMMPTE PtePointer) = 0; VIRTUAL XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer) = 0; + XTAPI ULONG_PTR GetUserProbeAddress(VOID); XTAPI BOOLEAN GetXpaStatus(); VIRTUAL XTAPI VOID InitializePageMapInfo(VOID) = 0; VIRTUAL XTAPI BOOLEAN PteValid(IN PMMPTE PtePointer) = 0; diff --git a/xtoskrnl/includes/mm/i686/paging.hh b/xtoskrnl/includes/mm/i686/paging.hh index 3924111..9ac8f8f 100644 --- a/xtoskrnl/includes/mm/i686/paging.hh +++ b/xtoskrnl/includes/mm/i686/paging.hh @@ -45,6 +45,7 @@ namespace MM STATIC XTAPI ULONG GetPteSoftwarePrototype(IN PMMPTE PtePointer); STATIC XTAPI ULONG GetPteSoftwareTransition(IN PMMPTE PtePointer); STATIC XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer); + STATIC XTAPI ULONG_PTR GetUserProbeAddress(VOID); STATIC XTAPI BOOLEAN GetXpaStatus(VOID); STATIC XTAPI VOID InitializePageMapSupport(VOID); STATIC XTAPI XTSTATUS MapVirtualAddress(IN PVOID VirtualAddress, diff --git a/xtoskrnl/includes/mm/probe.hh b/xtoskrnl/includes/mm/probe.hh new file mode 100644 index 0000000..f4e9875 --- /dev/null +++ b/xtoskrnl/includes/mm/probe.hh @@ -0,0 +1,44 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/mm/probe.hh + * DESCRIPTION: Memory Manager read/write probe support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_MM_PROBE_HH +#define __XTOSKRNL_MM_PROBE_HH + +#include + + +/* Memory Manager */ +namespace MM +{ + class Probe + { + public: + STATIC XTAPI VOID ProbeForRead(IN CONST PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment); + STATIC XTAPI VOID ProbeForReadArray(IN CONST PVOID Array, + IN ULONG ItemSize, + IN ULONG ItemCount, + IN ULONG Alignment); + STATIC XTAPI VOID ProbeForReadStructure(IN CONST PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment); + STATIC XTAPI VOID ProbeForWrite(IN PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment); + STATIC XTAPI VOID ProbeForWriteArray(IN OUT PVOID Array, + IN ULONG ItemSize, + IN ULONG ItemCount, + IN ULONG Alignment); + STATIC XTAPI VOID ProbeForWriteStructure(IN PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment); + }; +} + +#endif /* __XTOSKRNL_MM_PROBE_HH */ diff --git a/xtoskrnl/includes/mm/quota.hh b/xtoskrnl/includes/mm/quota.hh new file mode 100644 index 0000000..8579833 --- /dev/null +++ b/xtoskrnl/includes/mm/quota.hh @@ -0,0 +1,33 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/mm/quota.hh + * DESCRIPTION: Memory Manager Quota support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_MM_QUOTA_HH +#define __XTOSKRNL_MM_QUOTA_HH + +#include + + +/* Memory Manager */ +namespace MM +{ + class Quota + { + private: + STATIC SIZE_T PagedPoolQuota; + STATIC SIZE_T NonPagedPoolQuota; + + public: + STATIC XTAPI BOOLEAN RaisePoolQuota(IN MMPOOL_TYPE PoolType, + IN SIZE_T CurrentQuotaLimit, + OUT PSIZE_T NewQuotaLimit); + STATIC XTAPI VOID ReturnPoolQuota(IN MMPOOL_TYPE PoolType, + IN SIZE_T ReturnedQuota); + }; +} + +#endif /* __XTOSKRNL_MM_QUOTA_HH */ diff --git a/xtoskrnl/includes/mm/tags.hh b/xtoskrnl/includes/mm/tags.hh new file mode 100644 index 0000000..937784b --- /dev/null +++ b/xtoskrnl/includes/mm/tags.hh @@ -0,0 +1,32 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/mm/tags.hh + * DESCRIPTION: Memory Manager allocation tags + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_MM_TAGS_HH +#define __XTOSKRNL_MM_TAGS_HH + +#include + + +/* Allocation tags */ +#define TAG_HL_FRAMEBUFFER SIGNATURE32('H', 'L', 'F', 'B') +#define TAG_MM_BIG_ALLOC SIGNATURE32('B', 'I', 'G', 'A') +#define TAG_MM_MEMORY_MGR SIGNATURE32('M', 'M', 'G', 'R') +#define TAG_MM_OVERFLOW SIGNATURE32('O', 'V', 'F', 'L') +#define TAG_MM_MEMORY_POOL SIGNATURE32('P', 'O', 'O', 'L') +#define TAG_MM_NONE SIGNATURE32('N', 'O', 'N', 'E') +#define TAG_OB_CREATE_INFO SIGNATURE32('O', 'B', 'C', 'I') +#define TAG_OB_DIRECTORY SIGNATURE32('O', 'B', 'D', 'I') +#define TAG_OB_MEMORY_POOL SIGNATURE32('O', 'B', 'J', 'M') +#define TAG_OB_NAME SIGNATURE32('O', 'B', 'N', 'M') +#define TAG_OB_OBJECT_TABLE SIGNATURE32('O', 'B', 'T', 'B') +#define TAG_OB_OBJECT_TYPE SIGNATURE32('O', 'B', 'J', 'T') +#define TAG_PS_QUOTA_BLOCK SIGNATURE32('P', 'S', 'Q', 'B') +#define TAG_SE_DESCRIPTOR SIGNATURE32('S', 'E', 'S', 'D') +#define TAG_SE_PRIVILEGE_ARRAY SIGNATURE32('S', 'E', 'P', 'A') + +#endif /* __XTOSKRNL_MM_TAGS_HH */ diff --git a/xtoskrnl/includes/ob.hh b/xtoskrnl/includes/ob.hh new file mode 100644 index 0000000..3e13660 --- /dev/null +++ b/xtoskrnl/includes/ob.hh @@ -0,0 +1,23 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob.hh + * DESCRIPTION: Object Manager + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_HH +#define __XTOSKRNL_OB_HH + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __XTOSKRNL_OB_HH */ diff --git a/xtoskrnl/includes/ob/devmap.hh b/xtoskrnl/includes/ob/devmap.hh new file mode 100644 index 0000000..3f59e41 --- /dev/null +++ b/xtoskrnl/includes/ob/devmap.hh @@ -0,0 +1,34 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/devmap.hh + * DESCRIPTION: Object Manager Device Map + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_DEVMAP_HH +#define __XTOSKRNL_OB_DEVMAP_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class DeviceMap + { + private: + STATIC KPUSH_LOCK DeviceMapLock; + STATIC PDEVICE_MAP SystemDeviceMap; + STATIC BOOLEAN UniqueDeviceMaps; + + public: + STATIC XTAPI POBJECT_DIRECTORY GetGlobalDevicesDirectory(IN POBJECT_DIRECTORY Directory); + STATIC XTAPI BOOLEAN GetUniqueDeviceMaps(VOID); + STATIC VOID InheritDeviceMap(IN PEPROCESS NewProcess, + IN PEPROCESS ParentProcess); + STATIC XTAPI XTSTATUS InitializeDeviceMap(VOID); + }; +} + +#endif /* __XTOSKRNL_OB_DEVMAP_HH */ diff --git a/xtoskrnl/includes/ob/handle.hh b/xtoskrnl/includes/ob/handle.hh new file mode 100644 index 0000000..d3148a8 --- /dev/null +++ b/xtoskrnl/includes/ob/handle.hh @@ -0,0 +1,27 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/handle.hh + * DESCRIPTION: Object Manager Handle Management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_HANDLE_HH +#define __XTOSKRNL_OB_HANDLE_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class Handle + { + public: + STATIC XTFASTCALL HANDLE DecodeKernelHandle(IN HANDLE Handle); + STATIC XTFASTCALL HANDLE EncodeKernelHandle(IN HANDLE Handle); + STATIC XTFASTCALL ULONG GetHandleAttributes(IN PHANDLE_TABLE_ENTRY HandleTableEntry); + }; +} + +#endif /* __XTOSKRNL_OB_HANDLE_HH */ diff --git a/xtoskrnl/includes/ob/hndltlb.hh b/xtoskrnl/includes/ob/hndltlb.hh new file mode 100644 index 0000000..1cfd078 --- /dev/null +++ b/xtoskrnl/includes/ob/hndltlb.hh @@ -0,0 +1,106 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/hndltlb.hh + * DESCRIPTION: Object Manager Handle Table Management Interface + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_HNDLTLB_HH +#define __XTOSKRNL_OB_HNDLTLB_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class HandleTable + { + private: + STATIC KPUSH_LOCK HandleTableListLock; + STATIC LIST_ENTRY HandleTableListHead; + + public: + STATIC XTAPI BOOLEAN ChangeHandle(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN POB_CHANGE_HANDLE_ROUTINE ChangeRoutine, + IN ULONG_PTR Parameter); + STATIC XTAPI HANDLE CreateHandle(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry); + STATIC XTAPI PHANDLE_TABLE CreateHandleTable(IN PEPROCESS Process); + STATIC XTAPI BOOLEAN DestroyHandle(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN PHANDLE_TABLE_ENTRY HandleTableEntry); + STATIC XTAPI VOID DestroyHandleTable(IN PHANDLE_TABLE HandleTable, + IN POB_DESTROY_HANDLE_ROUTINE DestroyHandleProcedure); + STATIC XTAPI PHANDLE_TABLE DuplicateHandleTable(IN PEPROCESS Process, + IN PHANDLE_TABLE OldHandleTable, + IN POB_DUPLICATE_HANDLE_ROUTINE DupHandleProcedure, + IN ULONG_PTR Mask); + STATIC XTAPI BOOLEAN EnumerateHandleTable(IN PHANDLE_TABLE HandleTable, + IN POB_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure, + IN PVOID EnumParameter, + OUT PHANDLE Handle); + STATIC XTAPI PHANDLE_TABLE_ENTRY_INFO GetHandleInformation(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN BOOLEAN Locked); + STATIC XTAPI VOID InitializeHandleTable(VOID); + STATIC XTAPI BOOLEAN LockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry); + STATIC XTAPI PHANDLE_TABLE_ENTRY MapHandleToPointer(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle); + STATIC XTAPI PHANDLE_TABLE_ENTRY MapHandleToPointer(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN KPROCESSOR_MODE PreviousMode); + STATIC XTAPI VOID RemoveHandleTable(IN PHANDLE_TABLE HandleTable); + STATIC XTAPI XTSTATUS SetHandleInformation(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN PHANDLE_TABLE_ENTRY_INFO EntryInfo, + IN BOOLEAN EntryLocked); + STATIC XTAPI XTSTATUS SnapshotHandleTables(IN POB_SNAPSHOT_HANDLE_ENTRY SnapshotHandleEntry, + IN OUT PSYSTEM_HANDLE_INFORMATION HandleInformation, + IN ULONG Length, + IN OUT PULONG RequiredLength); + STATIC XTAPI XTSTATUS SnapshotHandleTables(IN POB_SNAPSHOT_HANDLE_ENTRY_EX SnapshotHandleEntry, + IN OUT PSYSTEM_HANDLE_INFORMATION_EX HandleInformation, + IN ULONG Length, + IN OUT PULONG RequiredLength); + STATIC XTAPI VOID SweepHandleTable(IN PHANDLE_TABLE HandleTable, + IN POB_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure, + IN PVOID EnumParameter); + STATIC XTAPI VOID UnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry); + + private: + STATIC XTAPI PHANDLE_TABLE AllocateHandleTable(IN PEPROCESS Process, + IN BOOLEAN DoInit); + STATIC XTAPI PHANDLE_TABLE_ENTRY AllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, + OUT POBJECT_HANDLE Handle); + STATIC XTAPI BOOLEAN AllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN BOOLEAN DoInit); + STATIC XTAPI PHANDLE_TABLE_ENTRY AllocateLowLevelTable(IN PHANDLE_TABLE HandleTable, + IN BOOLEAN DoInit); + STATIC XTAPI PHANDLE_TABLE_ENTRY *AllocateMediumLevelTable(IN PHANDLE_TABLE HandleTable, + IN BOOLEAN DoInit, + OUT PHANDLE_TABLE_ENTRY *NewLowLevel); + STATIC XTAPI PVOID AllocateTableMemory(IN PEPROCESS QuotaProcess, + IN SIZE_T NumberOfBytes, + IN BOOLEAN ZeroMemory); + STATIC XTAPI VOID FreeHandleTable(IN PHANDLE_TABLE HandleTable); + STATIC XTAPI VOID FreeHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN OBJECT_HANDLE Handle, + IN PHANDLE_TABLE_ENTRY HandleTableEntry); + STATIC XTAPI VOID FreeLowLevelTable(IN PEPROCESS QuotaProcess, + IN PHANDLE_TABLE_ENTRY TableLevel1); + STATIC XTAPI VOID FreeTableMemory(IN PEPROCESS QuotaProcess, + IN PVOID PoolMemory, + IN SIZE_T NumberOfBytes); + STATIC XTAPI PHANDLE_TABLE_ENTRY LookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN OBJECT_HANDLE Handle); + STATIC XTAPI ULONG MoveFreeHandles(IN PHANDLE_TABLE HandleTable); + STATIC XTINLINE BOOLEAN ValidateObjectEntry(IN PHANDLE_TABLE_ENTRY Entry); + }; +} + +#endif /* __XTOSKRNL_OB_HNDLTLB_HH */ diff --git a/xtoskrnl/includes/ob/lifecycl.hh b/xtoskrnl/includes/ob/lifecycl.hh new file mode 100644 index 0000000..bacfadd --- /dev/null +++ b/xtoskrnl/includes/ob/lifecycl.hh @@ -0,0 +1,93 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/lifecycl.hh + * DESCRIPTION: Object Manager Lifecycle Management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_LIFECYCL_HH +#define __XTOSKRNL_OB_LIFECYCL_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class LifeCycle + { + private: + STATIC PHANDLE_TABLE KernelHandleTable; + STATIC PVOID RemoveObjectList; + STATIC WORK_QUEUE_ITEM RemoveObjectWorkItem; + + public: + STATIC XTAPI XTSTATUS AllocateObject(IN POBJECT_CREATE_INFORMATION CreateInfo, + IN KPROCESSOR_MODE ProcessorMode, + IN POBJECT_TYPE ObjectType, + IN PUNICODE_STRING ObjectName, + IN ULONG ObjectBodySize, + OUT POBJECT_HEADER *ReturnedObjectHeader); + STATIC XTAPI XTSTATUS CreateObject(IN KPROCESSOR_MODE ProcessorMode, + IN POBJECT_TYPE ObjectType, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN KPROCESSOR_MODE OwnerProcessorMode, + IN OUT PVOID ParseContext, + IN ULONG ObjectBodySize, + IN ULONG PagedPoolCharge, + IN ULONG NonPagedPoolCharge, + OUT PVOID *Object); + STATIC XTAPI VOID DeferObjectDeletion(IN POBJECT_HEADER ObjectHeader); + STATIC XTFASTCALL LONG_PTR DereferenceObject(IN PVOID Object); + STATIC XTFASTCALL LONG_PTR DereferenceObject(IN PVOID Object, + IN ULONG Count); + STATIC XTFASTCALL LONG_PTR DereferenceObjectDeferDelete(IN PVOID Object); + STATIC XTFASTCALL VOID DereferenceObjectNameInformation(IN POBJECT_HEADER_NAME_INFO NameInfo); + STATIC XTFASTCALL POBJECT_HEADER_CREATOR_INFO GetObjectCreatorInformation(IN POBJECT_HEADER ObjectHeader); + STATIC XTFASTCALL POBJECT_HEADER_NAME_INFO GetObjectNameInformation(IN POBJECT_HEADER ObjectHeader); + STATIC XTAPI VOID InitializeObjectLifeCycle(VOID); + STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object); + STATIC XTFASTCALL LONG_PTR ReferenceObject(IN PVOID Object, + IN ULONG Count); + STATIC XTAPI XTSTATUS ReferenceObject(IN HANDLE Handle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode, + OUT PVOID *Object, + OUT POBJECT_HANDLE_INFORMATION HandleInformation); + STATIC XTFASTCALL POBJECT_HEADER_NAME_INFO ReferenceObjectNameInformation(IN POBJECT_HEADER ObjectHeader); + + private: + STATIC XTFASTCALL PWCHAR AllocateObjectName(IN ULONG Length, + IN BOOLEAN UseLookaside, + IN OUT PUNICODE_STRING ObjectName); + STATIC XTAPI VOID CalculateOptionalHeaderSize(IN POBJECT_CREATE_INFORMATION CreateInfo, + IN POBJECT_TYPE ObjectType, + IN PUNICODE_STRING ObjectName, + OUT POBJECT_OPTIONAL_HEADER_LAYOUT Layout); + STATIC XTAPI XTSTATUS CaptureObjectCreateInformation(IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE ProcessorMode, + IN KPROCESSOR_MODE OwnerProcessorMode, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN OUT PUNICODE_STRING CapturedObjectName, + IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, + IN BOOLEAN UseLookaside); + STATIC XTAPI XTSTATUS CaptureObjectName(IN KPROCESSOR_MODE ProcessorMode, + IN PUNICODE_STRING ObjectName, + IN OUT PUNICODE_STRING CapturedObjectName, + IN BOOLEAN UseLookaside); + STATIC XTAPI VOID DeleteObject(IN PVOID Object, + IN BOOLEAN CalledOnWorkerThread); + STATIC XTAPI VOID FreeObject(IN PVOID Object); + STATIC XTFASTCALL VOID FreeObjectCreateInformation(IN POBJECT_CREATE_INFORMATION CreateInfo); + STATIC XTFASTCALL VOID FreeObjectName(IN OUT PUNICODE_STRING ObjectName); + STATIC XTAPI PVOID GetObjectAllocationBase(IN POBJECT_HEADER ObjectHeader); + STATIC XTAPI VOID ProcessDeferredDeletionQueue(IN PVOID Parameter); + STATIC XTFASTCALL VOID ReleaseObjectCreateInformation(IN POBJECT_CREATE_INFORMATION CreateInfo); + STATIC XTAPI VOID ReturnObjectQuota(IN POBJECT_HEADER ObjectHeader, + IN POBJECT_TYPE ObjectType); + }; +} + +#endif /* __XTOSKRNL_OB_LIFECYCL_HH */ diff --git a/xtoskrnl/includes/ob/obdir.hh b/xtoskrnl/includes/ob/obdir.hh new file mode 100644 index 0000000..f864b85 --- /dev/null +++ b/xtoskrnl/includes/ob/obdir.hh @@ -0,0 +1,53 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/obdir.hh + * DESCRIPTION: Object Manager Security API + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_OBDIR_HH +#define __XTOSKRNL_OB_OBDIR_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class Directory + { + public: + STATIC XTAPI BOOLEAN DeleteDirectoryEntry(IN POBJECT_LOOKUP_CONTEXT LookupContext); + STATIC XTFASTCALL VOID InitializeLookupContext(OUT POBJECT_LOOKUP_CONTEXT LookupContext); + STATIC XTAPI BOOLEAN InsertDirectoryEntry(IN OUT POBJECT_DIRECTORY Directory, + IN POBJECT_LOOKUP_CONTEXT LookupContext, + IN OUT POBJECT_HEADER ObjectHeader); + STATIC XTFASTCALL VOID LockLookupContext(IN POBJECT_DIRECTORY Directory, + IN POBJECT_LOOKUP_CONTEXT LookupContext); + + STATIC XTAPI PVOID LookupDirectoryEntry(IN POBJECT_DIRECTORY Directory, + IN PUNICODE_STRING Name, + IN ULONG Attributes, + IN BOOLEAN SearchGlobalDirectory, + OUT POBJECT_LOOKUP_CONTEXT LookupContext); + STATIC XTFASTCALL VOID ReleaseLookupContext(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext); + + private: + STATIC XTFASTCALL VOID AcquireExclusiveDirectoryLock(IN OUT POBJECT_DIRECTORY Directory, + IN OUT POBJECT_LOOKUP_CONTEXT LookupContext); + STATIC XTFASTCALL VOID AcquireSharedDirectoryLock(IN POBJECT_DIRECTORY Directory, + IN POBJECT_LOOKUP_CONTEXT LookupContext); + STATIC XTFASTCALL ULONG ComputeObjectNameHash(IN PCUNICODE_STRING Name); + STATIC XTFASTCALL VOID ReleaseDirectoryLock(IN OUT POBJECT_DIRECTORY Directory, + IN OUT POBJECT_LOOKUP_CONTEXT LookupContext); + STATIC XTFASTCALL VOID ReleaseLookupContextObject(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext); + STATIC XTFASTCALL PVOID SearchDirectory(IN POBJECT_DIRECTORY Directory, + IN PCUNICODE_STRING Name, + IN BOOLEAN CaseInsensitive, + IN ULONG HashIndex, + IN POBJECT_LOOKUP_CONTEXT LookupContext); + }; +} + +#endif /* __XTOSKRNL_OB_OBDIR_HH */ diff --git a/xtoskrnl/includes/ob/obmgr.hh b/xtoskrnl/includes/ob/obmgr.hh new file mode 100644 index 0000000..7badb5c --- /dev/null +++ b/xtoskrnl/includes/ob/obmgr.hh @@ -0,0 +1,35 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/obmgr.hh + * DESCRIPTION: Object Manager + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_OBMGR_HH +#define __XTOSKRNL_OB_OBMGR_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class Manager + { + private: + STATIC GENERAL_LOOKASIDE CreateInfoList; + STATIC GENERAL_LOOKASIDE NameBufferList; + + public: + STATIC XTFASTCALL VOID InitializeObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING ObjectName, + IN ULONG Attributes, + IN HANDLE Directory, + IN PVOID SecurityDescriptor); + STATIC XTAPI XTSTATUS InitializeObjectManager(VOID); + STATIC XTAPI VOID InitializeSystemLookasideList(VOID); + }; +} + +#endif /* __XTOSKRNL_OB_OBMGR_HH */ diff --git a/xtoskrnl/includes/ob/security.hh b/xtoskrnl/includes/ob/security.hh new file mode 100644 index 0000000..8f873b2 --- /dev/null +++ b/xtoskrnl/includes/ob/security.hh @@ -0,0 +1,54 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/security.hh + * DESCRIPTION: Object Manager Security API + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_SECURITY_HH +#define __XTOSKRNL_OB_SECURITY_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class Security + { + public: + STATIC XTAPI XTSTATUS AssignObjectSecurityDescriptor(IN PVOID Object, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN MMPOOL_TYPE PoolType); + STATIC XTAPI BOOLEAN AuditInheritedHandle(IN PHANDLE_TABLE_ENTRY ObjectTableEntry, + IN HANDLE HandleId, + IN PVOID Context); + STATIC XTAPI VOID AuditObjectAccess(IN HANDLE Handle, + IN PHANDLE_TABLE_ENTRY_INFO ObjectTableEntryInfo, + IN PUNICODE_STRING ObjectTypeName, + IN ACCESS_MASK DesiredAccess); + STATIC XTAPI XTSTATUS DeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor); + STATIC XTAPI XTSTATUS ProcessObjectSecurityDescriptor(IN PVOID Object, + IN SECURITY_OPERATION_CODE OperationCode, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG Length, + IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor, + IN MMPOOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping); + STATIC XTAPI XTSTATUS QuerySecurityDescriptorInfo(IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG Length, + IN PSECURITY_DESCRIPTOR *OldSecurityDescriptor); + STATIC XTAPI XTSTATUS SetSecurityDescriptorInfo(IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor, + IN MMPOOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping); + }; +} + +#endif /* __XTOSKRNL_OB_SECURITY_HH */ diff --git a/xtoskrnl/includes/ob/typereg.hh b/xtoskrnl/includes/ob/typereg.hh new file mode 100644 index 0000000..5e4d2d4 --- /dev/null +++ b/xtoskrnl/includes/ob/typereg.hh @@ -0,0 +1,44 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ob/typereg.hh + * DESCRIPTION: Object Manager Type Registry + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_OB_TYPEREG_HH +#define __XTOSKRNL_OB_TYPEREG_HH + +#include + + +/* Object Manager */ +namespace OB +{ + class TypeRegistry + { + private: + STATIC KEVENT DefaultEvent; + STATIC POBJECT_TYPE MasterObjectType; + STATIC POBJECT_DIRECTORY ObjectTypeDirectory; + STATIC POBJECT_TYPE ObjectTypesTable[OBJECT_MAX_DEFINED_OBJECT_TYPES]; + + public: + STATIC XTAPI XTSTATUS CreateObjectType(IN PUNICODE_STRING TypeName, + IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + OUT POBJECT_TYPE *ObjectType); + STATIC XTAPI VOID DeleteObjectType(IN PVOID Object); + STATIC XTAPI XTSTATUS InitializeObjectTypeRegistry(VOID); + + private: + STATIC XTAPI ULONG GenerateObjectPoolTag(IN PUNICODE_STRING TypeName); + STATIC XTAPI VOID InitializeObjectType(IN OUT POBJECT_TYPE ObjectType, + IN POBJECT_TYPE_INITIALIZER Initializer, + IN PUNICODE_STRING ObjectName); + STATIC XTAPI XTSTATUS ValidateObjectTypeParameters(IN PUNICODE_STRING TypeName, + IN POBJECT_TYPE_INITIALIZER Initializer); + }; +} + +#endif /* __XTOSKRNL_OB_TYPEREG_HH */ diff --git a/xtoskrnl/includes/po/idle.hh b/xtoskrnl/includes/po/idle.hh index 0452063..37f4bfa 100644 --- a/xtoskrnl/includes/po/idle.hh +++ b/xtoskrnl/includes/po/idle.hh @@ -12,7 +12,7 @@ #include -/* Runtime Library */ +/* Power Management */ namespace PO { class Idle diff --git a/xtoskrnl/includes/ps.hh b/xtoskrnl/includes/ps.hh new file mode 100644 index 0000000..f3aa725 --- /dev/null +++ b/xtoskrnl/includes/ps.hh @@ -0,0 +1,20 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ps.hh + * DESCRIPTION: Process and thread management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_PS_HH +#define __XTOSKRNL_PS_HH + +#include + +#include +#include +#include +#include + + +#endif /* __XTOSKRNL_PS_HH */ diff --git a/xtoskrnl/includes/ps/process.hh b/xtoskrnl/includes/ps/process.hh new file mode 100644 index 0000000..0b7ab62 --- /dev/null +++ b/xtoskrnl/includes/ps/process.hh @@ -0,0 +1,49 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ps/process.hh + * DESCRIPTION: Process Management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_PS_PROCESS_HH +#define __XTOSKRNL_PS_PROCESS_HH + +#include + + +/* Process and thread management */ +namespace PS +{ + class Process + { + private: + STATIC PEPROCESS IdleProcess; + STATIC PEPROCESS SystemProcess; + STATIC HANDLE SystemProcessHandle; + + public: + STATIC XTAPI XTSTATUS CreateIdleProcess(IN PKPROCESSOR_CONTROL_BLOCK Prcb); + STATIC XTAPI XTSTATUS CreateInitialSystemProcess(VOID); + STATIC XTAPI XTSTATUS CreateSystemProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK AccessMask, + IN POBJECT_ATTRIBUTES Attributes); + STATIC XTAPI VOID DeleteProcess(IN PVOID ProcessObject); + STATIC XTFASTCALL PEPROCESS GetCurrentProcess(VOID); + STATIC XTFASTCALL PEPROCESS GetSystemProcess(VOID); + STATIC XTAPI VOID InitializeIdleProcess(VOID); + + private: + STATIC XTAPI XTSTATUS CreateKernelProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK AccessMask, + IN POBJECT_ATTRIBUTES Attributes, + IN HANDLE ParentProcess, + IN ULONG Flags, + IN HANDLE SectionHandle, + IN HANDLE DebugPort, + IN HANDLE ExceptionPort, + IN BOOLEAN JobMember); + }; +} + +#endif /* __XTOSKRNL_PS_PROCESS_HH */ diff --git a/xtoskrnl/includes/ps/psmgr.hh b/xtoskrnl/includes/ps/psmgr.hh new file mode 100644 index 0000000..43cde09 --- /dev/null +++ b/xtoskrnl/includes/ps/psmgr.hh @@ -0,0 +1,31 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ps/process.hh + * DESCRIPTION: Process Manager + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_PS_PSMGR_HH +#define __XTOSKRNL_PS_PSMGR_HH + +#include + + +/* Process and thread management */ +namespace PS +{ + class ProcessManager + { + private: + STATIC POBJECT_TYPE ProcessType; + STATIC POBJECT_TYPE ThreadType; + + public: + STATIC XTFASTCALL POBJECT_TYPE GetProcessType(VOID); + STATIC XTFASTCALL POBJECT_TYPE GetThreadType(VOID); + STATIC XTAPI VOID InitializeProcessManager(VOID); + }; +} + +#endif /* __XTOSKRNL_PS_PSMGR_HH */ diff --git a/xtoskrnl/includes/ps/quota.hh b/xtoskrnl/includes/ps/quota.hh new file mode 100644 index 0000000..81e38f6 --- /dev/null +++ b/xtoskrnl/includes/ps/quota.hh @@ -0,0 +1,48 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ps/quota.hh + * DESCRIPTION: Process Quota Management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_PS_QUOTA_HH +#define __XTOSKRNL_PS_QUOTA_HH + +#include + + +/* Process and thread management */ +namespace PS +{ + class Quota + { + private: + STATIC EPROCESS_QUOTA_BLOCK DefaultQuotaBlock; + STATIC KSPIN_LOCK QuotaLock; + + public: + STATIC XTAPI XTSTATUS ChargeProcessQuota(IN PEPROCESS_QUOTA_BLOCK QuotaBlock, + IN PEPROCESS Process, + IN PS_QUOTA_TYPE QuotaType, + IN SIZE_T Amount); + STATIC XTAPI PEPROCESS_QUOTA_BLOCK ChargeSharedPoolQuota(IN PEPROCESS Process, + IN SIZE_T PagedAmount, + IN SIZE_T NonPagedAmount); + STATIC VOID XTAPI InitializeQuota(VOID); + STATIC XTFASTCALL VOID ReturnProcessQuota(IN PEPROCESS_QUOTA_BLOCK QuotaBlock, + IN PEPROCESS Process, + IN PS_QUOTA_TYPE QuotaType, + IN SIZE_T Amount); + STATIC XTAPI VOID ReturnSharedPoolQuota(IN PEPROCESS_QUOTA_BLOCK QuotaBlock, + IN SIZE_T PagedAmount, + IN SIZE_T NonPagedAmount); + + private: + STATIC XTAPI VOID DereferenceQuotaBlock(IN PEPROCESS_QUOTA_BLOCK QuotaBlock); + STATIC XTINLINE VOID UpdatePeakUsage(IN PSIZE_T TargetQuota, + IN SIZE_T NewQuota); + }; +} + +#endif /* __XTOSKRNL_PS_QUOTA_HH */ diff --git a/xtoskrnl/includes/ps/thread.hh b/xtoskrnl/includes/ps/thread.hh new file mode 100644 index 0000000..a6a0f2c --- /dev/null +++ b/xtoskrnl/includes/ps/thread.hh @@ -0,0 +1,28 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/ps/thread.hh + * DESCRIPTION: Thread Management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_PS_THREAD_HH +#define __XTOSKRNL_PS_THREAD_HH + +#include + + +/* Process and thread management */ +namespace PS +{ + class Thread + { + public: + STATIC XTAPI XTSTATUS CreateIdleThread(IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PVOID Stack); + STATIC XTAPI VOID DeleteThread(IN PVOID ThreadObject); + STATIC XTAPI PETHREAD GetCurrentThread(VOID); + }; +} + +#endif /* __XTOSKRNL_PS_THREAD_HH */ diff --git a/xtoskrnl/includes/rtl.hh b/xtoskrnl/includes/rtl.hh index 939ee8c..b27b08d 100644 --- a/xtoskrnl/includes/rtl.hh +++ b/xtoskrnl/includes/rtl.hh @@ -17,15 +17,19 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include #include #include #include +#include #include #endif /* __XTOSKRNL_RTL_HH */ diff --git a/xtoskrnl/includes/rtl/atomic.hh b/xtoskrnl/includes/rtl/atomic.hh index f3b9150..1325bf5 100644 --- a/xtoskrnl/includes/rtl/atomic.hh +++ b/xtoskrnl/includes/rtl/atomic.hh @@ -18,6 +18,16 @@ namespace RTL class Atomic { public: + STATIC XTFASTCALL CHAR Add8(IN PCHAR Address, + IN CHAR Value); + STATIC XTFASTCALL SHORT Add16(IN PSHORT Address, + IN SHORT Value); + STATIC XTFASTCALL LONG Add32(IN PLONG Address, + IN LONG Value); + STATIC XTFASTCALL LONG_PTR Add64(IN PLONG_PTR Address, + IN LONG_PTR Value); + STATIC XTFASTCALL PVOID AddPointer(IN PVOID *Address, + IN PVOID Value); STATIC XTFASTCALL CHAR And8(IN PCHAR Address, IN CHAR Mask); STATIC XTFASTCALL SHORT And16(IN PSHORT Address, @@ -26,6 +36,10 @@ namespace RTL IN LONG Mask); STATIC XTFASTCALL LONG_PTR And64(IN PLONG_PTR Address, IN LONG_PTR Mask); + STATIC XTFASTCALL UCHAR BitTestAndReset(IN PLONG Base, + IN LONG Offset); + STATIC XTFASTCALL UCHAR BitTestAndReset64(IN PLONGLONG Base, + IN LONGLONG Offset); STATIC XTFASTCALL UCHAR BitTestAndSet(IN PLONG Base, IN LONG Offset); STATIC XTFASTCALL UCHAR BitTestAndSet64(IN PLONGLONG Base, @@ -67,7 +81,7 @@ namespace RTL IN LONG_PTR Value); STATIC XTFASTCALL PVOID ExchangePointer(IN PVOID *Address, IN PVOID Exchange); - STATIC XTFASTCALL PSINGLE_LIST_ENTRY FlushSingleList(IN PSINGLE_LIST_HEADER Header); + STATIC XTFASTCALL PSINGLE_LIST_ENTRY FlushSingleList(IN PSINGLE_LIST_HEADER ListHead); STATIC XTFASTCALL CHAR Increment8(IN PCHAR Address); STATIC XTFASTCALL SHORT Increment16(IN PSHORT Address); STATIC XTFASTCALL LONG Increment32(IN PLONG Address); @@ -80,8 +94,8 @@ namespace RTL IN LONG Mask); STATIC XTFASTCALL LONG_PTR Or64(IN PLONG_PTR Address, IN LONG_PTR Mask); - STATIC XTFASTCALL XTFASTCALL PSINGLE_LIST_ENTRY PopEntrySingleList(IN PSINGLE_LIST_HEADER Header); - STATIC XTFASTCALL PSINGLE_LIST_ENTRY PushEntrySingleList(IN PSINGLE_LIST_HEADER Header, + STATIC XTFASTCALL XTFASTCALL PSINGLE_LIST_ENTRY PopEntrySingleList(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTFASTCALL PSINGLE_LIST_ENTRY PushEntrySingleList(IN PSINGLE_LIST_HEADER ListHead, IN PSINGLE_LIST_ENTRY Entry); STATIC XTFASTCALL CHAR Xor8(IN PCHAR Address, IN CHAR Mask); diff --git a/xtoskrnl/includes/rtl/exsup.hh b/xtoskrnl/includes/rtl/exsup.hh new file mode 100644 index 0000000..d221c98 --- /dev/null +++ b/xtoskrnl/includes/rtl/exsup.hh @@ -0,0 +1,27 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/exsup.hh + * DESCRIPTION: Exception handling + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_RTL_EXSUP_HH +#define __XTOSKRNL_RTL_EXSUP_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class Exception + { + public: + STATIC XTAPI VOID RaiseException(IN PEXCEPTION_RECORD ExceptionRecord); + STATIC XTAPI VOID RaiseStatus(IN XTSTATUS Status); + STATIC XTAPI LONG SystemFilter(VOID); + }; +} + +#endif /* __XTOSKRNL_RTL_EXSUP_HH */ diff --git a/xtoskrnl/includes/rtl/lifo.hh b/xtoskrnl/includes/rtl/lifo.hh new file mode 100644 index 0000000..35a4740 --- /dev/null +++ b/xtoskrnl/includes/rtl/lifo.hh @@ -0,0 +1,31 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/lifo.hh + * DESCRIPTION: Last In First Out (LIFO) queue implementation + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_RTL_LIFO_HH +#define __XTOSKRNL_RTL_LIFO_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class LifoQueue + { + public: + STATIC XTFASTCALL BOOLEAN EmptyList(IN PSINGLE_LIST_ENTRY ListHead); + STATIC XTFASTCALL PSINGLE_LIST_ENTRY PeekEntryList(IN PSINGLE_LIST_ENTRY ListHead); + STATIC XTFASTCALL PSINGLE_LIST_ENTRY PopEntryList(IN OUT PSINGLE_LIST_ENTRY ListHead); + STATIC XTFASTCALL VOID PushEntryList(IN OUT PSINGLE_LIST_ENTRY ListHead, + IN PSINGLE_LIST_ENTRY Entry); + STATIC XTFASTCALL BOOLEAN SearchEntryList(IN PSINGLE_LIST_ENTRY ListHead, + IN PSINGLE_LIST_ENTRY Entry); + }; +} + +#endif /* __XTOSKRNL_RTL_LIFO_HH */ diff --git a/xtoskrnl/includes/rtl/nls.hh b/xtoskrnl/includes/rtl/nls.hh new file mode 100644 index 0000000..8174186 --- /dev/null +++ b/xtoskrnl/includes/rtl/nls.hh @@ -0,0 +1,34 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/nls.hh + * DESCRIPTION: National Language Support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_RTL_NLS_HH +#define __XTOSKRNL_RTL_NLS_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class Nls + { + public: + STATIC XTAPI VOID GetDefaultCodePage(OUT PUSHORT AnsiCodePage, + OUT PUSHORT OemCodePage); + STATIC XTAPI VOID InitializeCodePageTable(IN PUSHORT TableBase, + OUT PCPTABLE_INFO CodePageTable); + STATIC XTAPI VOID InitializeNlsTables(IN PUSHORT AnsiTableBase, + IN PUSHORT OemTableBase, + IN PUSHORT CaseTableBase, + OUT PNLSTABLE_INFO NlsTable); + STATIC XTAPI WCHAR ToLowerUnicodeCharacter(IN WCHAR WideCHaracter); + STATIC XTAPI WCHAR ToUpperUnicodeCharacter(IN WCHAR WideCharacter); + }; +} + +#endif /* __XTOSKRNL_RTL_NLS_HH */ diff --git a/xtoskrnl/includes/rtl/unicode.hh b/xtoskrnl/includes/rtl/unicode.hh new file mode 100644 index 0000000..5ea1c5e --- /dev/null +++ b/xtoskrnl/includes/rtl/unicode.hh @@ -0,0 +1,32 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/unicode.hh + * DESCRIPTION: Unicode support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_RTL_UNICODE_HH +#define __XTOSKRNL_RTL_UNICODE_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class Unicode + { + public: + STATIC XTAPI LONG CompareString(IN PCUNICODE_STRING String1, + IN PCUNICODE_STRING String2, + IN BOOLEAN CaseInsensitive); + STATIC XTAPI VOID CopyString(IN OUT PUNICODE_STRING Destination, + IN PCUNICODE_STRING Source); + STATIC XTAPI XTSTATUS InitializeString(OUT PUNICODE_STRING Destination, + IN PCWSTR Source, + IN BOOLEAN Truncate = FALSE); + }; +} + +#endif /* __XTOSKRNL_RTL_UNICODE_HH */ diff --git a/xtoskrnl/includes/se.hh b/xtoskrnl/includes/se.hh new file mode 100644 index 0000000..7f92143 --- /dev/null +++ b/xtoskrnl/includes/se.hh @@ -0,0 +1,20 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/se.hh + * DESCRIPTION: Kernel Security + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_SE_HH +#define __XTOSKRNL_SE_HH + +#include + +#include +#include +#include +#include + + +#endif /* __XTOSKRNL_SE_HH */ diff --git a/xtoskrnl/includes/se/access.hh b/xtoskrnl/includes/se/access.hh new file mode 100644 index 0000000..307724b --- /dev/null +++ b/xtoskrnl/includes/se/access.hh @@ -0,0 +1,30 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/se/access.hh + * DESCRIPTION: Security access state check routines + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_SE_ACCESS_HH +#define __XTOSKRNL_SE_ACCESS_HH + +#include + + +/* Kernel Security */ +namespace SE +{ + class Access + { + public: + STATIC XTFASTCALL ACCESS_MASK ComputeDeniedAccesses(IN ACCESS_MASK GrantedAccess, + IN ACCESS_MASK DesiredAccess); + STATIC XTFASTCALL ACCESS_MASK ComputeGrantedAccesses(IN ACCESS_MASK GrantedAccess, + IN ACCESS_MASK DesiredAccess); + STATIC XTAPI VOID MapGenericMask(IN OUT PACCESS_MASK AccessMask, + IN PGENERIC_MAPPING Mapping); + }; +} + +#endif /* __XTOSKRNL_SE_ACCESS_HH */ diff --git a/xtoskrnl/includes/se/audit.hh b/xtoskrnl/includes/se/audit.hh new file mode 100644 index 0000000..0f35d13 --- /dev/null +++ b/xtoskrnl/includes/se/audit.hh @@ -0,0 +1,34 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/se/audit.hh + * DESCRIPTION: Security Auditing + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_SE_AUDIT_HH +#define __XTOSKRNL_SE_AUDIT_HH + +#include + + +/* Kernel Security */ +namespace SE +{ + class Audit + { + public: + STATIC XTAPI VOID AuditHandleDuplication(PVOID SourceHandle, + PVOID TargetHandle, + PEPROCESS SourceProcess, + PEPROCESS TargetProcess); + STATIC XTFASTCALL BOOLEAN AuditWithToken(IN PACCESS_TOKEN AccessToken); + STATIC XTAPI VOID OperationAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN ACCESS_MASK AccessMask, + IN PSID UserSid); + }; +} + +#endif /* __XTOSKRNL_SE_AUDIT_HH */ diff --git a/xtoskrnl/includes/se/descript.hh b/xtoskrnl/includes/se/descript.hh new file mode 100644 index 0000000..5493c10 --- /dev/null +++ b/xtoskrnl/includes/se/descript.hh @@ -0,0 +1,35 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/se/descript.hh + * DESCRIPTION: Security Descriptors + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_SE_DESCRIPT_HH +#define __XTOSKRNL_SE_DESCRIPT_HH + +#include + + +/* Kernel Security */ +namespace SE +{ + class Descriptor + { + public: + STATIC XTAPI XTSTATUS CaptureSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputDescriptor, + IN KPROCESSOR_MODE ProcessorMode, + IN MMPOOL_TYPE PoolType, + IN BOOLEAN ForceCapture, + OUT PSECURITY_DESCRIPTOR *OutputDescriptor); + STATIC XTFASTCALL ULONG ComputeSecurityQuota(IN ULONG Size); + STATIC XTAPI XTSTATUS ComputeQuotaInformationSize(IN PSECURITY_DESCRIPTOR SecurityDescriptor, + OUT PULONG QuotaSize); + STATIC XTAPI VOID ReleaseSecurityDescriptor(IN PSECURITY_DESCRIPTOR Descriptor, + IN KPROCESSOR_MODE ProcessorMode, + IN BOOLEAN Force); + }; +} + +#endif /* __XTOSKRNL_SE_DESCRIPT_HH */ diff --git a/xtoskrnl/includes/se/privileg.hh b/xtoskrnl/includes/se/privileg.hh new file mode 100644 index 0000000..ded58e0 --- /dev/null +++ b/xtoskrnl/includes/se/privileg.hh @@ -0,0 +1,37 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/se/privileg.hh + * DESCRIPTION: Privileges Management + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_SE_PRIVILEG_HH +#define __XTOSKRNL_SE_PRIVILEG_HH + +#include + + +/* Kernel Security */ +namespace SE +{ + class Privileges + { + + public: + STATIC XTAPI BOOLEAN CheckPrivilege(IN OUT PPRIVILEGE_SET RequiredPrivileges, + IN PSECURITY_SUBJECT_CONTEXT SecurityContext, + IN KPROCESSOR_MODE ProcessorMode); + STATIC XTAPI BOOLEAN CheckSinglePrivilege(LUID PrivilegeValue, + KPROCESSOR_MODE ProcessorMode); + + private: + STATIC XTAPI BOOLEAN CheckPrivilege(IN PTOKEN Token, + IN OUT PLUID_AND_ATTRIBUTES Privileges, + IN ULONG PrivilegeCount, + IN ULONG PrivilegeSet, + IN KPROCESSOR_MODE ProcessorMode); + }; +} + +#endif /* __XTOSKRNL_SE_PRIVILEG_HH */ diff --git a/xtoskrnl/includes/xtos.hh b/xtoskrnl/includes/xtos.hh index 3363583..253418d 100644 --- a/xtoskrnl/includes/xtos.hh +++ b/xtoskrnl/includes/xtos.hh @@ -23,5 +23,8 @@ #include #include #include +#include #include +#include #include +#include diff --git a/xtoskrnl/kd/amd64/debug.cc b/xtoskrnl/kd/amd64/debug.cc new file mode 100644 index 0000000..bc372b8 --- /dev/null +++ b/xtoskrnl/kd/amd64/debug.cc @@ -0,0 +1,36 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/kd/amd64/debug.cc + * DESCRIPTION: Kernel Debugger + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Transfers active control to a previously frozen processor. + * + * @return This routine returns a value indicating how execution should proceed after the debugging session concludes. + * + * @since XT 1.0 + */ +XTAPI +KCONTINUE_STATUS +KD::Debugger::SwitchProcessor(VOID) +{ + EXCEPTION_RECORD ExceptionRecord; + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Get processor control block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Construct an exception record */ + ExceptionRecord.ExceptionAddress = (PVOID)&Prcb->ProcessorState.ContextFrame.Rip; + ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER; + ExceptionRecord.ExceptionRecord = &ExceptionRecord; + + /* Pass the synthetic exception and the processor context to the debugger */ + return (KCONTINUE_STATUS)ProcessCpuStateChange(&ExceptionRecord, &Prcb->ProcessorState.ContextFrame, FALSE); +} diff --git a/xtoskrnl/kd/data.cc b/xtoskrnl/kd/data.cc index 4a999a3..044a55e 100644 --- a/xtoskrnl/kd/data.cc +++ b/xtoskrnl/kd/data.cc @@ -9,6 +9,9 @@ #include +/* Debugger active flag */ +BOOLEAN KD::Debugger::Active; + /* Debug I/O spinlock */ KSPIN_LOCK KD::DebugIo::DebugIoLock; diff --git a/xtoskrnl/kd/dbgio.cc b/xtoskrnl/kd/dbgio.cc index e9f0b21..91f5b79 100644 --- a/xtoskrnl/kd/dbgio.cc +++ b/xtoskrnl/kd/dbgio.cc @@ -57,12 +57,16 @@ VOID KD::DebugIo::DbgPrint(PCWSTR Format, VA_LIST Arguments) { - PLIST_ENTRY DispatchTableEntry; PKD_DISPATCH_TABLE DispatchTable; + PLIST_ENTRY DispatchTableEntry; + BOOLEAN BypassLocks; - /* Raise runlevel and acquire the Debug I/O lock */ - KE::RaiseRunLevel RunLevel(HIGH_LEVEL); - KE::SpinLockGuard SpinLock(&DebugIoLock); + /* Evaluate if the system is currently in a critical or debugging state */ + BypassLocks = (KE::Crash::SystemCrashed() || KD::Debugger::DebuggerActive()); + + /* Conditionally raise runlevel and acquire the Debug I/O lock */ + KE::RaiseRunLevel RunLevel(HIGH_LEVEL, !BypassLocks); + KE::SpinLockGuard SpinLock(&DebugIoLock, !BypassLocks); /* Iterate over all registered debug providers */ DispatchTableEntry = Providers.Flink; diff --git a/xtoskrnl/kd/debug.cc b/xtoskrnl/kd/debug.cc new file mode 100644 index 0000000..7a06647 --- /dev/null +++ b/xtoskrnl/kd/debug.cc @@ -0,0 +1,74 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/kd/debug.cc + * DESCRIPTION: Kernel Debugger + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Determines whether the interactive kernel debugger is currently active and controlling the execution flow. + * + * @return This routine returns TRUE if the kernel debugger is active, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +KD::Debugger::DebuggerActive(VOID) +{ + return Active; +} + +/** + * Serves as the primary entry point for the interactive kernel debugger. + * + * @param TrapFrame + * Supplies a pointer to the processor's trap frame captured at the moment the breakpoint or exception occurred. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KD::Debugger::EnterDebugger(IN PKTRAP_FRAME TrapFrame) +{ + /* Mark the debugger as active */ + Active = TRUE; + + /* Print debug message and enter an infinite loop */ + DebugPrint(L"\n\n*** Entered KDebugger ***\n"); + for(;;); + + /* Mark the debugger as inactive */ + Active = FALSE; +} + +/** + * Processes a processor state change and acts as the primary event loop for the debugger. + * + * @param ExceptionRecord + * Supplies a pointer to the exception record that triggered the state change. + * + * @param Context + * Supplies a pointer to the processor's context frame. + * + * @param SecondChance + * Supplies a boolean value indicating whether this is a second-chance exception. + * + * @return This routine returns TRUE if the exception was handled by the debugger, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +KD::Debugger::ProcessCpuStateChange(IN PEXCEPTION_RECORD ExceptionRecord, + IN OUT PCONTEXT Context, + IN BOOLEAN SecondChance) +{ + return FALSE; +} diff --git a/xtoskrnl/kd/i686/debug.cc b/xtoskrnl/kd/i686/debug.cc new file mode 100644 index 0000000..8ce4233 --- /dev/null +++ b/xtoskrnl/kd/i686/debug.cc @@ -0,0 +1,36 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/kd/i686/debug.cc + * DESCRIPTION: Kernel Debugger + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Transfers active control to a previously frozen processor. + * + * @return This routine returns a value indicating how execution should proceed after the debugging session concludes. + * + * @since XT 1.0 + */ +XTAPI +KCONTINUE_STATUS +KD::Debugger::SwitchProcessor(VOID) +{ + EXCEPTION_RECORD ExceptionRecord; + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Get processor control block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Construct an exception record */ + ExceptionRecord.ExceptionAddress = (PVOID)&Prcb->ProcessorState.ContextFrame.Eip; + ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER; + ExceptionRecord.ExceptionRecord = &ExceptionRecord; + + /* Pass the synthetic exception and the processor context to the debugger */ + return (KCONTINUE_STATUS)ProcessCpuStateChange(&ExceptionRecord, &Prcb->ProcessorState.ContextFrame, FALSE); +} diff --git a/xtoskrnl/ke/affinity.cc b/xtoskrnl/ke/affinity.cc new file mode 100644 index 0000000..acc7e8f --- /dev/null +++ b/xtoskrnl/ke/affinity.cc @@ -0,0 +1,562 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/affinity.cc + * DESCRIPTION: XT kernel processor affinity management support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Atomically sets the target processor's affinity bit within the affinity map. + * + * @param AffinityMap + * Supplies a pointer to the affinity map to be modified. + * + * @param CpuNumber + * Supplies the logical processor number to include in the affinity map. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Affinity::AtomicSetProcessorAffinity(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber) +{ + /* Verify that the target processor falls within the allocated map boundaries */ + if((CpuNumber / 64) < AffinityMap->Size) + { + /* Atomically set the target CPU bit */ + RTL::Atomic::Or64((PLONG_PTR)&AffinityMap->Bitmap[CpuNumber / 64], ((KAFFINITY)1 << (CpuNumber % 64))); + } +} + +/** + * Computes the memory size required to allocate an affinity map. + * + * @param CpuCount + * Supplies the total number of logical processors the map needs to support. + * + * @param RequiredMapSize + * Supplies a pointer to a variable that receives the 8-byte aligned allocation size in bytes. + * + * @param RequiredBlockCount + * Supplies a pointer to a variable that receives the number of KAFFINITY blocks required to hold all CPUs. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Affinity::CalculateAffinityMapSize(IN ULONG CpuCount, + OUT PULONG RequiredMapSize, + OUT PULONG RequiredBlockCount) +{ + ULONG AffinitySize, MapSize; + + /* Calculate the required number of blocks and the total structure size */ + AffinitySize = (CpuCount + 63) / 64; + MapSize = sizeof(KAFFINITY_MAP) + (AffinitySize * sizeof(KAFFINITY)); + + /* Check if an allocation size is required */ + if(RequiredMapSize != NULLPTR) + { + /* Return the required allocation bytes aligned to an 8-byte boundary */ + *RequiredMapSize = (MapSize + 7) & ~7; + } + + /* Check if a block count is required */ + if(RequiredBlockCount != NULLPTR) + { + /* Return the required logical block count */ + *RequiredBlockCount = AffinitySize; + } +} + +/** + * Checks whether a specific processor is included in the affinity map. + * + * @param AffinityMap + * Supplies a pointer to the affinity map to query. + * + * @param CpuNumber + * Supplies the logical processor number to test. + * + * @return This routine returns TRUE if the processor's bit is set in the map, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::Affinity::CheckProcessorAffinity(IN PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber) +{ + /* Verify that the target processor falls within the allocated map boundaries */ + if((CpuNumber / 64) < AffinityMap->Size) + { + /* Isolate and test the specific bit corresponding to the target CPU */ + return (AffinityMap->Bitmap[CpuNumber / 64] & ((KAFFINITY)1 << (CpuNumber % 64))) != 0; + } + + /* Return FALSE if the requested CPU exceeds the map capacity */ + return FALSE; +} + +/** + * Clears all processor bindings from the given affinity map. + * + * @param AffinityMap + * Supplies a pointer to the affinity map to be cleared. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Affinity::ClearAffinityMap(IN OUT PKAFFINITY_MAP AffinityMap) +{ + /* Zero out the entire bitmap */ + RTL::Memory::ZeroMemory(AffinityMap->Bitmap, AffinityMap->Size * sizeof(KAFFINITY)); +} + +/** + * Clears the affinity bit for a specified processor. This is a non-atomic operation. + * + * @param AffinityMap + * Supplies a pointer to the affinity map to be modified. + * + * @param CpuNumber + * Supplies the logical processor number to exclude from the affinity map. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Affinity::ClearProcessorAffinity(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber) +{ + /* Verify that the target processor falls within the allocated map boundaries */ + if((CpuNumber / 64) < AffinityMap->Size) + { + /* Clear the target CPU bit in the affinity map */ + AffinityMap->Bitmap[CpuNumber / 64] &= ~((KAFFINITY)1 << (CpuNumber % 64)); + } +} + +/** + * Copies the topological layout and processor bindings from a source affinity map to a destination map. + * + * @param Destination + * Supplies a pointer to the target affinity map that will receive the copied data. + * + * @param Source + * Supplies a pointer to the source affinity map containing the active processor bindings. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +KE::Affinity::CopyAffinity(OUT PKAFFINITY_MAP Destination, + IN PKAFFINITY_MAP Source) +{ + ULONG Index; + + /* Validate that the destination map can accommodate the source topology */ + if(Destination->Size < Source->Size) + { + /* Buffer overrun prevention */ + return STATUS_BUFFER_TOO_SMALL; + } + + /* Copy map metadata */ + Destination->Reserved = Source->Reserved; + + /* Copy the active affinity bitmasks */ + for(Index = 0; Index < Source->Size; Index++) + { + /* Replicate the hardware topology bindings across all active array elements */ + Destination->Bitmap[Index] = Source->Bitmap[Index]; + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Allocates and initializes a new affinity map for the specified number of processors. + * + * @param CpuCount + * Supplies the total number of logical processors the map needs to support. + * + * @param AffinityMap + * Supplies a pointer to a variable that receives the address of the newly allocated and initialized map. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +KE::Affinity::CreateAffinityMap(IN ULONG CpuCount, + OUT PKAFFINITY_MAP* AffinityMap) +{ + PKAFFINITY_MAP AllocatedMap; + ULONG BlockCount, MapSize; + XTSTATUS Status; + + /* Query the required allocation size and internal block count */ + KE::Affinity::CalculateAffinityMapSize(CpuCount, &MapSize, &BlockCount); + + /* Allocate the memory block from the specified pool */ + Status = MM::Allocator::AllocatePool(NonPagedPool, MapSize, (PVOID*)&AllocatedMap); + if(Status != STATUS_SUCCESS) + { + /* Allocation failed, return status code */ + return Status; + } + + /* Zero the memory to ensure all processor bits are initially cleared */ + RTL::Memory::ZeroMemory(AllocatedMap, MapSize); + + /* Initialize the internal metadata required by iteration and validation routines */ + AllocatedMap->Size = BlockCount; + + /* Return the constructed map to the caller */ + *AffinityMap = AllocatedMap; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Frees a previously allocated affinity map and returns its memory to the pool. + * + * @param AffinityMap + * Supplies a pointer to the affinity map to be freed and destroyed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Affinity::DestroyAffinityMap(IN PKAFFINITY_MAP AffinityMap) +{ + /* Ensure the map pointer is valid */ + if(AffinityMap != NULLPTR) + { + /* Free the memory block back to the kernel pool */ + MM::Allocator::FreePool((PVOID)AffinityMap); + } +} + +/** + * Locates the next available logical processor to the left (higher topological index) of a specified seed. + * + * @param ThreadSeed + * Supplies the logical processor index used as the starting point for the upward search. + * + * @param AffinityMap + * Supplies a pointer to the extended affinity map defining the permitted processors. + * + * @return This routine returns the absolute topological index of the selected processor. + * + * @since XT 1.0 + */ +XTAPI +ULONG +KE::Affinity::FindNextLeftSetProcessor(IN ULONG ThreadSeed, + IN PKAFFINITY_MAP AffinityMap) +{ + ULONG BitIndex, BitsPerMask, Index, StartBit, StartIndex; + KAFFINITY Mask; + + /* Define the architectural bit width of a single affinity mask */ + BitsPerMask = sizeof(KAFFINITY) * 8; + + /* Prevent division by zero and out-of-bounds access if the topology map is uninitialized or empty */ + if(AffinityMap->Size == 0) + { + /* Fallback to the bootstrap processor */ + return 0; + } + + /* Calculate the target array index and bit offset based on the thread seed */ + StartIndex = (ThreadSeed / BitsPerMask) % AffinityMap->Size; + StartBit = ThreadSeed % BitsPerMask; + + /* Isolate the segment of the current affinity mask strictly to the left */ + if(StartBit == (BitsPerMask - 1)) + { + /* Prevent undefined behavior when shifting by the total architectural bit width */ + Mask = 0; + } + else + { + /* Mask out the seed bit and all bits below it */ + Mask = AffinityMap->Bitmap[StartIndex] & (~((KAFFINITY)0) << (StartBit + 1)); + } + + /* Evaluate if any allowed processors exist in the higher portion of the current mask */ + if(Mask != 0) + { + /* Locate the rightmost set bit within this masked subset */ + if(AR::CpuFunctions::ScanForwardBit(&BitIndex, Mask)) + { + /* Return the absolute topological index of the located processor */ + return (StartIndex * BitsPerMask) + BitIndex; + } + } + + /* Ascend through the subsequent array elements in the map */ + for(Index = StartIndex + 1; Index < AffinityMap->Size; Index++) + { + /* Load the complete processor mask for the current array boundary */ + Mask = AffinityMap->Bitmap[Index]; + + /* Check if this segment contains any active processor bindings */ + if(Mask != 0) + { + /* Find the lowest available processor within this array element */ + if(AR::CpuFunctions::ScanForwardBit(&BitIndex, Mask)) + { + /* Return the absolute topological index of the located processor */ + return (Index * BitsPerMask) + BitIndex; + } + } + } + + /* Wrap around and scan the entire map from the bottom to find the lowest globally permitted processor */ + for(Index = 0; Index < AffinityMap->Size; Index++) + { + /* Load the complete processor mask for the current array boundary */ + Mask = AffinityMap->Bitmap[Index]; + + /* Check if this segment contains any active processor bindings */ + if(Mask != 0) + { + /* Find the lowest available processor within this array element */ + if(AR::CpuFunctions::ScanForwardBit(&BitIndex, Mask)) + { + /* Return the absolute topological index of the located processor */ + return (Index * BitsPerMask) + BitIndex; + } + } + } + + /* Fallback to the bootstrap processor */ + return 0; +} + +/** + * Locates the next available logical processor to the right (lower topological index) of a specified seed. + * + * @param ThreadSeed + * Supplies the logical processor index used as the starting point for the downward search. + * + * @param AffinityMap + * Supplies a pointer to the extended affinity map defining the permitted processors. + * + * @return This routine returns the absolute topological index of the selected processor. + * + * @since XT 1.0 + */ +XTAPI +ULONG +KE::Affinity::FindNextRightSetProcessor(IN ULONG ThreadSeed, + IN PKAFFINITY_MAP AffinityMap) +{ + ULONG BitIndex, BitsPerMask, StartBit, StartIndex; + KAFFINITY Mask; + LONG Index; + + /* Define the architectural bit width of a single affinity mask */ + BitsPerMask = sizeof(KAFFINITY) * 8; + + /* Prevent division by zero and out-of-bounds access if the topology map is uninitialized or empty */ + if(AffinityMap->Size == 0) + { + /* Fallback to the bootstrap processor */ + return 0; + } + + /* Calculate the target array index and bit offset based on the seed */ + StartIndex = (ThreadSeed / BitsPerMask) % AffinityMap->Size; + StartBit = ThreadSeed % BitsPerMask; + + /* Isolate the segment of the current affinity mask strictly to the right */ + Mask = AffinityMap->Bitmap[StartIndex] & (((KAFFINITY)1 << StartBit) - 1); + + /* Evaluate if any allowed processors exist in the lower portion of the current mask */ + if(Mask != 0) + { + /* Locate the leftmost set bit within this masked subset */ + if(AR::CpuFunctions::ScanReverseBit(&BitIndex, Mask)) + { + /* Return the absolute topological index of the located processor */ + return (StartIndex * BitsPerMask) + BitIndex; + } + } + + /* Descend through the preceding array elements in the map */ + for(Index = (LONG)StartIndex - 1; Index >= 0; Index--) + { + /* Load the complete processor mask for the current array boundary */ + Mask = AffinityMap->Bitmap[Index]; + + /* Check if this segment contains any active processor bindings */ + if(Mask != 0) + { + /* Find the highest available processor within this array element */ + if(AR::CpuFunctions::ScanReverseBit(&BitIndex, Mask)) + { + /* Return the absolute topological index of the located processor */ + return ((ULONG)Index * BitsPerMask) + BitIndex; + } + } + } + + /* Wrap around and scan the entire map from the top to find the highest globally permitted processor */ + for(Index = (LONG)AffinityMap->Size - 1; Index >= 0; Index--) + { + /* Load the complete processor mask for the current array boundary */ + Mask = AffinityMap->Bitmap[Index]; + + /* Check if this segment contains any active processor bindings */ + if(Mask != 0) + { + /* Find the highest available processor within this array element */ + if(AR::CpuFunctions::ScanReverseBit(&BitIndex, Mask)) + { + /* Return the absolute topological index of the located processor */ + return ((ULONG)Index * BitsPerMask) + BitIndex; + } + } + } + + /* Fallback to the bootstrap processor */ + return 0; +} + +/** + * Initializes a caller-allocated affinity map structure. + * + * @param AffinityMap + * Supplies a pointer to the caller-allocated buffer to be initialized. + * + * @param BufferSize + * Supplies the size, in bytes, of the provided buffer. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +KE::Affinity::InitializeAffinityMap(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG BufferSize) +{ + ULONG Cpus, RequiredBlocks, RequiredSize; + + /* Get the number of available CPUs */ + Cpus = KE::Processor::GetInstalledCpus(); + + /* Query the required size in bytes and the architectural block count */ + KE::Affinity::CalculateAffinityMapSize(Cpus, &RequiredSize, &RequiredBlocks); + + /* Validate that the provided buffer is large enough to hold the structure */ + if(BufferSize < RequiredSize) + { + /* Buffer overrun prevention */ + return STATUS_BUFFER_TOO_SMALL; + } + + /* Zero only the required portion of the memory to clear any garbage data */ + RTL::Memory::ZeroMemory(AffinityMap, RequiredSize); + + /* Initialize the internal metadata required by iteration routines */ + AffinityMap->Reserved = 0; + AffinityMap->Size = RequiredBlocks; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Populates the affinity map with all available processors. + * + * @param AffinityMap + * Supplies a pointer to the affinity map to be fully populated. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Affinity::SetAllProcessorsAffinity(IN OUT PKAFFINITY_MAP AffinityMap) +{ + ULONG Cpus, Index; + + /* Get the number of available CPUs */ + Cpus = KE::Processor::GetInstalledCpus(); + + /* Iterate through all allocated blocks in the map */ + for(Index = 0; Index < AffinityMap->Size; Index++) + { + /* Evaluate if the remaining logical processors fully saturate the current block */ + if(Cpus >= 64) + { + /* Set all 64 bits and decrement the remaining count */ + AffinityMap->Bitmap[Index] = ~((KAFFINITY)0); + Cpus -= 64; + } + else if(Cpus > 0) + { + /* Generate a partial bitmask for the tail end of the processors */ + AffinityMap->Bitmap[Index] = (((KAFFINITY)1 << Cpus) - 1); + Cpus = 0; + } + else + { + /* Ensure any remaining blocks are safely zeroed */ + AffinityMap->Bitmap[Index] = 0; + } + } +} + +/** + * Sets the affinity bit for a specified processor. This is a non-atomic operation. + * + * @param AffinityMap + * Supplies a pointer to the affinity map to be modified. + * + * @param CpuNumber + * Supplies the logical processor number to include in the affinity map. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Affinity::SetProcessorAffinity(IN OUT PKAFFINITY_MAP AffinityMap, + IN ULONG CpuNumber) +{ + /* Verify that the target processor falls within the allocated map boundaries */ + if((CpuNumber / 64) < AffinityMap->Size) + { + /* Set the target CPU bit in the affinity map */ + AffinityMap->Bitmap[CpuNumber / 64] |= ((KAFFINITY)1 << (CpuNumber % 64)); + } +} diff --git a/xtoskrnl/ke/amd64/dispatch.cc b/xtoskrnl/ke/amd64/dispatch.cc index d9168da..80030fb 100644 --- a/xtoskrnl/ke/amd64/dispatch.cc +++ b/xtoskrnl/ke/amd64/dispatch.cc @@ -22,13 +22,12 @@ * * @since XT 1.0 */ +XTASSEMBLY XTFASTCALL BOOLEAN KE::Dispatcher::SwitchContext(IN PKTHREAD CurrentThread, IN KRUNLEVEL RunLevel) { - BOOLEAN PendingApc; - /* Save non-volatile and XMM registers to the exception frame, align the stack and invoke the switch routine */ __asm__ volatile("subq %[ExFrameSize], %%rsp\n" "movq %%rbp, %c[ExRbp](%%rsp)\n" @@ -69,10 +68,9 @@ KE::Dispatcher::SwitchContext(IN PKTHREAD CurrentThread, "movdqa %c[ExXmm14](%%rsp), %%xmm14\n" "movdqa %c[ExXmm15](%%rsp), %%xmm15\n" "addq %[ExFrameSize], %%rsp\n" - : "=a" (PendingApc) - : "c" (CurrentThread), - "d" (RunLevel), - [ExFrameSize] "i" (sizeof(KEXCEPTION_FRAME) - 8), + "ret\n" + : + : [ExFrameSize] "i" (sizeof(KEXCEPTION_FRAME) - 8), [ExR12] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, R12)), [ExR13] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, R13)), [ExR14] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, R14)), @@ -93,9 +91,6 @@ KE::Dispatcher::SwitchContext(IN PKTHREAD CurrentThread, [ExXmm15] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm15)), [SwitchRoutine] "i" (SwitchThreadStack) : "cc", "memory", "r8", "r9", "r10", "r11"); - - /* Return the APC status */ - return PendingApc; } /** @@ -134,13 +129,12 @@ KE::Dispatcher::SwitchThreadContext(IN PKTHREAD CurrentThread, * * @since XT 1.0 */ +XTASSEMBLY XTFASTCALL BOOLEAN KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread, IN KRUNLEVEL RunLevel) { - BOOLEAN PendingApc; - /* Preserve MXCSR, synchronize with CPUs, switch stack and call the switch routine */ __asm__ volatile("pushq %%rbp\n" "subq %[FrameSize], %%rsp\n" @@ -160,10 +154,9 @@ KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread, "ldmxcsr %c[SwMxCsr](%%rsp)\n" "addq %[FrameSize], %%rsp\n" "popq %%rbp\n" - : "=a" (PendingApc) - : "c" (CurrentThread), - "d" (RunLevel), - [FrameSize] "i" (FIELD_OFFSET(KSWITCH_FRAME, Rbp)), + "ret\n" + : + : [FrameSize] "i" (FIELD_OFFSET(KSWITCH_FRAME, Rbp)), [PrcbcCurrentThread] "i" (FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread)), [SwApcBypass] "i" (FIELD_OFFSET(KSWITCH_FRAME, ApcBypass)), [SwMxCsr] "i" (FIELD_OFFSET(KSWITCH_FRAME, MxCsr)), @@ -171,7 +164,4 @@ KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread, [ThrdStack] "i" (FIELD_OFFSET(KTHREAD, KernelStack)), [ThrdSwapBusy] "i" (FIELD_OFFSET(KTHREAD, SwapBusy)) : "cc", "memory", "r8", "r9", "r10", "r11"); - - /* Return the APC status */ - return PendingApc; } diff --git a/xtoskrnl/ke/amd64/krnlinit.cc b/xtoskrnl/ke/amd64/krnlinit.cc index 2a23e87..d1d680c 100644 --- a/xtoskrnl/ke/amd64/krnlinit.cc +++ b/xtoskrnl/ke/amd64/krnlinit.cc @@ -46,21 +46,30 @@ KE::KernelInit::BootstrapApplicationProcessor(IN PPROCESSOR_START_BLOCK StartBlo PO::Idle::InitializeProcessorIdleState(ControlBlock); /* Save processor state */ - KE::Processor::SaveProcessorState(&ControlBlock->ProcessorState); + KE::Processor::SaveProcessorControlState(&ControlBlock->ProcessorState); /* Initialize per-CPU spin lock queues */ KE::SpinLock::InitializeLockQueues(); + /* Initialize interrupt handlers */ + InitializeInterruptHandlers(); + /* Lower to APC runlevel */ KE::RunLevel::LowerRunLevel(APC_LEVEL); /* Initialize local clock for this CPU */ HL::Timer::InitializeLocalClock(); - /* Enter infinite loop */ - DebugPrint(L"KernelInit::BootstrapApplicationProcessor() finished for CPU #%lu. Entering infinite loop.\n", + /* Create and initialize IDLE thread */ + PS::Thread::CreateIdleThread(ControlBlock, StartBlock->Stack); + + /* Register DISPATCH interrupt handler */ + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_DPC, KE::Dispatcher::HandleDispatchInterrupt); + + /* Enter idle loop */ + DebugPrint(L"KernelInit::BootstrapApplicationProcessor() finished for CPU #%lu. Entering IDLE loop.\n", ControlBlock->CpuNumber); - KE::Crash::HaltSystem(); + KE::Dispatcher::EnterIdleLoop(); } /** @@ -76,62 +85,66 @@ VOID KE::KernelInit::BootstrapKernel(VOID) { PKPROCESSOR_CONTROL_BLOCK Prcb; - ULONG_PTR PageDirectory[2]; - PKPROCESS CurrentProcess; - PKTHREAD CurrentThread; - /* Get processor control block and current thread */ + /* Get processor control block */ Prcb = KE::Processor::GetCurrentProcessorControlBlock(); - CurrentThread = KE::Processor::GetCurrentThread(); - - /* Get current process */ - CurrentProcess = CurrentThread->ApcState.Process; /* Initialize CPU power state structures */ PO::Idle::InitializeProcessorIdleState(Prcb); /* Save processor state */ - KE::Processor::SaveProcessorState(&Prcb->ProcessorState); + KE::Processor::SaveProcessorControlState(&Prcb->ProcessorState); /* Initialize spin locks */ KE::SpinLock::InitializeAllLocks(); KE::SpinLock::InitializeLockQueues(); + /* Initialize interrupt handlers */ + InitializeInterruptHandlers(); + /* Lower to APC runlevel */ KE::RunLevel::LowerRunLevel(APC_LEVEL); /* Initialize XTOS kernel */ InitializeKernel(); - /* Initialize Idle process */ - PageDirectory[0] = 0; - PageDirectory[1] = 0; - KE::KProcess::InitializeProcess(CurrentProcess, 0, MAXULONG_PTR, PageDirectory, FALSE); - CurrentProcess->Quantum = MAXCHAR; - - /* Initialize Idle thread */ - KE::KThread::InitializeThread(CurrentProcess, CurrentThread, NULLPTR, NULLPTR, NULLPTR, - NULLPTR, NULLPTR, AR::ProcessorSupport::GetBootStack(), TRUE); - CurrentThread->NextProcessor = Prcb->CpuNumber; - CurrentThread->Priority = THREAD_HIGH_PRIORITY; - CurrentThread->State = Running; - CurrentThread->Affinity = (ULONG_PTR)1 << Prcb->CpuNumber; - CurrentThread->WaitRunLevel = DISPATCH_LEVEL; - CurrentProcess->ActiveProcessors |= (ULONG_PTR)1 << Prcb->CpuNumber; - /* Initialize Memory Manager */ MM::Manager::InitializeMemoryManager(); /* Enable shadow buffer for framebuffer */ HL::FrameBuffer::EnableShadowBuffer(); + /* Create and initialize IDLE process */ + PS::Process::CreateIdleProcess(Prcb); + /* Start all application processors */ KE::Processor::InitializeProcessorBlocks(); + HL::Cpu::InitializeProcessorAffinity(); HL::Cpu::StartAllProcessors(); - /* Enter infinite loop */ - DebugPrint(L"KernelInit::BootstrapKernel() finished. Entering infinite loop.\n"); - KE::Crash::HaltSystem(); + /* Register DISPATCH interrupt handler */ + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_DPC, KE::Dispatcher::HandleDispatchInterrupt); + + /* Enter idle loop */ + DebugPrint(L"KernelInit::BootstrapKernel() finished. Entering IDLE loop.\n"); + KE::Dispatcher::EnterIdleLoop(); +} + +/** + * Initializes and registers the core system interrupt handlers. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::KernelInit::InitializeInterruptHandlers(VOID) +{ + /* Register interrupt handlers */ + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_APC, KE::Apc::HandleApcInterrupt); + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_DPC, KE::Dispatcher::HandleDispatchInterrupt); + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_IPI, KE::Ipi::HandleIpiInterrupt); } /** @@ -209,7 +222,7 @@ KE::KernelInit::SwitchBootStack(VOID) __asm__ volatile("movq %[Stack], %%rsp\n" "subq %[TotalSize], %%rsp\n" "xorq %%rbp, %%rbp\n" - "jmp *%[TargetRoutine]\n" + "call *%[TargetRoutine]\n" : : [Stack] "r" (Stack), [TargetRoutine] "r" (StartKernel), diff --git a/xtoskrnl/ke/amd64/kthread.cc b/xtoskrnl/ke/amd64/kthread.cc index 83820e7..9bee0b3 100644 --- a/xtoskrnl/ke/amd64/kthread.cc +++ b/xtoskrnl/ke/amd64/kthread.cc @@ -40,6 +40,7 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread, IN PCONTEXT ContextRecord) { PKTHREAD_INIT_FRAME ThreadFrame; + CONTEXT ContextFrame; /* Set initial thread frame */ ThreadFrame = ((PKTHREAD_INIT_FRAME)Thread->InitialStack) - 1; @@ -50,45 +51,63 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread, /* Check if context provided for this thread */ if(ContextRecord) { - /* User mode thread needs further initialization, this is not completed */ - UNIMPLEMENTED; + /* Make a local copy of the context to avoid mutating caller's memory */ + RTL::Memory::CopyMemory(&ContextFrame, ContextRecord, sizeof(CONTEXT)); + + /* Disable debug registers and enable context registers */ + ContextFrame.ContextFlags |= CONTEXT_CONTROL; + ContextFrame.ContextFlags &= ~CONTEXT_DEBUG_REGISTERS; + + /* Align the stack and reserve space for 4 parameters and return value */ + ContextFrame.Rsp = (ContextFrame.Rsp & ~15) - 40; + + /* Set CS and SS segments for user mode */ + ContextFrame.SegCs = KGDT_R3_CODE | RPL_MASK; + ContextFrame.SegSs = KGDT_R3_DATA | RPL_MASK; /* Fill exception and trap frames with zeroes */ RTL::Memory::ZeroMemory(&ThreadFrame->ExceptionFrame, sizeof(KEXCEPTION_FRAME)); RTL::Memory::ZeroMemory(&ThreadFrame->TrapFrame, sizeof(KTRAP_FRAME)); - /* Disable debug registers and enable context registers */ - ContextRecord->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL; - - /* Align the stack and reserve space for 4 parameters and return value */ - ContextRecord->Rsp = (ContextRecord->Rsp & ~15) - 40; - - /* Set CS and SS segments for user mode */ - ContextRecord->SegCs = KGDT_R3_CODE | RPL_MASK; - ContextRecord->SegSs = KGDT_R3_DATA | RPL_MASK; + /* Translate Context frame to Trap frame */ + KE::Processor::RestoreProcessorContext(&ThreadFrame->TrapFrame, &ThreadFrame->ExceptionFrame, + &ContextFrame, ContextFrame.ContextFlags); /* This is user mode thread */ Thread->PreviousMode = UserMode; + ThreadFrame->TrapFrame.PreviousMode = UserMode; /* Enable floating point state */ Thread->NpxState = NPX_STATE_SCRUB; /* Set initial floating point state */ ThreadFrame->NpxFrame.ControlWord = 0x27F; + ThreadFrame->NpxFrame.DataOffset = 0; + ThreadFrame->NpxFrame.DataSelector = 0; + ThreadFrame->NpxFrame.ErrorOffset = 0; + ThreadFrame->NpxFrame.ErrorOpcode = 0; + ThreadFrame->NpxFrame.ErrorSelector = 0; + ThreadFrame->NpxFrame.StatusWord = 0; ThreadFrame->NpxFrame.TagWord = 0xFFFF; + /* Set initial MXCSR register value */ + ThreadFrame->TrapFrame.MxCsr = INITIAL_MXCSR; + /* Clear DR6 and DR7 registers */ ThreadFrame->TrapFrame.Dr6 = 0; ThreadFrame->TrapFrame.Dr7 = 0; - /* Set initial MXCSR register value */ - ThreadFrame->TrapFrame.MxCsr = INITIAL_MXCSR; + /* Terminate the Exception Handler List */ + ThreadFrame->TrapFrame.ExceptionFrame = (ULONGLONG)NULLPTR; /* Initialize exception frame */ - ThreadFrame->ExceptionFrame.P1Home = (ULONG64)StartContext; - ThreadFrame->ExceptionFrame.P2Home = (ULONG64)StartRoutine; - ThreadFrame->ExceptionFrame.P3Home = (ULONG64)SystemRoutine; - ThreadFrame->ExceptionFrame.P4Home = (ULONG64)SystemRoutine; + ThreadFrame->ExceptionFrame.P1Home = (ULONGLONG)StartContext; + ThreadFrame->ExceptionFrame.P2Home = (ULONGLONG)StartRoutine; + ThreadFrame->ExceptionFrame.P3Home = (ULONGLONG)SystemRoutine; + ThreadFrame->ExceptionFrame.P4Home = (ULONGLONG)SystemRoutine; + + /* Set the routine that will handle the thread finishing its initialization and transition it to UserMode */ + ThreadFrame->StartFrame.Return = (ULONG64)SwitchToUserMode; } else { @@ -98,21 +117,64 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread, /* Disable floating point state */ Thread->NpxState = NPX_STATE_UNUSED; - /* Set thread start address */ - ThreadFrame->StartFrame.Return = (ULONG64)NULLPTR; + /* Set the routine that will handle a system thread that unexpectedly finished its execution */ + ThreadFrame->StartFrame.Return = (ULONG64)HandleSystemThreadExit; } /* Initialize thread startup information */ - ThreadFrame->StartFrame.P1Home = (ULONG64)StartContext; - ThreadFrame->StartFrame.P2Home = (ULONG64)StartRoutine; - ThreadFrame->StartFrame.P3Home = (ULONG64)SystemRoutine; - ThreadFrame->StartFrame.P4Home = (ULONG64)SystemRoutine; + ThreadFrame->StartFrame.P1Home = (ULONGLONG)StartContext; + ThreadFrame->StartFrame.P2Home = (ULONGLONG)StartRoutine; + ThreadFrame->StartFrame.P3Home = (ULONGLONG)SystemRoutine; + ThreadFrame->StartFrame.P4Home = (ULONGLONG)SystemRoutine; /* Initialize switch frame */ ThreadFrame->SwitchFrame.ApcBypass = APC_LEVEL; ThreadFrame->SwitchFrame.MxCsr = INITIAL_MXCSR; - ThreadFrame->SwitchFrame.Rbp = (ULONG64)&ThreadFrame->TrapFrame; + ThreadFrame->SwitchFrame.Rbp = (ULONGLONG)&ThreadFrame->TrapFrame; + ThreadFrame->SwitchFrame.Return = (ULONGLONG)RunThread; - /* Set thread stack */ + /* Set thread stack boundaries */ + Thread->InitialStack = (PVOID)&ThreadFrame->NpxFrame; Thread->KernelStack = &ThreadFrame->SwitchFrame; } + +/** + * Serves as the initial execution point for all threads after first context switch. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTASSEMBLY +XTAPI +VOID +KE::KThread::RunThread(VOID) +{ + /* Initialize execution context, adjust runlevel and dispatch the thread */ + __asm__ volatile("xorq %%rbx, %%rbx\n" + "xorq %%r10, %%r10\n" + "xorq %%r11, %%r11\n" + "xorq %%r12, %%r12\n" + "xorq %%r13, %%r13\n" + "xorq %%r14, %%r14\n" + "xorq %%r15, %%r15\n" + "xorq %%rbp, %%rbp\n" + "xorq %%rdi, %%rdi\n" + "xorq %%rsi, %%rsi\n" + "subq $32, %%rsp\n" + "movb $%c[RunLevel], %%cl\n" + "callq %P[LowerRunLevel]\n" + "addq $32, %%rsp\n" + "movq 8(%%rsp), %%rcx\n" + "movq 0(%%rsp), %%rdx\n" + "movq 24(%%rsp), %%rax\n" + "subq $32, %%rsp\n" + "callq *%%rax\n" + "addq $32, %%rsp\n" + "addq $40, %%rsp\n" + "ret\n" + : + : [RunLevel] "i" (APC_LEVEL), + [LowerRunLevel] "i" (KE::RunLevel::LowerRunLevel) + : "memory"); +} diff --git a/xtoskrnl/ke/amd64/proc.cc b/xtoskrnl/ke/amd64/proc.cc index 0c3a0f3..c5908d6 100644 --- a/xtoskrnl/ke/amd64/proc.cc +++ b/xtoskrnl/ke/amd64/proc.cc @@ -66,6 +66,21 @@ KE::Processor::GetCurrentThread(VOID) return (PKTHREAD)AR::CpuFunctions::ReadGSQuadWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread)); } +/** + * Retrieves the number of installed and enabled CPUs in the system. + * + * @return This routine returns the number of installed CPUs in the system. + * + * @since XT 1.0 + */ +XTAPI +ULONG +KE::Processor::GetInstalledCpus(VOID) +{ + /* Return number of installed CPUs */ + return InstalledCpus; +} + /** * Gets the processor block for the specified processor number. * @@ -122,6 +137,9 @@ KE::Processor::InitializeProcessorBlocks() /* Zero the array initially */ RTL::Memory::ZeroMemory(ProcessorBlocks, InstalledCpus * sizeof(PKPROCESSOR_BLOCK)); + /* Register the processor block for the BSP processor */ + KE::Processor::RegisterProcessorBlock(0, KE::Processor::GetCurrentProcessorBlock()); + /* Return success */ return STATUS_SUCCESS; } @@ -178,10 +196,20 @@ KE::Processor::RegisterProcessorBlock(ULONG CpuNumber, } /** - * Saves the current processor state. + * Restores the processor's architectural state from the provided context frame back into the hardware trap + * and exception frames. * - * @param State - * Supplies a pointer to the processor state structure. + * @param TrapFrame + * Supplies a pointer to the trap frame that will receive the volatile processor state and control registers. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame that will receive the non-volatile integer and FP registers. + * + * @param ContextFrame + * Supplies a pointer to the context frame containing the state to be restored. + * + * @param ContextFlags + * Supplies a bitmask indicating which specific register groups should be restored from the ContextFrame. * * @return This routine does not return any value. * @@ -189,7 +217,223 @@ KE::Processor::RegisterProcessorBlock(ULONG CpuNumber, */ XTAPI VOID -KE::Processor::SaveProcessorState(OUT PKPROCESSOR_STATE CpuState) +KE::Processor::RestoreProcessorContext(IN OUT PKTRAP_FRAME TrapFrame, + IN OUT PKEXCEPTION_FRAME ExceptionFrame, + IN PCONTEXT ContextFrame, + IN ULONG ContextFlags) +{ + UNIMPLEMENTED; +} + +/** + * Restores the processor's low-level hardware control state. + * + * @param CpuState + * Supplies a pointer to the processor state block containing the previously saved control data. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::RestoreProcessorControlState(IN PKPROCESSOR_STATE CpuState) +{ + /* Restore the CR registers */ + AR::CpuFunctions::WriteControlRegister(0, CpuState->SpecialRegisters.Cr0); + AR::CpuFunctions::WriteControlRegister(2, CpuState->SpecialRegisters.Cr2); + AR::CpuFunctions::WriteControlRegister(3, CpuState->SpecialRegisters.Cr3); + AR::CpuFunctions::WriteControlRegister(4, CpuState->SpecialRegisters.Cr4); + AR::CpuFunctions::WriteControlRegister(8, CpuState->SpecialRegisters.Cr8); + + /* Restore the DR registers */ + AR::CpuFunctions::WriteDebugRegister(0, CpuState->SpecialRegisters.KernelDr0); + AR::CpuFunctions::WriteDebugRegister(1, CpuState->SpecialRegisters.KernelDr1); + AR::CpuFunctions::WriteDebugRegister(2, CpuState->SpecialRegisters.KernelDr2); + AR::CpuFunctions::WriteDebugRegister(3, CpuState->SpecialRegisters.KernelDr3); + AR::CpuFunctions::WriteDebugRegister(6, CpuState->SpecialRegisters.KernelDr6); + AR::CpuFunctions::WriteDebugRegister(7, CpuState->SpecialRegisters.KernelDr7); + + /* Restore MSR registers */ + AR::CpuFunctions::WriteModelSpecificRegister(X86_MSR_GSBASE, CpuState->SpecialRegisters.MsrGsBase); + AR::CpuFunctions::WriteModelSpecificRegister(X86_MSR_KERNEL_GSBASE, CpuState->SpecialRegisters.MsrGsSwap); + AR::CpuFunctions::WriteModelSpecificRegister(X86_MSR_CSTAR, CpuState->SpecialRegisters.MsrCStar); + AR::CpuFunctions::WriteModelSpecificRegister(X86_MSR_LSTAR, CpuState->SpecialRegisters.MsrLStar); + AR::CpuFunctions::WriteModelSpecificRegister(X86_MSR_STAR, CpuState->SpecialRegisters.MsrStar); + AR::CpuFunctions::WriteModelSpecificRegister(X86_MSR_FMASK, CpuState->SpecialRegisters.MsrSyscallMask); + + /* Restore XMM control/status register */ + AR::CpuFunctions::LoadMxcsrRegister(CpuState->SpecialRegisters.MxCsr); + + /* Restore GDT, IDT and LDT */ + AR::CpuFunctions::LoadGlobalDescriptorTable(&CpuState->SpecialRegisters.Gdtr.Limit); + AR::CpuFunctions::LoadInterruptDescriptorTable(&CpuState->SpecialRegisters.Idtr.Limit); + AR::CpuFunctions::LoadLocalDescriptorTable(CpuState->SpecialRegisters.Ldtr); + + /* Force the TSS descriptor into a non-busy state and restore TaskRegister */ + *(VOLATILE PUCHAR)((ULONG_PTR)CpuState->SpecialRegisters.Gdtr.Base + CpuState->SpecialRegisters.Tr + 5) &= ~0x02; + AR::CpuFunctions::LoadTaskRegister(CpuState->SpecialRegisters.Tr); +} + +/** + * Restores the executing processor's state. + * + * @param TrapFrame + * Supplies a pointer to the hardware trap frame that will be populated with the restored volatile state. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame that will be populated with the restored non-volatile state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::RestoreProcessorState(OUT PKTRAP_FRAME TrapFrame, + OUT PKEXCEPTION_FRAME ExceptionFrame) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Retrieve current processor control block */ + Prcb = GetCurrentProcessorControlBlock(); + + /* Restore processor context */ + RestoreProcessorContext(TrapFrame, ExceptionFrame, &Prcb->ProcessorState.ContextFrame, CONTEXT_ALL); + + /* Restore processor control registers */ + RestoreProcessorControlState(&Prcb->ProcessorState); +} + +/** + * Constructs a standardized processor context from the hardware trap and exception frames. + * + * @param TrapFrame + * Supplies a pointer to the trap frame containing volatile processor state, control registers and debug + * registers saved at the time of the interrupt or exception. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame containing non-volatile integer and floating-point registers. + * + * @param ContextFrame + * Supplies a pointer to the context frame that will receive the processor state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::SaveProcessorContext(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PCONTEXT ContextFrame) +{ + /* Elevate RunLevel to APC_LEVEL to prevent thread preemption */ + KE::RaiseRunLevel RunLevel(APC_LEVEL); + + /* Check if control registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_CONTROL) + { + /* Copy instruction pointer, stack pointer, and CPU status flags */ + ContextFrame->Flags = TrapFrame->Flags; + ContextFrame->Rbp = TrapFrame->Rbp; + ContextFrame->Rip = TrapFrame->Rip; + ContextFrame->Rsp = TrapFrame->Rsp; + ContextFrame->SegCs = TrapFrame->SegCs; + ContextFrame->SegSs = TrapFrame->SegSs; + } + + /* Check if general-purpose integer registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_INTEGER) + { + /* Copy volatile integer registers directly from the trap frame */ + ContextFrame->Rax = TrapFrame->Rax; + ContextFrame->Rcx = TrapFrame->Rcx; + ContextFrame->Rdx = TrapFrame->Rdx; + ContextFrame->R8 = TrapFrame->R8; + ContextFrame->R9 = TrapFrame->R9; + ContextFrame->R10 = TrapFrame->R10; + ContextFrame->R11 = TrapFrame->R11; + + /* Check if a valid exception frame was provided */ + if(ExceptionFrame) + { + /* Copy non-volatile integer registers from the exception frame */ + ContextFrame->Rbx = ExceptionFrame->Rbx; + ContextFrame->R12 = ExceptionFrame->R12; + ContextFrame->R13 = ExceptionFrame->R13; + ContextFrame->R14 = ExceptionFrame->R14; + ContextFrame->R15 = ExceptionFrame->R15; + ContextFrame->Rdi = ExceptionFrame->Rdi; + ContextFrame->Rsi = ExceptionFrame->Rsi; + } + } + + /* Check if segment registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_SEGMENTS) + { + /* Populate segment selectors with standard Ring 3 values */ + ContextFrame->SegDs = KGDT_R3_DATA | RPL_MASK; + ContextFrame->SegEs = KGDT_R3_DATA | RPL_MASK; + ContextFrame->SegFs = KGDT_R3_CMTEB | RPL_MASK; + ContextFrame->SegGs = KGDT_R3_DATA | RPL_MASK; + } + + /* Check if floating-point registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_FLOATING_POINT) + { + /* Copy the SSE control/status register and volatile XMM registers */ + ContextFrame->MxCsr = TrapFrame->MxCsr; + ContextFrame->Xmm0 = TrapFrame->Xmm0; + ContextFrame->Xmm1 = TrapFrame->Xmm1; + ContextFrame->Xmm2 = TrapFrame->Xmm2; + ContextFrame->Xmm3 = TrapFrame->Xmm3; + ContextFrame->Xmm4 = TrapFrame->Xmm4; + ContextFrame->Xmm5 = TrapFrame->Xmm5; + + /* Check if a valid exception frame was provided */ + if(ExceptionFrame) + { + /* Copy non-volatile XMM registers from the exception frame */ + ContextFrame->Xmm6 = ExceptionFrame->Xmm6; + ContextFrame->Xmm7 = ExceptionFrame->Xmm7; + ContextFrame->Xmm8 = ExceptionFrame->Xmm8; + ContextFrame->Xmm9 = ExceptionFrame->Xmm9; + ContextFrame->Xmm10 = ExceptionFrame->Xmm10; + ContextFrame->Xmm11 = ExceptionFrame->Xmm11; + ContextFrame->Xmm12 = ExceptionFrame->Xmm12; + ContextFrame->Xmm13 = ExceptionFrame->Xmm13; + ContextFrame->Xmm14 = ExceptionFrame->Xmm14; + ContextFrame->Xmm15 = ExceptionFrame->Xmm15; + } + } + + /* Check if debug registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_DEBUG_REGISTERS) + { + /* Copy debug registers */ + ContextFrame->Dr0 = TrapFrame->Dr0; + ContextFrame->Dr1 = TrapFrame->Dr1; + ContextFrame->Dr2 = TrapFrame->Dr2; + ContextFrame->Dr3 = TrapFrame->Dr3; + ContextFrame->Dr6 = TrapFrame->Dr6; + ContextFrame->Dr7 = TrapFrame->Dr7; + } +} + +/** + * Saves the current processor's low-level hardware control state. + * + * @param State + * Supplies a pointer to the processor state block that will receive processor's control data. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::SaveProcessorControlState(OUT PKPROCESSOR_STATE CpuState) { /* Save CR registers */ CpuState->SpecialRegisters.Cr0 = AR::CpuFunctions::ReadControlRegister(0); @@ -223,3 +467,36 @@ KE::Processor::SaveProcessorState(OUT PKPROCESSOR_STATE CpuState) AR::CpuFunctions::StoreLocalDescriptorTable(&CpuState->SpecialRegisters.Ldtr); AR::CpuFunctions::StoreTaskRegister(&CpuState->SpecialRegisters.Tr); } + +/** + * Captures the executing processor's state. + * + * @param TrapFrame + * Supplies a pointer to the hardware trap frame containing the processor's volatile state. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame containing the processor's non-volatile state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::SaveProcessorState(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Retrieve current processor control block */ + Prcb = GetCurrentProcessorControlBlock(); + + /* Set context flags to save whole all context */ + Prcb->ProcessorState.ContextFrame.ContextFlags = CONTEXT_ALL; + + /* Save processor context */ + SaveProcessorContext(TrapFrame, ExceptionFrame, &Prcb->ProcessorState.ContextFrame); + + /* Save processor control registers */ + SaveProcessorControlState(&Prcb->ProcessorState); +} diff --git a/xtoskrnl/ke/apc.cc b/xtoskrnl/ke/apc.cc index 1969d5c..16320dc 100644 --- a/xtoskrnl/ke/apc.cc +++ b/xtoskrnl/ke/apc.cc @@ -4,11 +4,99 @@ * FILE: xtoskrnl/ke/apc.cc * DESCRIPTION: Kernel APC objects support * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #include +/** + * Checks if a kernel APC can be delivered and initiates the delivery process. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Apc::CheckApcDelivery(VOID) +{ + PKTHREAD Thread; + + /* Check if system is running at PASSIVE level */ + if(KE::RunLevel::GetCurrentRunLevel() == PASSIVE_LEVEL) + { + /* Raise runlevel to APC level */ + KE::RaiseRunLevel RunLevel(APC_LEVEL); + + /* Deliver the APC */ + DeliverApc(KernelMode, NULLPTR, NULLPTR); + } + else + { + /* Mark the current thread as having a pending kernel APC */ + Thread = KE::Processor::GetCurrentThread(); + Thread->ApcState.KernelApcPending = TRUE; + + /* Request an APC software interrupt */ + HL::Irq::SendSoftwareInterrupt(APC_LEVEL); + } +} + +/** + * Delivers pending Asynchronous Procedure Calls (APCs) to the current executing thread. + * + * @param ProcessorMode + * Supplies the processor execution mode at the time the APC delivery was requested. + * + * @param ExceptionFrame + * Supplies an optional pointer to the exception frame if the APC is being delivered following an exception. + * + * @param TrapFrame + * Supplies an optional pointer to the trap frame if the APC is being delivered following an interrupt. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Apc::DeliverApc(IN KPROCESSOR_MODE ProcessorMode, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame) +{ + PKTHREAD Thread; + + UNIMPLEMENTED; + + /* Get the current thread */ + Thread = KE::Processor::GetCurrentThread(); + + /* Clear the pending kernel APC flag */ + Thread->ApcState.KernelApcPending = FALSE; +} + +/** + * Handles the Asynchronous Procedure Call (APC) interrupt. + * + * @param TrapFrame + * Supplies a pointer to the hardware trap frame representing the interrupted context. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +KE::Apc::HandleApcInterrupt(IN PKTRAP_FRAME TrapFrame) +{ + /* Raise runlevel to APC level */ + KE::RaiseRunLevel RunLevel(APC_LEVEL); + + /* Deliver the APC */ + DeliverApc(TrapFrame->PreviousMode, NULLPTR, TrapFrame); +} + /** * Initializes an APC object. * @@ -28,7 +116,7 @@ * Supplies a pointer to routine called on thread exit. * * @param NormalRoutine - * Supplies a pointer to routine called at IRQL 0. + * Supplies a pointer to routine called at PASSIVE_LEVEL. * * @param ApcMode * Specifies processor mode, in which NormalRoutine gets called. diff --git a/xtoskrnl/ke/crash.cc b/xtoskrnl/ke/crash.cc index 16cfdd9..3e9da6b 100644 --- a/xtoskrnl/ke/crash.cc +++ b/xtoskrnl/ke/crash.cc @@ -4,11 +4,234 @@ * FILE: xtoskrnl/ke/panic.cc * DESCRIPTION: System shutdown and kernel panic mechanism * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #include +/** + * Freezes the execution of the current processor during a fatal system crash or an interactive debugging session. + * + * @param TrapFrame + * Supplies an optional pointer to the trap frame captured at the moment the IPI_FREEZE was delivered. + * + * @param ExceptionFrame + * Supplies an optional pointer to the exception frame containing the non-volatile processor state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Crash::FreezeCurrentExecution(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame) +{ + KCONTINUE_STATUS ContinueStatus; + PKPROCESSOR_CONTROL_BLOCK Prcb; + BOOLEAN Interrupts; + + /* Check whether interrupts are enabled */ + Interrupts = AR::CpuFunctions::InterruptsEnabled(); + + /* Disable interrupts */ + AR::CpuFunctions::ClearInterruptFlag(); + + /* Start a guarded code block */ + { + /* Raise runlevel to HIGH level */ + KE::RaiseRunLevel RunLevel(HIGH_LEVEL); + + /* Get the processor control block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Verify that this core was genuinely requested to freeze */ + if(Prcb->IpiFrozen != IPI_FROZEN_STATE_FREEZE) + { + /* Spurious call or already thawed, return */ + return; + } + + /* Acknowledge the freeze request to the initiator */ + Prcb->IpiFrozen = IPI_FROZEN_STATE_FROZEN; + + /* Check if there is a valid trap frame to save the context */ + if(TrapFrame != NULLPTR) + { + /* Capture the processor state */ + KE::Processor::SaveProcessorState(TrapFrame, ExceptionFrame); + } + + /* Enter the stateless polling loop */ + while(Prcb->IpiFrozen != IPI_FROZEN_STATE_THAW) + { + /* Check for debugger processor switch */ + if(Prcb->IpiFrozen & IPI_FROZEN_STATE_ACTIVE) + { + /* Let the CPU enter the debugger as the active processor */ + ContinueStatus = KD::Debugger::SwitchProcessor(); + + /* Set the state back to passively frozen */ + Prcb->IpiFrozen = IPI_FROZEN_STATE_FROZEN; + + /* Check if the status is ContinueSuccess */ + if(ContinueStatus == ContinueSuccess) + { + /* Release the freeze owner to globally resume system execution */ + FreezeOwner->IpiFrozen = IPI_FROZEN_STATE_THAW; + } + } + + /* Mitigate spin-lock starvation and enforce memory coherence */ + AR::CpuFunctions::YieldProcessor(); + AR::CpuFunctions::MemoryBarrier(); + } + + /* Thaw signal received, check if there is a need to restore context */ + if(TrapFrame != NULLPTR) + { + /* Restore the processor state */ + KE::Processor::RestoreProcessorState(TrapFrame, ExceptionFrame); + } + + /* Acknowledge the thaw and mark the processor as fully operational */ + Prcb->IpiFrozen = IPI_FROZEN_STATE_RUNNING; + + /* Flush the Translation Lookaside Buffer (TLB) */ + AR::CpuFunctions::FlushTlb(); + } + + /* Check whether interrupts need to be re-enabled */ + if(Interrupts) + { + /* Re-enable interrupts */ + AR::CpuFunctions::SetInterruptFlag(); + } +} + +/** + * Asserts control over the entire system by freezing all other executing processors. + * + * @param TrapFrame + * Supplies a pointer to the trap frame of the initiating processor. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame of the initiating processor. + * + * @return This routine returns the interrupt state prior to the freeze execution. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +KE::Crash::FreezeExecution(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame) +{ + PKPROCESSOR_BLOCK ProcessorBlock; + PKPROCESSOR_CONTROL_BLOCK Prcb; + KRUNLEVEL OldRunLevel; + ULONG CpuCount, Index; + BOOLEAN Interrupts; + + /* Check whether interrupts are enabled */ + Interrupts = AR::CpuFunctions::InterruptsEnabled(); + + /* Disable interrupts */ + AR::CpuFunctions::ClearInterruptFlag(); + + /* Raise runlevel to HIGH level */ + OldRunLevel = KE::RunLevel::RaiseRunLevel(HIGH_LEVEL); + + /* Get processor control block for the executing core */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Check if CPU already owns the freeze */ + if(FreezeOwner == Prcb && Prcb->IpiFrozen == IPI_FROZEN_STATE_OWNER) + { + /* Freeze already owned, return interrupt state */ + return Interrupts; + } + + /* Attempt to establish ownership of the freeze */ + while(RTL::Atomic::CompareExchangePointer((PVOID*)&FreezeOwner, NULLPTR, Prcb)) + { + /* Freeze owned by another processor, spin until the lock is released */ + while(FreezeOwner != NULLPTR) + { + /* Check whether interrupts need to be re-enabled */ + if(Interrupts) + { + /* Re-enable interrupts */ + AR::CpuFunctions::SetInterruptFlag(); + } + + /* Process pending IPIs */ + KE::Ipi::HandleIpiService(TrapFrame, ExceptionFrame); + + /* Disable interrupts */ + AR::CpuFunctions::ClearInterruptFlag(); + } + } + + /* Re-fetch the processor control block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Set the freeze state */ + Prcb->IpiFrozen = IPI_FROZEN_STATE_OWNER | IPI_FROZEN_STATE_ACTIVE; + + /* Get the number of installed CPUs */ + CpuCount = KE::Processor::GetInstalledCpus(); + + /* Iterate over all installed CPUs */ + for(Index = 0; Index < CpuCount; Index++) + { + /* Get the processor block for next CPU */ + ProcessorBlock = KE::Processor::GetProcessorBlock(Index); + + /* Check if the processor block exists and the processor is running */ + if(ProcessorBlock != NULLPTR && ProcessorBlock->Started) + { + /* Do not freeze ourselves */ + if(ProcessorBlock->Prcb.CpuNumber != Prcb->CpuNumber) + { + /* Request the target processor to freeze execution */ + ProcessorBlock->Prcb.IpiFrozen = IPI_FROZEN_STATE_FREEZE; + } + } + } + + /* Broadcast the freeze request to all other processors */ + KE::Ipi::SendBroadcastIpi(IPI_FREEZE, FALSE); + + /* Iterate over all installed CPUs to verify their frozen state */ + for(Index = 0; Index < CpuCount; Index++) + { + /* Get the processor block for next CPU */ + ProcessorBlock = KE::Processor::GetProcessorBlock(Index); + + /* Check if the processor block exists and the processor is running */ + if(ProcessorBlock != NULLPTR && ProcessorBlock->Started) + { + /* Do not wait for ourselves */ + if(ProcessorBlock->Prcb.CpuNumber != Prcb->CpuNumber) + { + /* Wait for the target processor to acknowledge the freeze */ + while(ProcessorBlock->Prcb.IpiFrozen != IPI_FROZEN_STATE_FROZEN) + { + /* Mitigate spin-lock starvation */ + AR::CpuFunctions::YieldProcessor(); + AR::CpuFunctions::MemoryBarrier(); + } + } + } + } + + /* Save original runlevel and return the original interrupt state */ + RunLevel = OldRunLevel; + return Interrupts; +} + /** * Halts the system. * @@ -43,6 +266,7 @@ XTAPI VOID KE::Crash::Panic(IN ULONG Code) { + /* Call panic function */ Panic(Code, 0, 0, 0, 0); } @@ -76,7 +300,115 @@ KE::Crash::Panic(IN ULONG Code, IN ULONG_PTR Parameter3, IN ULONG_PTR Parameter4) { + /* Set kernel panic state */ + KernelPanic = TRUE; + + /* Broadcast IPI_FREEZE to all other processors */ + FreezeExecution(NULLPTR, NULLPTR); + + /* Print error message to debug console */ KD::DebugIo::KdPrint(L"Fatal System Error: 0x%08lx (0x%zx 0x%zx 0x%zx 0x%zx)\nKernel Panic!\n\n", Code, Parameter1, Parameter2, Parameter3, Parameter4); + + /* Halt system */ HaltSystem(); } + +/** + * Determines whether the system has experienced a fatal error and entered a kernel panic state. + * + * @return This routine returns TRUE if the system has halted due to a kernel panic, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +KE::Crash::SystemCrashed(VOID) +{ + /* Return kernel panic state */ + return KernelPanic; +} + +/** + * Resumes execution of the entire system following a system freeze or an interactive debugging session. + * + * @param Interrupts + * Supplies the original interrupt state captured prior to the freeze. + * This determines if local interrupts should be re-enabled. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Crash::ThawExecution(IN BOOLEAN Interrupts) +{ + PKPROCESSOR_BLOCK ProcessorBlock; + PKPROCESSOR_CONTROL_BLOCK Prcb; + ULONG CpuCount, Index; + + /* Get the processor control block and available CPU count */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + CpuCount = KE::Processor::GetInstalledCpus(); + + /* Mark the freeze owner processor as running */ + Prcb->IpiFrozen = IPI_FROZEN_STATE_RUNNING; + + /* Iterate over all CPUs to signal them to thaw */ + for(Index = 0; Index < CpuCount; Index++) + { + /* Get the processor block for the next CPU */ + ProcessorBlock = KE::Processor::GetProcessorBlock(Index); + + /* Check if the processor block exists and the processor is running */ + if(ProcessorBlock != NULLPTR && ProcessorBlock->Started) + { + /* Do not thaw ourselves */ + if(ProcessorBlock->Prcb.CpuNumber != Prcb->CpuNumber) + { + /* Request the target processor to thaw execution */ + ProcessorBlock->Prcb.IpiFrozen = IPI_FROZEN_STATE_THAW; + } + } + } + + /* Iterate over all installed CPUs to verify they have resumed */ + for(Index = 0; Index < CpuCount; Index++) + { + /* Get the processor block for the next CPU */ + ProcessorBlock = KE::Processor::GetProcessorBlock(Index); + + /* Check if the processor block exists and the processor is running */ + if(ProcessorBlock != NULLPTR && ProcessorBlock->Started) + { + /* Do not wait for ourselves */ + if(ProcessorBlock->Prcb.CpuNumber != Prcb->CpuNumber) + { + /* Wait for the target processor to acknowledge it is running */ + while(ProcessorBlock->Prcb.IpiFrozen != IPI_FROZEN_STATE_RUNNING) + { + /* Mitigate spin-lock starvation */ + AR::CpuFunctions::YieldProcessor(); + AR::CpuFunctions::MemoryBarrier(); + } + } + } + } + + /* Release the global freeze owner lock */ + RTL::Atomic::ExchangePointer((PVOID *)&FreezeOwner, NULLPTR); + + /* Flush the Translation Lookaside Buffer (TLB) */ + AR::CpuFunctions::FlushTlb(); + + /* Restore the original runlevel from before the freeze */ + KE::RunLevel::LowerRunLevel(RunLevel); + + /* Check whether interrupts need to be re-enabled */ + if(Interrupts) + { + /* Re-enable interrupts */ + AR::CpuFunctions::SetInterruptFlag(); + } +} diff --git a/xtoskrnl/ke/data.cc b/xtoskrnl/ke/data.cc index 9ae23c1..a239204 100644 --- a/xtoskrnl/ke/data.cc +++ b/xtoskrnl/ke/data.cc @@ -12,6 +12,15 @@ /* Kernel initialization block passed by boot loader */ PKERNEL_INITIALIZATION_BLOCK KE::BootInformation::InitializationBlock = {}; +/* Processor control block belonging to the freeze owner */ +PKPROCESSOR_CONTROL_BLOCK KE::Crash::FreezeOwner; + +/* Kernel panic state */ +BOOLEAN KE::Crash::KernelPanic; + +/* System runlevel before execution freeze */ +KRUNLEVEL KE::Crash::RunLevel; + /* Kernel initial process */ EPROCESS KE::KProcess::InitialProcess; @@ -95,3 +104,6 @@ LONG KE::SystemTime::TickOffset; /* The runtime adjustment value applied to the system clock at each interrupt */ ULONG KE::SystemTime::TimeAdjustment; + +/* Kernel timer table containing a list of active timers */ +LIST_ENTRY KE::Timer::TimerTableListHead[KTIMER_TABLE_SIZE]; diff --git a/xtoskrnl/ke/dispatch.cc b/xtoskrnl/ke/dispatch.cc index df464aa..0e6161a 100644 --- a/xtoskrnl/ke/dispatch.cc +++ b/xtoskrnl/ke/dispatch.cc @@ -4,11 +4,121 @@ * FILE: xtoskrnl/ke/dispatch.cc * DESCRIPTION: Kernel Thread Dispatcher * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #include +/** + * Calculates the remaining wait interval for a thread after a wait operation has been interrupted. + * + * @param OriginalDueTime + * Supplies the original timeout value requested by the caller. + * + * @param PreviousDueTime + * Supplies the base timestamp, usually the time when the wait was first initiated. + * + * @param NewDueTime + * Supplies a pointer to a LARGE_INTEGER buffer where the recalculated time will be stored. + * + * @return This routine returns a pointer to the resulting due time. + * + * @since XT 1.0 + */ +XTFASTCALL +PLARGE_INTEGER +KE::Dispatcher::ComputeWaitInterval(IN PLARGE_INTEGER OriginalDueTime, + IN PLARGE_INTEGER PreviousDueTime, + IN OUT PLARGE_INTEGER NewDueTime) +{ + /* Check if the timeout is absolute */ + if(OriginalDueTime->QuadPart >= 0) + { + /* No recalculation is needed, return the original value */ + return OriginalDueTime; + } + + /* Fetch the current system interrupt time for the recalculation base */ + KE::SystemTime::GetInterruptTime(NewDueTime); + + /* Calculate the delta */ + NewDueTime->QuadPart -= PreviousDueTime->QuadPart; + + /* Return the new due time */ + return NewDueTime; +} + +/** + * Enters the system idle thread loop for the current processor, running continuously when no other + * threads are scheduled for execution. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Dispatcher::EnterIdleLoop(VOID) +{ + PKTHREAD CurrentThread, NextThread; + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Retrieve the processor control block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Enter the infinite idle loop */ + while(TRUE) + { + /* Temporarily enable interrupts and yield the processor to handle pending hardware events */ + AR::CpuFunctions::SetInterruptFlag(); + AR::CpuFunctions::YieldProcessor(); + AR::CpuFunctions::YieldProcessor(); + AR::CpuFunctions::ClearInterruptFlag(); + + /* Check for pending deferred ready threads, DPCs, or timer requests */ + if(Prcb->DeferredReadyListHead.Next || + Prcb->DpcData[0].DpcQueueDepth || + Prcb->TimerRequest) + { + /* Unimplemented path */ + UNIMPLEMENTED; + } + + /* Check if a new thread has been scheduled for execution */ + if(Prcb->NextThread) + { + /* Enable interrupts to allow hardware events during context switch preparation */ + AR::CpuFunctions::SetInterruptFlag(); + + /* Capture the current and next thread pointers */ + CurrentThread = Prcb->CurrentThread; + NextThread = Prcb->NextThread; + + /* Update the processor control block with the incoming thread */ + Prcb->NextThread = NULLPTR; + Prcb->CurrentThread = NextThread; + + /* Transition the incoming thread to the running state */ + NextThread->State = Running; + + /* Start a guarded code block */ + { + /* Raise runlevel to SYNC level */ + KE::RaiseRunLevel RunLevel(SYNC_LEVEL); + + /* Perform the context switch away from the idle thread */ + KE::Dispatcher::SwitchContext(CurrentThread, APC_LEVEL); + } + } + else + { + /* No threads scheduled, enter a low-power processor state and wait for interrupts */ + Prcb->PowerState.IdleFunction(&Prcb->PowerState); + } + } +} + /** * Exits the dispatcher, switches context to a new thread and lowers runlevel to its original state. * @@ -29,6 +139,135 @@ KE::Dispatcher::ExitDispatcher(IN KRUNLEVEL OldRunLevel) RunLevel::LowerRunLevel(OldRunLevel); } +/** + * Handles the dispatch interrupt by retiring pending DPCs, asking the scheduler for the next runnable thread + * and performing the context switch. + * + * @param TrapFrame + * Supplies a pointer to the hardware trap frame representing the interrupted context. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +KE::Dispatcher::HandleDispatchInterrupt(IN PKTRAP_FRAME TrapFrame) +{ + PKTHREAD CurrentThread, NextThread; + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Receive the Processor Control Block*/ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Raise runlevel to DISPATCH level */ + KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); + + /* End the interrupt */ + HL::Pic::SendEoi(); + + /* Check if there is pending deferred work */ + if(Prcb->DeferredReadyListHead.Next || + Prcb->DpcData[0].DpcQueueDepth || + Prcb->TimerRequest) + { + UNIMPLEMENTED; + } + + /* Re-enable hardware interrupts */ + AR::CpuFunctions::SetInterruptFlag(); + + /* Check if the current thread has exhausted its execution quantum */ + if((Prcb->CurrentThread->Quantum <= 0) && (Prcb->CurrentThread != Prcb->IdleThread)) + { + /* Trigger the scheduler to recalculate thread parameters */ + KE::Scheduler::ProcessQuantumEnd(); + } + else if(Prcb->NextThread) + { + /* Start a guarded code block */ + { + /* Lock the processor control block */ + KE::SpinLockGuard PrcbGuard(&Prcb->PrcbLock); + + /* Capture the outgoing (preempted) and incoming threads */ + CurrentThread = Prcb->CurrentThread; + NextThread = Prcb->NextThread; + + /* Acknowledge the pending thread and swap the pointers */ + Prcb->NextThread = NULLPTR; + Prcb->CurrentThread = NextThread; + + /* Update scheduling states */ + NextThread->State = Running; + CurrentThread->WaitReason = WrDispatchInt; + + /* Re-queue the preempted thread back into the local run queue or defer it */ + KE::Scheduler::QueueReadyThread(CurrentThread, Prcb); + } + + /* Perform the context switch */ + SwitchContext(CurrentThread, APC_LEVEL); + } + + /* Disable hardware interrupts before returning from the handler */ + AR::CpuFunctions::ClearInterruptFlag(); +} + + +/** + * Evaluates the state of a dispatcher object to determine if a wait can be satisfied immediately without + * suspending the current thread. + * + * @param Object + * Supplies a pointer to the dispatcher object header. + * + * @param Thread + * Supplies a pointer to the current thread attempting to acquire the object. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTFASTCALL +XTSTATUS +KE::Dispatcher::SatisfyWaitingObject(IN PDISPATCHER_HEADER Object, + IN PKTHREAD Thread) +{ + PKMUTEX Mutex; + + /* Check if the object is a Mutex */ + if(Object->Type == MutexObject) + { + /* Get a pointer to the Mutex object */ + Mutex = (PKMUTEX)Object; + + /* Check if the mutex is free or if the current thread already owns it */ + if((Mutex->Header.SignalState > 0) || (Thread == Mutex->OwnerThread)) + { + /* Verify that recursive acquisition has not hit the mathematical lower bound */ + if(Mutex->Header.SignalState != MINLONG) + { + /* Satisfy the wait and inherit priority if applicable */ + KE::DispatcherObject::SatisfyWaitingMutexObject(Mutex, Thread); + return (XTSTATUS)Thread->WaitStatus; + } + + /* The mutex counter has overflowed */ + return STATUS_MUTEX_LIMIT_EXCEEDED; + } + } + else if(Object->SignalState > 0) + { + /* Apply generic satisfaction rules */ + KE::DispatcherObject::SatisfyWaitingNonMutexObject(Object); + return STATUS_WAIT_0; + } + + /* Object is not signaled, the thread must be queued */ + return STATUS_PENDING; +} + /** * Updates the runtime quantum of the currently executing thread and handles preemption. * @@ -47,4 +286,181 @@ VOID KE::Dispatcher::UpdateRunTime(IN PKTRAP_FRAME TrapFrame, IN KRUNLEVEL RunLevel) { + PKPROCESSOR_CONTROL_BLOCK ControlBlock; + PKTHREAD Thread; + + /* Retrieve current processor control block and current thread */ + ControlBlock = KE::Processor::GetCurrentProcessorControlBlock(); + Thread = KE::Processor::GetCurrentThread(); + + /* Increment interrupt count */ + ControlBlock->InterruptCount++; + + /* Check if the thread ran in user mode */ + if(TrapFrame->PreviousMode == UserMode) + { + /* Atomically increment the process-wide user time */ + RTL::Atomic::Increment32((PLONG)&Thread->ApcState.Process->UserTime); + + /* Increment thread and total time this processor has spent executing in user time */ + ControlBlock->UserTime++; + Thread->UserTime++; + } + else + { + /* Increment the total time this processor has spent executing in kernel mode */ + ControlBlock->KernelTime++; + + /* Check if normal kernel thread execution was interrupted */ + if((RunLevel < DISPATCH_LEVEL) || !(ControlBlock->DpcRoutineActive)) + { + /* Atomically increment the process-wide kernel time */ + RTL::Atomic::Increment32((PLONG)&Thread->ApcState.Process->KernelTime); + + /* Increment the kernel execution time for the current thread */ + Thread->KernelTime++; + } + else if(RunLevel > DISPATCH_LEVEL) + { + /* Increment the time spent servicing hardware interrupts */ + ControlBlock->InterruptTime++; + } + else + { + /* Increment the time spent servicing DPCs */ + ControlBlock->DpcTime++; + } + } + + /* Calculate the new DPC request rate as a moving average of the current and previous rates */ + ControlBlock->DpcRequestRate = ((ControlBlock->DpcData[0].DpcCount - ControlBlock->DpcLastCount) + + ControlBlock->DpcRequestRate) >> 1; + + /* Snapshot the current DPC count */ + ControlBlock->DpcLastCount = ControlBlock->DpcData[0].DpcCount; + + /* Check if there are pending DPCs, no DPC routine is currently executing, and DPC interrupt is not pending */ + if((ControlBlock->DpcData[0].DpcQueueDepth) && + !(ControlBlock->DpcRoutineActive) && + !(ControlBlock->DpcInterruptRequested)) + { + /* Reset the adjustment threshold counter */ + ControlBlock->AdjustDpcThreshold = DPC_ADJUST_THRESHOLD; + + /* Request a DISPATCH level software interrupt to process the pending DPCs */ + HL::Irq::SendSoftwareInterrupt(DISPATCH_LEVEL); + + /* Evaluate if the DPC request rate is below the ideal threshold */ + if((ControlBlock->DpcRequestRate < DPC_IDEAL_RATE) && (ControlBlock->MaximumDpcQueueDepth > 1)) + { + /* Decrease the maximum queue depth */ + ControlBlock->MaximumDpcQueueDepth--; + } + } + else + { + /* Decrement the tuning threshold counter and verify if an adjustment cycle is required */ + if(!(--ControlBlock->AdjustDpcThreshold)) + { + /* Reset the counter for the next tuning cycle */ + ControlBlock->AdjustDpcThreshold = DPC_ADJUST_THRESHOLD; + + /* Check if the current queue depth limit is below the system-wide absolute maximum */ + if(ControlBlock->MaximumDpcQueueDepth != DPC_MAXIMUM_QUEUE_DEPTH) + { + /* Increase the maximum queue depth to batch more DPCs */ + ControlBlock->MaximumDpcQueueDepth++; + } + } + } + + /* Decrement the execution time slice */ + Thread->Quantum -= CLOCK_QUANTUM_DECREMENT; + + /* Check if the thread has exhausted its quantum, ignoring the idle thread */ + if((Thread->Quantum <= 0) && (Thread != ControlBlock->IdleThread)) + { + /* Request a DISPATCH level software interrupt to preempt the thread */ + HL::Irq::SendSoftwareInterrupt(DISPATCH_LEVEL); + } +} + +/** + * Places the current thread into a wait state until the specified dispatcher object is set to a signaled state, + * or until the optional timeout expires. + * + * @param Object + * Supplies a pointer to the dispatcher object to wait on. + * + * @param WaitReason + * Supplies the reason for the wait, utilized for diagnostic and profiling purposes. + * + * @param WaitMode + * Supplies the processor mode in which the wait is occurring (KernelMode or UserMode). + * + * @param Alertable + * Specifies whether the wait is alertable by asynchronous procedure calls (APCs). + * + * @param Timeout + * Supplies an optional pointer to an absolute or relative timeout value. + * + * @return This routine returns the completion status of the wait operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +KE::Dispatcher::WaitForSingleObject(IN PVOID Object, + IN KWAIT_REASON WaitReason, + IN KPROCESSOR_MODE WaitMode, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout) +{ + PDISPATCHER_HEADER Header; + LARGE_INTEGER CurrentTime; + PKTHREAD CurrentThread; + + /* Not implemented, active polling only */ + UNIMPLEMENTED; + + /* Get the dispatcher header */ + Header = (PDISPATCHER_HEADER)Object; + + /* Get the current thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Check if the object is already signaled or if it is an already owned Mutex */ + if((Header->SignalState > 0) || ((Header->Type == MutexObject) && (CurrentThread == ((PKMUTEX)Object)->OwnerThread))) + { + /* Satisfy the object and return status code */ + SatisfyWaitingObject(Header, CurrentThread); + return STATUS_WAIT_0; + } + + /* Enter cctive polling loop */ + while(Header->SignalState <= 0) + { + /* Check if the timeout has expired */ + if(Timeout != NULLPTR) + { + /* Get the current interrupt time */ + KE::SystemTime::GetInterruptTime(&CurrentTime); + + /* Check if current time exceeds the timeout value */ + if(CurrentTime.QuadPart >= Timeout->QuadPart) + { + /* Wait expired, return status code */ + return STATUS_TIMEOUT; + } + } + + /* Yield the processor */ + AR::CpuFunctions::YieldProcessor(); + } + + /* Apply acquisition rules */ + SatisfyWaitingObject(Header, CurrentThread); + + /* Return status code */ + return STATUS_WAIT_0; } diff --git a/xtoskrnl/ke/dispobj.cc b/xtoskrnl/ke/dispobj.cc new file mode 100644 index 0000000..faf504d --- /dev/null +++ b/xtoskrnl/ke/dispobj.cc @@ -0,0 +1,113 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/dispobj.cc + * DESCRIPTION: Kernel Thread Dispatcher Objects + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Satisfies a wait operation specifically for a Mutex object. + * + * @param Mutex + * Supplies a pointer to the Mutex object being acquired. + * + * @param Thread + * Supplies a pointer to the thread that is acquiring the Mutex. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::DispatcherObject::SatisfyWaitingMutexObject(IN PKMUTEX Mutex, + IN PKTHREAD Thread) +{ + /* Decrement the signal state */ + Mutex->Header.SignalState--; + + /* Check if the mutex is now fully acquired */ + if(!Mutex->Header.SignalState) + { + /* Bind the mutex ownership to the current acquiring thread */ + Mutex->OwnerThread = Thread; + + /* Inherit the APC disable from the mutex */ + Thread->KernelApcDisable = Thread->KernelApcDisable - Mutex->ApcDisable; + + /* Check if the previous owner terminated without releasing the mutex */ + if(Mutex->Abandoned) + { + /* Clear the abandonment flag */ + Mutex->Abandoned = FALSE; + + /* Alert the thread */ + Thread->WaitStatus = STATUS_ABANDONED; + } + + /* Track this mutex in the thread's local list */ + RTL::LinkedList::InsertHeadList(Thread->MutexListHead.Blink, &Mutex->MutexListEntry); + } +} + +/** + * Satisfies a wait operation for non-mutex dispatcher objects, such as Synchronization Events and Semaphores. + * + * @param Object + * Supplies a pointer to the dispatcher object. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::DispatcherObject::SatisfyWaitingNonMutexObject(IN PDISPATCHER_HEADER Object) +{ + /* Check if the object is a Synchronization Event */ + if((Object->Type & DISPATCHER_OBJECT_TYPE_MASK) == EventSynchronizationObject) + { + /* Reset the event */ + Object->SignalState = 0; + } + else if(Object->Type == SemaphoreObject) + { + /* Decrement the signal state */ + Object->SignalState--; + } +} + +/** + * Evaluates the object type and routes the wait satisfaction logic to the appropriate specialized handler. + * + * @param Object + * Supplies a pointer to the dispatcher object being acquired. + * + * @param Thread + * Supplies a pointer to the thread acquiring the object. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::DispatcherObject::SatisfyWaitingObject(IN PDISPATCHER_HEADER Object, + IN PKTHREAD Thread) +{ + /* Check if the object is a Mutex */ + if(Object->Type == MutexObject) + { + /* Apply mutex-specific acquisition rules */ + SatisfyWaitingMutexObject((PKMUTEX)Object, Thread); + } + else + { + /* Apply generic acquisition rules for events, semaphores, and timers */ + SatisfyWaitingNonMutexObject(Object); + } +} diff --git a/xtoskrnl/ke/event.cc b/xtoskrnl/ke/event.cc index 83b4020..9e39d1c 100644 --- a/xtoskrnl/ke/event.cc +++ b/xtoskrnl/ke/event.cc @@ -83,3 +83,35 @@ KE::Event::SetEvent(IN PKEVENT Event, return 0; } + +/** + * Sets an event to the signaled state and attempts to boost the priority of the waiting thread. + * + * @param Event + * Supplies a pointer to the dispatcher object (Event) to be signaled. + * + * @param WaitingThread + * supplies an optional pointer to a variable that receives the unblocked thread. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Event::SetEventBoostPriority(IN PKEVENT Event, + IN OUT PKTHREAD* WaitingThread) +{ + /* Not implemented, active polling only */ + UNIMPLEMENTED; + + /* Set the signal state */ + Event->Header.SignalState = 1; + + /* Check if the caller requested the unblocked thread */ + if(WaitingThread != NULLPTR) + { + /* Return NULLPTR for now */ + *WaitingThread = NULLPTR; + } +} diff --git a/xtoskrnl/ke/i686/dispatch.cc b/xtoskrnl/ke/i686/dispatch.cc index b06e5cd..38e19c9 100644 --- a/xtoskrnl/ke/i686/dispatch.cc +++ b/xtoskrnl/ke/i686/dispatch.cc @@ -22,13 +22,12 @@ * * @since XT 1.0 */ +XTASSEMBLY XTFASTCALL BOOLEAN KE::Dispatcher::SwitchContext(IN PKTHREAD CurrentThread, IN KRUNLEVEL RunLevel) { - BOOLEAN PendingApc; - /* Save registers to the exception frame and invoke the stack switch routine */ __asm__ volatile("subl %[ExFrameSize], %%esp\n" "movl %%esi, %c[ExEsi](%%esp)\n" @@ -41,19 +40,15 @@ KE::Dispatcher::SwitchContext(IN PKTHREAD CurrentThread, "movl %c[ExEdi](%%esp), %%edi\n" "movl %c[ExEsi](%%esp), %%esi\n" "addl %[ExFrameSize], %%esp\n" - : "=a" (PendingApc) - : "c" (CurrentThread), - "d" (RunLevel), - [ExFrameSize] "i" (sizeof(KEXCEPTION_FRAME) - 4), + "ret\n" + : + : [ExFrameSize] "i" (sizeof(KEXCEPTION_FRAME) - 4), [ExEbp] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Ebp)), [ExEbx] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Ebx)), [ExEdi] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Edi)), [ExEsi] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Esi)), [SwitchRoutine] "i" (SwitchThreadStack) : "cc", "memory"); - - /* Return the APC status */ - return PendingApc; } /** @@ -92,13 +87,12 @@ KE::Dispatcher::SwitchThreadContext(IN PKTHREAD CurrentThread, * * @since XT 1.0 */ +XTASSEMBLY XTFASTCALL BOOLEAN KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread, IN KRUNLEVEL RunLevel) { - BOOLEAN PendingApc; - /* Save old state, synchronize with CPUs, switch stack and call the switch routine */ __asm__ volatile("subl %[FrameSize], %%esp\n" "movl %%fs:%c[PrcbcCurrentThread], %%ebx\n" @@ -116,19 +110,15 @@ KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread, "movzbl %c[SwApcBypass](%%esp), %%edx\n" "call %P[SwitchRoutine]\n" "addl %[FrameSize], %%esp\n" - : "=a" (PendingApc) - : "c" (CurrentThread), - "d" (RunLevel), - [FrameSize] "i" (sizeof(KSWITCH_FRAME) - 4), + "ret\n" + : + : [FrameSize] "i" (sizeof(KSWITCH_FRAME) - 4), [PrcbcCurrentThread] "i" (FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread)), - [SwApcBypass] "i" (FIELD_OFFSET(KSWITCH_FRAME, ApcBypassDisabled)), + [SwApcBypass] "i" (FIELD_OFFSET(KSWITCH_FRAME, ApcBypass)), [SwExceptionList] "i" (FIELD_OFFSET(KSWITCH_FRAME, ExceptionList)), [SwitchRoutine] "i" (SwitchThreadContext), [ThrdInfoExceptions] "i" (FIELD_OFFSET(THREAD_INFORMATION_BLOCK, ExceptionList)), [ThrdStack] "i" (FIELD_OFFSET(KTHREAD, KernelStack)), [ThrdSwapBusy] "i" (FIELD_OFFSET(KTHREAD, SwapBusy)) : "cc", "memory"); - - /* Return the APC status */ - return PendingApc; } diff --git a/xtoskrnl/ke/i686/krnlinit.cc b/xtoskrnl/ke/i686/krnlinit.cc index 7dd579b..7e6be4f 100644 --- a/xtoskrnl/ke/i686/krnlinit.cc +++ b/xtoskrnl/ke/i686/krnlinit.cc @@ -46,21 +46,30 @@ KE::KernelInit::BootstrapApplicationProcessor(IN PPROCESSOR_START_BLOCK StartBlo PO::Idle::InitializeProcessorIdleState(ControlBlock); /* Save processor state */ - KE::Processor::SaveProcessorState(&ControlBlock->ProcessorState); + KE::Processor::SaveProcessorControlState(&ControlBlock->ProcessorState); /* Initialize per-CPU spin lock queues */ KE::SpinLock::InitializeLockQueues(); + /* Initialize interrupt handlers */ + InitializeInterruptHandlers(); + /* Lower to APC runlevel */ KE::RunLevel::LowerRunLevel(APC_LEVEL); /* Initialize local clock for this CPU */ HL::Timer::InitializeLocalClock(); - /* Enter infinite loop */ - DebugPrint(L"KernelInit::BootstrapApplicationProcessor() finished for CPU #%lu. Entering infinite loop.\n", + /* Create and initialize IDLE thread */ + PS::Thread::CreateIdleThread(ControlBlock, StartBlock->Stack); + + /* Register DISPATCH interrupt handler */ + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_DPC, KE::Dispatcher::HandleDispatchInterrupt); + + /* Enter idle loop */ + DebugPrint(L"KernelInit::BootstrapApplicationProcessor() finished for CPU #%lu. Entering IDLE loop.\n", ControlBlock->CpuNumber); - KE::Crash::HaltSystem(); + KE::Dispatcher::EnterIdleLoop(); } /** @@ -76,62 +85,66 @@ VOID KE::KernelInit::BootstrapKernel(VOID) { PKPROCESSOR_CONTROL_BLOCK Prcb; - ULONG_PTR PageDirectory[2]; - PKPROCESS CurrentProcess; - PKTHREAD CurrentThread; - /* Get processor control block and current thread */ + /* Get processor control block */ Prcb = KE::Processor::GetCurrentProcessorControlBlock(); - CurrentThread = KE::Processor::GetCurrentThread(); - - /* Get current process */ - CurrentProcess = CurrentThread->ApcState.Process; /* Initialize CPU power state structures */ PO::Idle::InitializeProcessorIdleState(Prcb); /* Save processor state */ - KE::Processor::SaveProcessorState(&Prcb->ProcessorState); + KE::Processor::SaveProcessorControlState(&Prcb->ProcessorState); /* Initialize spin locks */ KE::SpinLock::InitializeAllLocks(); KE::SpinLock::InitializeLockQueues(); + /* Initialize interrupt handlers */ + InitializeInterruptHandlers(); + /* Lower to APC runlevel */ KE::RunLevel::LowerRunLevel(APC_LEVEL); /* Initialize XTOS kernel */ InitializeKernel(); - /* Initialize Idle process */ - PageDirectory[0] = 0; - PageDirectory[1] = 0; - KE::KProcess::InitializeProcess(CurrentProcess, 0, MAXULONG_PTR, PageDirectory, FALSE); - CurrentProcess->Quantum = MAXCHAR; - - /* Initialize Idle thread */ - KE::KThread::InitializeThread(CurrentProcess, CurrentThread, NULLPTR, NULLPTR, NULLPTR, - NULLPTR, NULLPTR, AR::ProcessorSupport::GetBootStack(), TRUE); - CurrentThread->NextProcessor = Prcb->CpuNumber; - CurrentThread->Priority = THREAD_HIGH_PRIORITY; - CurrentThread->State = Running; - CurrentThread->Affinity = (ULONG_PTR)1 << Prcb->CpuNumber; - CurrentThread->WaitRunLevel = DISPATCH_LEVEL; - CurrentProcess->ActiveProcessors |= (ULONG_PTR)1 << Prcb->CpuNumber; - /* Initialize Memory Manager */ MM::Manager::InitializeMemoryManager(); /* Enable shadow buffer for framebuffer */ HL::FrameBuffer::EnableShadowBuffer(); + /* Create and initialize IDLE process */ + PS::Process::CreateIdleProcess(Prcb); + /* Start all application processors */ KE::Processor::InitializeProcessorBlocks(); + HL::Cpu::InitializeProcessorAffinity(); HL::Cpu::StartAllProcessors(); - /* Enter infinite loop */ - DebugPrint(L"KernelInit::BootstrapKernel() finished. Entering infinite loop.\n"); - KE::Crash::HaltSystem(); + /* Register DISPATCH interrupt handler */ + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_DPC, KE::Dispatcher::HandleDispatchInterrupt); + + /* Enter idle loop */ + DebugPrint(L"KernelInit::BootstrapKernel() finished. Entering IDLE loop.\n"); + KE::Dispatcher::EnterIdleLoop(); +} + +/** + * Initializes and registers the core system interrupt handlers. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::KernelInit::InitializeInterruptHandlers(VOID) +{ + /* Register interrupt handlers */ + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_APC, KE::Apc::HandleApcInterrupt); + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_DPC, KE::Dispatcher::HandleDispatchInterrupt); + HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_IPI, KE::Ipi::HandleIpiInterrupt); } /** diff --git a/xtoskrnl/ke/i686/kthread.cc b/xtoskrnl/ke/i686/kthread.cc index b4a924c..ba6ff35 100644 --- a/xtoskrnl/ke/i686/kthread.cc +++ b/xtoskrnl/ke/i686/kthread.cc @@ -41,6 +41,7 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread, { PKTHREAD_INIT_FRAME ThreadFrame; PFX_SAVE_FORMAT FxSaveFormat; + CONTEXT ContextFrame; /* Set initial thread frame */ ThreadFrame = ((PKTHREAD_INIT_FRAME)Thread->InitialStack) - 1; @@ -51,31 +52,45 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread, /* Check if context provided for this thread */ if(ContextRecord) { - /* User mode thread needs further initialization, this is not completed */ - UNIMPLEMENTED; + /* Make a local copy of the context to avoid mutating caller's memory */ + RTL::Memory::CopyMemory(&ContextFrame, ContextRecord, sizeof(CONTEXT)); + + /* Disable debug registers and enable control and extended registers */ + ContextFrame.ContextFlags |= (CONTEXT_CONTROL | CONTEXT_EXTENDED_REGISTERS); + ContextFrame.ContextFlags &= ~CONTEXT_DEBUG_REGISTERS; /* Fill trap frame with zeroes */ RTL::Memory::ZeroMemory(&ThreadFrame->TrapFrame, sizeof(KTRAP_FRAME)); - /* Disable debug registers and enable context registers */ - ContextRecord->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS | CONTEXT_CONTROL; + /* Translate Context frame to Trap frame */ + KE::Processor::RestoreProcessorContext(&ThreadFrame->TrapFrame, NULLPTR, + &ContextFrame, ContextFrame.ContextFlags); /* This is user mode thread */ - ThreadFrame->StartFrame.UserMode = TRUE; Thread->PreviousMode = UserMode; + ThreadFrame->StartFrame.UserMode = TRUE; + ThreadFrame->TrapFrame.PreviousMode = UserMode; /* Disable coprocessor floating point state */ Thread->NpxState = NPX_STATE_UNLOADED; - Thread->Header.NpxIrql = PASSIVE_LEVEL; + Thread->NpxRunLevel = PASSIVE_LEVEL; /* Set initial floating point state */ FxSaveFormat = (PFX_SAVE_FORMAT)ContextRecord->ExtendedRegisters; FxSaveFormat->ControlWord = 0x27F; - FxSaveFormat->MxCsr = 0x1F80; - ContextRecord->FloatSave.Cr0NpxState = 0; + FxSaveFormat->DataOffset = 0; + FxSaveFormat->DataSelector = 0; + FxSaveFormat->ErrorOffset = 0; + FxSaveFormat->ErrorSelector = 0; + FxSaveFormat->StatusWord = 0; + FxSaveFormat->TagWord = 0; + ContextFrame.FloatSave.Cr0NpxState = 0; ThreadFrame->NpxFrame.Cr0NpxState = 0; ThreadFrame->NpxFrame.NpxSavedCpu = 0; + /* Set initial MXCSR register value */ + FxSaveFormat->MxCsr = 0x1F80; + /* Clear DR6 and DR7 registers */ ThreadFrame->TrapFrame.Dr6 = 0; ThreadFrame->TrapFrame.Dr7 = 0; @@ -85,14 +100,14 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread, ThreadFrame->TrapFrame.SegEs |= RPL_MASK; ThreadFrame->TrapFrame.SegSs |= RPL_MASK; - /* Set user mode thread in the trap frame */ - ThreadFrame->TrapFrame.PreviousMode = UserMode; + /* Set the routine that will handle the thread finishing its initialization and transition it to UserMode */ + ThreadFrame->StartFrame.Return = (ULONG)SwitchToUserMode; } else { /* This is kernel mode thread */ - ThreadFrame->StartFrame.UserMode = FALSE; Thread->PreviousMode = KernelMode; + ThreadFrame->StartFrame.UserMode = FALSE; /* Disable coprocessor floating point state */ Thread->NpxState = NPX_STATE_UNLOADED; @@ -100,17 +115,55 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread, /* Set initial floating point state */ ThreadFrame->NpxFrame.FxArea.ControlWord = 0x27F; ThreadFrame->NpxFrame.FxArea.MxCsr = 0x1F80; + + /* Set the routine that will handle a system thread that unexpectedly finished its execution */ + ThreadFrame->StartFrame.Return = (ULONG)HandleSystemThreadExit; } /* Initialize thread startup information */ - ThreadFrame->StartFrame.StartContext = StartContext; - ThreadFrame->StartFrame.StartRoutine = StartRoutine; - ThreadFrame->StartFrame.SystemRoutine = SystemRoutine; + ThreadFrame->StartFrame.P1Home = (ULONG)StartContext; + ThreadFrame->StartFrame.P2Home = (ULONG)StartRoutine; + ThreadFrame->StartFrame.P3Home = (ULONG)SystemRoutine; /* Initialize switch frame */ - ThreadFrame->SwitchFrame.ApcBypassDisabled = TRUE; + ThreadFrame->SwitchFrame.ApcBypass = APC_LEVEL; ThreadFrame->SwitchFrame.ExceptionList = (PEXCEPTION_REGISTRATION_RECORD) - 1; + ThreadFrame->SwitchFrame.Return = (ULONG)RunThread; - /* Set thread stack */ + /* Set thread stack boundaries */ + Thread->InitialStack = (PVOID)&ThreadFrame->NpxFrame; Thread->KernelStack = &ThreadFrame->SwitchFrame; } + +/** + * Serves as the initial execution point for all threads after first context switch. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTASSEMBLY +XTAPI +VOID +KE::KThread::RunThread(VOID) +{ + /* Initialize execution context, adjust runlevel and dispatch the thread */ + __asm__ volatile("xorl %%ebx, %%ebx\n" + "xorl %%ebp, %%ebp\n" + "xorl %%edi, %%edi\n" + "xorl %%esi, %%esi\n" + "movl $%c[RunLevel], %%ecx\n" + "call %P[LowerRunLevel]\n" + "movl 0(%%esp), %%esi\n" + "movl 4(%%esp), %%ebx\n" + "movl 8(%%esp), %%edi\n" + "pushl %%esi\n" + "pushl %%ebx\n" + "call *%%edi\n" + "addl $16, %%esp\n" + "ret\n" + : + : [RunLevel] "i" (APC_LEVEL), + [LowerRunLevel] "i" (KE::RunLevel::LowerRunLevel) + : "memory"); +} diff --git a/xtoskrnl/ke/i686/proc.cc b/xtoskrnl/ke/i686/proc.cc index 03c29ec..068f938 100644 --- a/xtoskrnl/ke/i686/proc.cc +++ b/xtoskrnl/ke/i686/proc.cc @@ -66,6 +66,21 @@ KE::Processor::GetCurrentThread(VOID) return (PKTHREAD)AR::CpuFunctions::ReadFSDualWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread)); } +/** + * Retrieves the number of installed and enabled CPUs in the system. + * + * @return This routine returns the number of installed CPUs in the system. + * + * @since XT 1.0 + */ +XTAPI +ULONG +KE::Processor::GetInstalledCpus(VOID) +{ + /* Return number of installed CPUs */ + return InstalledCpus; +} + /** * Gets the processor block for the specified processor number. * @@ -122,6 +137,9 @@ KE::Processor::InitializeProcessorBlocks() /* Zero the array initially */ RTL::Memory::ZeroMemory(ProcessorBlocks, InstalledCpus * sizeof(PKPROCESSOR_BLOCK)); + /* Register the processor block for the BSP processor */ + KE::Processor::RegisterProcessorBlock(0, KE::Processor::GetCurrentProcessorBlock()); + /* Return success */ return STATUS_SUCCESS; } @@ -178,10 +196,20 @@ KE::Processor::RegisterProcessorBlock(ULONG CpuNumber, } /** - * Saves the current processor state. + * Restores the processor's architectural state from the provided context frame back into the hardware trap + * and exception frames. * - * @param State - * Supplies a pointer to the processor state structure. + * @param TrapFrame + * Supplies a pointer to the trap frame that will receive the volatile processor state and control registers. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame that will receive the non-volatile integer and FP registers. + * + * @param ContextFrame + * Supplies a pointer to the context frame containing the state to be restored. + * + * @param ContextFlags + * Supplies a bitmask indicating which specific register groups should be restored from the ContextFrame. * * @return This routine does not return any value. * @@ -189,7 +217,183 @@ KE::Processor::RegisterProcessorBlock(ULONG CpuNumber, */ XTAPI VOID -KE::Processor::SaveProcessorState(OUT PKPROCESSOR_STATE CpuState) +KE::Processor::RestoreProcessorContext(IN OUT PKTRAP_FRAME TrapFrame, + IN OUT PKEXCEPTION_FRAME ExceptionFrame, + IN PCONTEXT ContextFrame, + IN ULONG ContextFlags) +{ + UNIMPLEMENTED; +} + +/** + * Restores the processor's low-level hardware control state. + * + * @param CpuState + * Supplies a pointer to the processor state block containing the previously saved control data. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::RestoreProcessorControlState(IN PKPROCESSOR_STATE CpuState) +{ + /* Restore CR registers */ + AR::CpuFunctions::WriteControlRegister(0, CpuState->SpecialRegisters.Cr0); + AR::CpuFunctions::WriteControlRegister(2, CpuState->SpecialRegisters.Cr2); + AR::CpuFunctions::WriteControlRegister(3, CpuState->SpecialRegisters.Cr3); + AR::CpuFunctions::WriteControlRegister(4, CpuState->SpecialRegisters.Cr4); + + /* Restore DR registers */ + AR::CpuFunctions::WriteDebugRegister(0, CpuState->SpecialRegisters.KernelDr0); + AR::CpuFunctions::WriteDebugRegister(1, CpuState->SpecialRegisters.KernelDr1); + AR::CpuFunctions::WriteDebugRegister(2, CpuState->SpecialRegisters.KernelDr2); + AR::CpuFunctions::WriteDebugRegister(3, CpuState->SpecialRegisters.KernelDr3); + AR::CpuFunctions::WriteDebugRegister(6, CpuState->SpecialRegisters.KernelDr6); + AR::CpuFunctions::WriteDebugRegister(7, CpuState->SpecialRegisters.KernelDr7); + + /* Restore GDT, IDT and LDT */ + AR::CpuFunctions::LoadGlobalDescriptorTable(&CpuState->SpecialRegisters.Gdtr.Limit); + AR::CpuFunctions::LoadInterruptDescriptorTable(&CpuState->SpecialRegisters.Idtr.Limit); + AR::CpuFunctions::LoadLocalDescriptorTable(CpuState->SpecialRegisters.Ldtr); + + /* Force the TSS descriptor into a non-busy state and restore TaskRegister */ + *(VOLATILE PUCHAR)((ULONG_PTR)CpuState->SpecialRegisters.Gdtr.Base + CpuState->SpecialRegisters.Tr + 5) &= ~0x02; + AR::CpuFunctions::LoadTaskRegister(CpuState->SpecialRegisters.Tr); +} + +/** + * Restores the executing processor's state. + * + * @param TrapFrame + * Supplies a pointer to the hardware trap frame that will be populated with the restored volatile state. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame that will be populated with the restored non-volatile state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::RestoreProcessorState(OUT PKTRAP_FRAME TrapFrame, + OUT PKEXCEPTION_FRAME ExceptionFrame) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Retrieve current processor control block */ + Prcb = GetCurrentProcessorControlBlock(); + + /* Restore processor context */ + RestoreProcessorContext(TrapFrame, ExceptionFrame, &Prcb->ProcessorState.ContextFrame, + CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS); + + /* Restore processor control registers */ + RestoreProcessorControlState(&Prcb->ProcessorState); +} + +/** + * Constructs a standardized processor context from the hardware trap and exception frames. + * + * @param TrapFrame + * Supplies a pointer to the trap frame containing volatile processor state, control registers and debug + * registers saved at the time of the interrupt or exception. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame containing non-volatile integer and floating-point registers. + * + * @param ContextFrame + * Supplies a pointer to the context frame that will receive the processor state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::SaveProcessorContext(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PCONTEXT ContextFrame) +{ + /* Elevate RunLevel to APC_LEVEL to prevent thread preemption */ + KE::RaiseRunLevel RunLevel(APC_LEVEL); + + /* Check if control registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_CONTROL) + { + /* Copy instruction pointer, stack pointer, and CPU status flags */ + ContextFrame->Flags = TrapFrame->Flags; + ContextFrame->Ebp = TrapFrame->Ebp; + ContextFrame->Eip = TrapFrame->Eip; + ContextFrame->Esp = TrapFrame->Esp; + ContextFrame->SegCs = TrapFrame->SegCs; + ContextFrame->SegSs = TrapFrame->SegSs; + } + + /* Check if general-purpose integer registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_INTEGER) + { + /* Copy integer registers directly from the trap frame */ + ContextFrame->Eax = TrapFrame->Eax; + ContextFrame->Ebx = TrapFrame->Ebx; + ContextFrame->Ecx = TrapFrame->Ecx; + ContextFrame->Edx = TrapFrame->Edx; + ContextFrame->Edi = TrapFrame->Edi; + ContextFrame->Esi = TrapFrame->Esi; + } + + /* Check if segment registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_SEGMENTS) + { + /* Populate segment selectors with standard Ring 3 values */ + TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK; + TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK; + TrapFrame->SegFs = KGDT_R0_PB; + TrapFrame->SegGs = 0; + } + + /* Check if floating-point registers are requested and if running in user mode */ + if((ContextFrame->ContextFlags & CONTEXT_FLOATING_POINT) && ((TrapFrame->SegCs & MODE_MASK) == UserMode)) + { + /* No user-mode support */ + UNIMPLEMENTED; + } + + /* Check if debug registers are requested */ + if(ContextFrame->ContextFlags & CONTEXT_DEBUG_REGISTERS) + { + /* Copy debug registers */ + ContextFrame->Dr0 = TrapFrame->Dr0; + ContextFrame->Dr1 = TrapFrame->Dr1; + ContextFrame->Dr2 = TrapFrame->Dr2; + ContextFrame->Dr3 = TrapFrame->Dr3; + ContextFrame->Dr6 = TrapFrame->Dr6; + ContextFrame->Dr7 = TrapFrame->Dr7; + } + + /* Check if extended registers are requested and if running in user mode */ + if((ContextFrame->ContextFlags & CONTEXT_EXTENDED_REGISTERS) && ((TrapFrame->SegCs & MODE_MASK) == UserMode)) + { + /* No user-mode support */ + UNIMPLEMENTED; + } +} + +/** + * Saves the current processor's low-level hardware control state. + * + * @param State + * Supplies a pointer to the processor state block that will receive processor's control data. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::SaveProcessorControlState(OUT PKPROCESSOR_STATE CpuState) { /* Save CR registers */ CpuState->SpecialRegisters.Cr0 = AR::CpuFunctions::ReadControlRegister(0); @@ -211,3 +415,36 @@ KE::Processor::SaveProcessorState(OUT PKPROCESSOR_STATE CpuState) AR::CpuFunctions::StoreLocalDescriptorTable(&CpuState->SpecialRegisters.Ldtr); AR::CpuFunctions::StoreTaskRegister(&CpuState->SpecialRegisters.Tr); } + +/** + * Captures the executing processor's state. + * + * @param TrapFrame + * Supplies a pointer to the hardware trap frame containing the processor's volatile state. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame containing the processor's non-volatile state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Processor::SaveProcessorState(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Retrieve current processor control block */ + Prcb = GetCurrentProcessorControlBlock(); + + /* Set context flags to save whole full context and debug registers */ + Prcb->ProcessorState.ContextFrame.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; + + /* Save processor context */ + SaveProcessorContext(TrapFrame, ExceptionFrame, &Prcb->ProcessorState.ContextFrame); + + /* Save processor control registers */ + SaveProcessorControlState(&Prcb->ProcessorState); +} diff --git a/xtoskrnl/ke/ipi.cc b/xtoskrnl/ke/ipi.cc new file mode 100644 index 0000000..c2d717a --- /dev/null +++ b/xtoskrnl/ke/ipi.cc @@ -0,0 +1,247 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/ipi.cc + * DESCRIPTION: Interprocessor interrupt support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Handles an IPI interrupt. + * + * @param TrapFrame + * Supplies a pointer to the processor's trap frame captured at the moment the interrupt was delivered. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +KE::Ipi::HandleIpiInterrupt(IN PKTRAP_FRAME TrapFrame) +{ + KRUNLEVEL RunLevel; + + /* Start the interrupt */ + HL::Irq::BeginSystemInterrupt(IPI_LEVEL, &RunLevel); + + /* Call the IPI service routine */ + HandleIpiService(TrapFrame, NULLPTR); + + /* End the interrupt */ + HL::Irq::EndInterrupt(TrapFrame, RunLevel); +} + +/** + * Services an incoming Inter-Processor Interrupt (IPI). + * + * @param TrapFrame + * Supplies a pointer to the trap frame representing the processor state at the time of the interrupt. + * + * @param ExceptionFrame + * Supplies a pointer to the exception frame. + * + * @return This routine returns TRUE if a standard IPI request (other than IPI_FREEZE) was processed, + * or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +KE::Ipi::HandleIpiService(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + LONG_PTR RequestSummary; + + /* Get processor control block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Atomically retrieve and clear the pending IPI request summary */ + RequestSummary = RTL::Atomic::Exchange64((PLONG_PTR)&Prcb->RequestSummary, 0); + + /* Check if an Asynchronous Procedure Call (APC) interrupt was requested */ + if((RequestSummary & IPI_APC) != 0) + { + /* Dispatch a software interrupt to process the APC queue */ + HL::Irq::SendSoftwareInterrupt(APC_LEVEL); + } + + /* Check if a Deferred Procedure Call (DPC) interrupt was requested */ + if((RequestSummary & IPI_DPC) != 0) + { + /* Flag the DPC request in the PRCB and dispatch a software interrupt */ + Prcb->DpcInterruptRequested = TRUE; + HL::Irq::SendSoftwareInterrupt(DISPATCH_LEVEL); + } + + /* Check if the IPI packet is ready to be processed */ + if((RequestSummary & IPI_PACKET_READY) != 0) + { + UNIMPLEMENTED; + } + + /* Check if a synchronous inter-processor event was requested */ + if((RequestSummary & IPI_SYNC_REQUEST) != 0) + { + UNIMPLEMENTED; + } + + /* Check if a debugger freeze request was issued */ + if((RequestSummary & IPI_FREEZE) != 0) + { + /* Suspend the current processor execution */ + KE::Crash::FreezeCurrentExecution(TrapFrame, ExceptionFrame); + } + + /* Return TRUE if any standard execution requests were serviced, excluding freeze events */ + return (RequestSummary & ~IPI_FREEZE) != 0; +} + +/** + * Broadcasts an Inter-Processor Interrupt (IPI) to all active processors in the system. + * + * @param Request + * Supplies the logical request operation flags to be merged into the target processors' request summaries. + * + * @param Self + * Specifies whether the broadcast IPI should also be delivered to the originating processor. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Ipi::SendBroadcastIpi(IN ULONG Request, + IN BOOLEAN Self) +{ + PKPROCESSOR_BLOCK CurrentProcessorBlock, TargetProcessorBlock; + ULONG CpuCount, Index; + BOOLEAN Interrupts; + + /* Get the number of installed CPUs */ + CpuCount = KE::Processor::GetInstalledCpus(); + + /* Check if there are any processors to broadcast to */ + if(CpuCount <= 1 && !Self) + { + /* There are no other processors, return */ + return; + } + + /* Check whether interrupts are enabled */ + Interrupts = AR::CpuFunctions::InterruptsEnabled(); + + /* Disable interrupts */ + AR::CpuFunctions::ClearInterruptFlag(); + + /* Get the current processor block */ + CurrentProcessorBlock = KE::Processor::GetCurrentProcessorBlock(); + + /* Iterate over all logical CPUs */ + for(Index = 0; Index < CpuCount; Index++) + { + /* Retrieve the target processor block by its Logical CPU Number */ + TargetProcessorBlock = KE::Processor::GetProcessorBlock(Index); + + /* Only target processors that exist and have successfully started */ + if(TargetProcessorBlock != NULLPTR && TargetProcessorBlock->Started) + { + /* Check if this processor originated the broadcast */ + if(TargetProcessorBlock->HardwareId == CurrentProcessorBlock->HardwareId) + { + /* Check if this is a self broadcast */ + if(Self) + { + /* Update the logical request summary and dispatch a physical IPI to the current processor */ + RTL::Atomic::Or64((PLONG_PTR)&TargetProcessorBlock->Prcb.RequestSummary, Request); + HL::Pic::SendSelfIpi(APIC_VECTOR_IPI); + } + } + else + { + /* Update the logical request summary and dispatch a physical IPI to the target processor */ + RTL::Atomic::Or64((PLONG_PTR)&TargetProcessorBlock->Prcb.RequestSummary, Request); + HL::Pic::SendIpi(TargetProcessorBlock->HardwareId, APIC_VECTOR_IPI, APIC_DM_FIXED, + APIC_DSH_Destination, APIC_TGM_EDGE); + } + } + } + + /* Check whether interrupts need to be re-enabled */ + if(Interrupts) + { + /* Re-enable interrupts */ + AR::CpuFunctions::SetInterruptFlag(); + } +} + +/** + * Sends an Inter-Processor Interrupt (IPI) to a specific set of target processors. + * + * @param Request + * Supplies the logical request operation flags to be merged into the target processors' * request summaries. + * + * @param TargetSet + * Supplies a pointer to the affinity map defining the processors to be interrupted. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Ipi::SendIpi(IN ULONG Request, + IN PKAFFINITY_MAP TargetSet) +{ + PKPROCESSOR_BLOCK ProcessorBlock; + ULONG BlockIndex, CpuIndex; + KAFFINITY AffinityBlock; + BOOLEAN Interrupts; + + /* Check whether interrupts are enabled */ + Interrupts = AR::CpuFunctions::InterruptsEnabled(); + + /* Disable interrupts */ + AR::CpuFunctions::ClearInterruptFlag(); + + /* Iterate through all blocks within the target affinity map */ + for(BlockIndex = 0; BlockIndex < TargetSet->Size; BlockIndex++) + { + /* Retrieve the current affinity block */ + AffinityBlock = TargetSet->Bitmap[BlockIndex]; + + /* Loop until all set bits in the current block have been processed */ + while(AffinityBlock != 0) + { + /* Find the index of the lowest set bit representing a target CPU */ + AR::CpuFunctions::ScanForwardBit(&CpuIndex, AffinityBlock); + + /* Retrieve the target processor block */ + ProcessorBlock = KE::Processor::GetProcessorBlock((BlockIndex * 64) + CpuIndex); + + /* Ensure the processor block exists */ + if(ProcessorBlock != NULLPTR) + { + /* Update the logical request summary and dispatch the physical IPI */ + RTL::Atomic::Or64((PLONG_PTR)&ProcessorBlock->Prcb.RequestSummary, Request); + HL::Pic::SendIpi(ProcessorBlock->HardwareId, APIC_VECTOR_IPI, APIC_DM_FIXED, + APIC_DSH_Destination, APIC_TGM_EDGE); + } + + /* Clear the processed bit to move on to the next CPU */ + AffinityBlock &= ~((KAFFINITY)1 << CpuIndex); + } + } + + /* Check whether interrupts need to be re-enabled */ + if(Interrupts) + { + /* Re-enable interrupts */ + AR::CpuFunctions::SetInterruptFlag(); + } +} diff --git a/xtoskrnl/ke/kprocess.cc b/xtoskrnl/ke/kprocess.cc index ac60e85..ac89d46 100644 --- a/xtoskrnl/ke/kprocess.cc +++ b/xtoskrnl/ke/kprocess.cc @@ -9,6 +9,21 @@ #include +/** + * Retrieves the pointer to the global Idle process. + * + * @return Returns a pointer to the Idle process. + * + * @since XT 1.0 + */ +XTAPI +PKPROCESS +KE::KProcess::GetIdleProcess(VOID) +{ + /* Return pointer to the idle process */ + return &InitialProcess.ProcessControlBlock; +} + /** * Retrieves a pointer to the system's initial executive process object. * @@ -23,6 +38,58 @@ KE::KProcess::GetInitialProcess(VOID) return &InitialProcess; } +/** + * Initializes the system-wide Idle Process. + * + * @param Process + * Supplies a pointer to the KPROCESS structure representing the idle process. + * + * @param DirectoryTable + * Supplies a pointer to the initial hardware page directory table for the process. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +KE::KProcess::InitializeIdleProcess(IN OUT PKPROCESS IdleProcess, + IN PULONG_PTR DirectoryTable) +{ + XTSTATUS Status; + ULONG Cpus; + + /* Get the number of natively installed CPUs */ + Cpus = KE::Processor::GetInstalledCpus(); + + /* Allocate and initialize the baseline affinity map for the process */ + Status = KE::Affinity::CreateAffinityMap(Cpus, &IdleProcess->Affinity); + if(Status != STATUS_SUCCESS) + { + /* Affinity map allocation failed, return status code */ + return Status; + } + + /* Allocate and initialize the dynamic map used to track actively running CPUs */ + Status = KE::Affinity::CreateAffinityMap(Cpus, &IdleProcess->ActiveProcessors); + if(Status != STATUS_SUCCESS) + { + /* Affinity map allocation failed, free affinity map and return status code */ + KE::Affinity::DestroyAffinityMap(IdleProcess->Affinity); + return Status; + } + + /* Set Idle Process affinity */ + KE::Affinity::SetAllProcessorsAffinity(IdleProcess->Affinity); + + /* Initialize Idle process */ + KE::KProcess::InitializeProcess(IdleProcess, 0, NULLPTR, DirectoryTable, FALSE); + IdleProcess->Quantum = MAXCHAR; + + /* Return success */ + return STATUS_SUCCESS; +} + /** * Initializes the process. * @@ -32,8 +99,8 @@ KE::KProcess::GetInitialProcess(VOID) * @param Priority * Specifies the process priority. * - * @param Affinity - * Specifies a process affinity designating processors on which process can run. + * @param AffinityMap + * Specifies a process affinity map designating processors on which process can run. * * @param DirectoryTable * Supplies a pointer to the directory table. @@ -49,11 +116,13 @@ XTAPI VOID KE::KProcess::InitializeProcess(IN OUT PKPROCESS Process, IN KPRIORITY Priority, - IN KAFFINITY Affinity, + IN PKAFFINITY_MAP AffinityMap, IN PULONG_PTR DirectoryTable, IN BOOLEAN Alignment) { /* Initialize process dispatcher header */ + Process->Header.SignalState = 0; + Process->Header.Size = sizeof(KPROCESS) / sizeof(LONG); Process->Header.Type = ProcessObject; /* Initialize process wait list */ @@ -64,15 +133,23 @@ KE::KProcess::InitializeProcess(IN OUT PKPROCESS Process, RtlInitializeListHead(&Process->ReadyListHead); RtlInitializeListHead(&Process->ThreadListHead); + /* Check if source affinity map was provided */ + if(AffinityMap != NULLPTR && AffinityMap != Process->Affinity) + { + /* Set process affinity */ + KE::Affinity::CopyAffinity(Process->Affinity, AffinityMap); + } + /* Set base process properties */ Process->BasePriority = Priority; - Process->Affinity = Affinity; Process->AutoAlignment = Alignment; + + /* Set directory tables */ Process->DirectoryTable[0] = DirectoryTable[0]; Process->DirectoryTable[1] = DirectoryTable[1]; - Process->StackCount = MAXSHORT; - /* Set thread quantum */ + /* Set the initial stack count and process quantum */ + Process->StackCount = MAXULONG_PTR; Process->Quantum = THREAD_QUANTUM; /* Set IOPM offset */ diff --git a/xtoskrnl/ke/krnlinit.cc b/xtoskrnl/ke/krnlinit.cc index 0d96438..ae864b5 100644 --- a/xtoskrnl/ke/krnlinit.cc +++ b/xtoskrnl/ke/krnlinit.cc @@ -9,9 +9,6 @@ #include -/* Use routines from Kernel Library */ -using namespace KE; - /** * This routine starts up the XT kernel. It is called by boot loader. * @@ -22,6 +19,7 @@ using namespace KE; * * @since XT 1.0 */ +XTCLINK XTAPI VOID KeStartXtSystem(IN PKERNEL_INITIALIZATION_BLOCK Parameters) diff --git a/xtoskrnl/ke/kthread.cc b/xtoskrnl/ke/kthread.cc index 39c2533..f9de62e 100644 --- a/xtoskrnl/ke/kthread.cc +++ b/xtoskrnl/ke/kthread.cc @@ -9,6 +9,144 @@ #include +/** + * Finalizes thread initialization by inheriting parent process scheduling properties. + * + * @param Thread + * Supplies a pointer to the thread. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::KThread::AttachThread(IN OUT PKTHREAD Thread) +{ + ULONG IdealProcessor; + PKPROCESS Process; + + /* Extract the parent process from the thread's initial APC state */ + Process = Thread->ApcState.Process; + + /* Inherit scheduling properties from the parent process */ + Thread->DisableBoost = Process->DisableBoost; + Thread->Iopl = Process->Iopl; + Thread->Quantum = Process->Quantum; + Thread->SystemAffinityActive = FALSE; + + /* Acquire the process lock */ + KE::SpinLockGuard ProcessGuard(&Process->ProcessLock); + + /* Inherit priority from the parent process */ + Thread->BasePriority = Process->BasePriority; + Thread->Priority = Process->BasePriority; + + /* Inherit affinity state from the parent process */ + KE::Affinity::CopyAffinity(Thread->Affinity, Process->Affinity); + KE::Affinity::CopyAffinity(Thread->UserAffinity, Process->Affinity); + + /* Calculate the ideal processor based on the process thread seed and the affinity map */ + IdealProcessor = KE::Affinity::FindNextRightSetProcessor(Process->ThreadSeed, Thread->Affinity); + + /* Advance the thread seed for the next thread created in this process */ + Process->ThreadSeed++; + + /* Assign the selected ideal processor */ + Thread->IdealProcessor = (UCHAR)IdealProcessor; + Thread->UserIdealProcessor = (UCHAR)IdealProcessor; + + /* Acquire the dispatcher database lock */ + KE::SystemQueuedSpinLockGuard DispatcherGuard(DispatcherLock); + + /* Insert the thread into the process's active thread list */ + RTL::LinkedList::InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); + + /* Handle edge cases where the stack count is uninitialized or explicitly maxed out */ + if(Process->StackCount == MAXULONG_PTR) + { + /* Initialize the stack count for the first thread */ + Process->StackCount = 1; + } + else + { + /* Increment the process stack count */ + Process->StackCount++; + } +} + +/** + * Disables the delivery of normal kernel APCs for the current thread. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::KThread::EnterCriticalRegion() +{ + /* Prevent the thread from being preempted by an APC */ + EnterCriticalRegion(KE::Processor::GetCurrentThread()); +} + +/** + * Disables the delivery of normal kernel APCs for the specified thread. + * + * @param Thread + * Supplies a pointer to the thread object whose APC delivery is to be disabled. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::KThread::EnterCriticalRegion(IN PKTHREAD Thread) +{ + /* Disable Kernel APCs */ + Thread->KernelApcDisable--; + + /* Prevent the compiler from reordering code */ + AR::CpuFunctions::ReadWriteBarrier(); +} + +/** + * Disables the delivery of special APCs for the current thread. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::KThread::EnterGuardedRegion() +{ + /* Prevent the thread from being preempted by an APC */ + EnterGuardedRegion(KE::Processor::GetCurrentThread()); +} + +/** + * Disables the delivery of special APCs for the specified thread. + * + * @param Thread + * Supplies a pointer to the thread object whose APC delivery is to be disabled. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::KThread::EnterGuardedRegion(IN PKTHREAD Thread) +{ + /* Disable Special APCs */ + Thread->SpecialApcDisable--; + + /* Prevent the compiler from reordering code */ + AR::CpuFunctions::ReadWriteBarrier(); +} + /** * Retrieves a pointer to the system's initial executive thread object. * @@ -23,6 +161,91 @@ KE::KThread::GetInitialThread(VOID) return &InitialThread; } +/** + * Handles an unexpected system thread exit. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::KThread::HandleSystemThreadExit(VOID) +{ + /* Trigger a debugger breakpoint */ + __asm__ volatile("int $3\n"); +} + +/** + * Initializes an Idle Thread. + * + * @param IdleProcess + * Supplies a pointer to the global Idle Process container. + * + * @param IdleThread + * Supplies a pointer to the KTHREAD structure being initialized. + * + * @param Prcb + * Supplies a pointer to the Processor Control Block of the target CPU. + * + * @param Stack + * Supplies a pointer to the pre-allocated kernel stack for this thread. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +KE::KThread::InitializeIdleThread(IN PKPROCESS IdleProcess, + IN OUT PKTHREAD IdleThread, + IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PVOID Stack) +{ + XTSTATUS Status; + ULONG Cpus; + + /* Get the number of installed CPUs */ + Cpus = KE::Processor::GetInstalledCpus(); + + /* Allocate and initialize the primary affinity map for the thread */ + Status = KE::Affinity::CreateAffinityMap(Cpus, &IdleThread->Affinity); + if(Status != STATUS_SUCCESS) + { + /* Affinity map allocation failed, return status code */ + return Status; + } + + /* Allocate and initialize the user-mode affinity map for the thread */ + Status = KE::Affinity::CreateAffinityMap(Cpus, &IdleThread->UserAffinity); + if(Status != STATUS_SUCCESS) + { + /* Affinity map allocation failed, free affinity map and return status code */ + KE::Affinity::DestroyAffinityMap(IdleThread->Affinity); + return Status; + } + + /* Initialize Idle thread */ + KE::KThread::InitializeThread(IdleProcess, IdleThread, NULLPTR, NULLPTR, NULLPTR, + NULLPTR, NULLPTR, Stack, TRUE); + + /* Configure Idle thread scheduling parameters */ + IdleThread->NextProcessor = Prcb->CpuNumber; + IdleThread->Priority = THREAD_HIGH_PRIORITY; + IdleThread->State = Running; + IdleThread->WaitRunLevel = DISPATCH_LEVEL; + + /* Configure thread affinity */ + KE::Affinity::SetProcessorAffinity(IdleThread->Affinity, Prcb->CpuNumber); + KE::Affinity::SetProcessorAffinity(IdleThread->UserAffinity, Prcb->CpuNumber); + + /* Register CPU as active in the IDLE Process */ + KE::Affinity::AtomicSetProcessorAffinity(IdleProcess->ActiveProcessors, Prcb->CpuNumber); + + /* Return success */ + return STATUS_SUCCESS; +} + /** * Initializes the thread. * @@ -64,7 +287,7 @@ KE::KThread::InitializeThread(IN PKPROCESS Process, IN PCONTEXT Context, IN PVOID EnvironmentBlock, IN PVOID Stack, - IN BOOLEAN RunThread) + IN BOOLEAN AttachToProcess) { PKWAIT_BLOCK TimerWaitBlock; BOOLEAN Allocation; @@ -75,18 +298,21 @@ KE::KThread::InitializeThread(IN PKPROCESS Process, Allocation = FALSE; /* Initialize thread dispatcher header */ - Thread->Header.Type = ThreadObject; Thread->Header.SignalState = 0; + Thread->Header.Size = sizeof(KTHREAD) / sizeof(LONG); + Thread->Header.DebugActive = FALSE; + Thread->Header.Type = ThreadObject; /* Initialize thread wait list */ RTL::LinkedList::InitializeListHead(&Thread->Header.WaitListHead); - /* Initialize thread mutant list head */ - RTL::LinkedList::InitializeListHead(&Thread->MutantListHead); + /* Initialize thread mutex list head */ + RTL::LinkedList::InitializeListHead(&Thread->MutexListHead); /* Initialize the builtin wait blocks */ for(Index = 0; Index <= KTHREAD_WAIT_BLOCK; Index++) { + /* Backlink the wait block to the owning thread */ Thread->WaitBlock[Index].Thread = Thread; } @@ -99,15 +325,18 @@ KE::KThread::InitializeThread(IN PKPROCESS Process, /* Set priority adjustment reason */ Thread->AdjustReason = AdjustNone; + /* Set the thread service table */ + Thread->ServiceTable = KE::SystemServices::GetSystemServicesDescriptorTable(); + /* Initialize thread lock */ KE::SpinLock::InitializeSpinLock(&Thread->ThreadLock); /* Initialize thread APC */ - Thread->ApcStatePointer[0] = &Thread->ApcState; - Thread->ApcStatePointer[1] = &Thread->SavedApcState; Thread->ApcQueueable = TRUE; Thread->ApcState.Process = Process; - Thread->Process = Process; + Thread->ApcStateIndex = OriginalApcEnvironment; + Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; + Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; /* Initialize APC list heads */ RTL::LinkedList::InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); @@ -132,8 +361,9 @@ KE::KThread::InitializeThread(IN PKPROCESS Process, TimerWaitBlock->WaitListEntry.Flink = &(&Thread->Timer)->Header.WaitListHead; TimerWaitBlock->WaitListEntry.Blink = &(&Thread->Timer)->Header.WaitListHead; - /* Initialize Thread Environment Block*/ + /* Initialize Thread Environment Block and set owner process */ Thread->EnvironmentBlock = (PTHREAD_ENVIRONMENT_BLOCK)EnvironmentBlock; + Thread->Process = Process; /* Make sure there is a valid stack available */ if(!Stack) @@ -150,6 +380,7 @@ KE::KThread::InitializeThread(IN PKPROCESS Process, Allocation = TRUE; } + /* Setup thread stack */ Thread->InitialStack = Stack; Thread->StackBase = Stack; Thread->StackLimit = (PVOID)((ULONG_PTR)Stack - KERNEL_STACK_SIZE); @@ -178,10 +409,10 @@ KE::KThread::InitializeThread(IN PKPROCESS Process, Thread->State = Initialized; /* Check if thread should be started */ - if(RunThread) + if(AttachToProcess) { /* Start thread */ - StartThread(Thread); + AttachThread(Thread); } /* Return success */ @@ -189,20 +420,108 @@ KE::KThread::InitializeThread(IN PKPROCESS Process, } /** - * Starts the thread. - * - * @param Thread - * Supplies a pointer to the thread. + * Re-enables the delivery of kernel APCs for the current thread. * * @return This routine does not return any value. * * @since XT 1.0 */ -XTAPI +XTFASTCALL VOID -KE::KThread::StartThread(IN PKTHREAD Thread) +KE::KThread::LeaveCriticalRegion() { - UNIMPLEMENTED; + /* Allow APCs to preempt the thread */ + LeaveCriticalRegion(KE::Processor::GetCurrentThread()); +} + +/** + * Re-enables the delivery of kernel APCs for the specified thread. + * + * @param Thread + * Supplies a pointer to the thread object whose APC delivery is to be re-enabled. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::KThread::LeaveCriticalRegion(IN PKTHREAD Thread) +{ + /* Ensure the compiler does not reorder code */ + AR::CpuFunctions::ReadWriteBarrier(); + + /* Re-enable APC delivery */ + Thread->KernelApcDisable++; + + /* Check if APC delivery is enabled */ + if(!Thread->KernelApcDisable) + { + /* Memory barrier */ + AR::CpuFunctions::MemoryBarrier(); + + /* Check for any pending kernel APCs */ + if(!RTL::LinkedList::ListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) + { + /* Check if special kernel APCs are not disabled */ + if(!Thread->SpecialApcDisable) + { + /* Initiate delivery of the pending APCs */ + KE::Apc::CheckApcDelivery(); + } + } + } +} + +/** + * Re-enables the delivery of special APCs for the current thread. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::KThread::LeaveGuardedRegion() +{ + /* Allow APCs to preempt the thread */ + LeaveGuardedRegion(KE::Processor::GetCurrentThread()); +} + + +/** + * Re-enables the delivery of special APCs for the specified thread. + * + * @param Thread + * Supplies a pointer to the thread object whose APC delivery is to be re-enabled. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::KThread::LeaveGuardedRegion(IN PKTHREAD Thread) +{ + /* Ensure the compiler does not reorder code */ + AR::CpuFunctions::ReadWriteBarrier(); + + /* Re-enable APC delivery */ + Thread->SpecialApcDisable++; + + /* Check if APC delivery is enabled */ + if(!Thread->SpecialApcDisable) + { + /* Memory barrier */ + AR::CpuFunctions::MemoryBarrier(); + + /* Check for any pending kernel APCs */ + if(!RTL::LinkedList::ListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) + { + /* Initiate delivery of the pending APCs */ + KE::Apc::CheckApcDelivery(); + } + } } /** @@ -279,3 +598,17 @@ KE::KThread::SuspendThread(IN PVOID NormalContext, { UNIMPLEMENTED; } + +/** + * Switches a new thread into User Mode. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::KThread::SwitchToUserMode(VOID) +{ + UNIMPLEMENTED; +} diff --git a/xtoskrnl/ke/pushlock.cc b/xtoskrnl/ke/pushlock.cc new file mode 100644 index 0000000..bc87d0f --- /dev/null +++ b/xtoskrnl/ke/pushlock.cc @@ -0,0 +1,1125 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/pushlock.cc + * DESCRIPTION: XT Kernel Push Lock support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Attempts to acquire a push lock for exclusive access via the fast-path. + * + * @param PushLock + * Supplies a pointer to the push lock to be acquired. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::AcquireExclusivePushLock(IN PKPUSH_LOCK PushLock) +{ + /* Attempt to swap a NULL pointer with the EXCLUSIVE flag */ + if(RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, NULLPTR, (PVOID)KPUSHLOCK_LOCK)) + { + /* Lock contention detected, enter the slow-path */ + AcquireWaitExclusivePushLock(PushLock); + } +} + +/** + * Attempts to acquire a push lock for shared access via the fast-path. + * + * @param PushLock + * Supplies a pointer to the push lock to be acquired. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::AcquireSharedPushLock(PKPUSH_LOCK PushLock) +{ + /* Attempt to set the reader flag */ + if(RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, NULLPTR, (PVOID)(KPUSHLOCK_LOCK | KPUSHLOCK_INCREMENT_SHARED))) + { + /* Lock contention or existing readers detected, Enter the slow-path */ + AcquireWaitSharedPushLock(PushLock); + } +} + +/** + * Enqueues the current thread's wait block into the lock's wait list, conditionally assumes responsibility + * for list optimization and transitions the thread into a wait state until exclusive ownership is acquired. + * + * @param PushLock + * Supplies a pointer to the push lock to be acquired. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::AcquireWaitExclusivePushLock(IN PKPUSH_LOCK PushLock) +{ + KPUSH_LOCK OldState, NewState, TempState; + KPUSH_LOCK_WAIT_BLOCK WaitBlock; + PVOID ActualState; + BOOLEAN Optimize; + + /* Initialize a synchronization event */ + KE::Event::InitializeEvent(&WaitBlock.WakeEvent, SynchronizationEvent, FALSE); + + /* Capture the snapshot of the push lock pointer */ + OldState.Ptr = PushLock->Ptr; + + /* Enter contention loop */ + while(TRUE) + { + /* Check if the lock is free */ + if(!(OldState.Value & KPUSHLOCK_LOCK)) + { + /* Assert the LOCK bit */ + NewState.Value = OldState.Value | KPUSHLOCK_LOCK; + + /* Commit the acquisition */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Lock acquired, return */ + return; + } + + /* The lock state changed, retry */ + OldState.Ptr = ActualState; + continue; + } + else + { + /* Prepare the wait block for enqueuing */ + WaitBlock.Flags = KPUSHLOCK_LOCK | KPUSHLOCK_WAITING; + WaitBlock.Previous = NULLPTR; + + /* Assume no list optimization is required initially */ + Optimize = FALSE; + + /* Check if other threads are already queued */ + if(OldState.Value & KPUSHLOCK_WAITING) + { + /* Hook into the head of the existing LIFO list */ + WaitBlock.Last = NULLPTR; + WaitBlock.Next = (PKPUSH_LOCK_WAIT_BLOCK)(OldState.Value & ~KPUSHLOCK_PTR_BITS); + WaitBlock.ShareCount = 0; + + /* Construct the new pointer containing wait block and preserved flags */ + NewState.Value = (OldState.Value & KPUSHLOCK_MULTIPLE_SHARED) | + KPUSHLOCK_LOCK | + KPUSHLOCK_WAKING | + KPUSHLOCK_WAITING | + (ULONG_PTR)&WaitBlock; + + /* Check if no one is currently organizing the list */ + if(!(OldState.Value & KPUSHLOCK_WAKING)) + { + /* Take responsibility for optimizing the wait list */ + Optimize = TRUE; + } + } + else + { + /* Mark this block as the tail of the new wait list and preserve the shared reader count */ + WaitBlock.Last = &WaitBlock; + WaitBlock.ShareCount = (ULONG)OldState.Shared; + + /* Check if multiple readers currently hold the lock */ + if(OldState.Shared > 1) + { + /* Inject the wait block and preserve the multiple shared state */ + NewState.Value = KPUSHLOCK_MULTIPLE_SHARED | KPUSHLOCK_LOCK | KPUSHLOCK_WAITING | (ULONG_PTR)&WaitBlock; + } + else + { + /* Clear the share count for a single owner */ + WaitBlock.ShareCount = 0; + + /* Inject the wait block for a single owner scenario */ + NewState.Value = KPUSHLOCK_LOCK | KPUSHLOCK_WAITING | (ULONG_PTR)&WaitBlock; + } + } + + /* insert wait block into the PushLock */ + TempState.Ptr = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(TempState.Ptr != OldState.Ptr) + { + /* Lost the queue race, retry */ + OldState.Ptr = TempState.Ptr; + continue; + } + + /* Check if this thread took the optimization role */ + if(Optimize) + { + /* Convert the LIFO wait list into a FIFO list */ + OptimizePushLockList(PushLock, NewState); + } + + /* Block the thread */ + SpinPushLock(&WaitBlock); + + /* Reset state and retry */ + WaitBlock.ShareCount = 0; + OldState.Ptr = PushLock->Ptr; + } + } +} + +/** + * Enqueues the current thread into the wait list if the lock is held exclusively or if a writer is already waiting. + * + * @param PushLock + * Supplies a pointer to the push lock to be acquired. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::AcquireWaitSharedPushLock(IN PKPUSH_LOCK PushLock) +{ + KPUSH_LOCK OldState, NewState, TempState; + KPUSH_LOCK_WAIT_BLOCK WaitBlock; + PVOID ActualState; + BOOLEAN Optimize; + + /* Initialize a synchronization event */ + KE::Event::InitializeEvent(&WaitBlock.WakeEvent, SynchronizationEvent, FALSE); + + /* Capture the snapshot of the push lock pointer */ + OldState.Ptr = PushLock->Ptr; + + /* Enter contention loop */ + while(TRUE) + { + /* Check if the lock is free */ + if(!(OldState.Value & (KPUSHLOCK_LOCK | KPUSHLOCK_WAITING))) + { + /* Increment the shared reader count */ + NewState.Value = OldState.Value + KPUSHLOCK_INCREMENT_SHARED; + + /* Commit the shared acquisition */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Lock acquired, return */ + return; + } + + /* The lock state changed, retry */ + OldState.Ptr = ActualState; + continue; + } + else + { + /* Prepare the wait block for enqueuing as a reader */ + WaitBlock.Flags = KPUSHLOCK_WAITING; + WaitBlock.Previous = NULLPTR; + + /* Assume no list optimization is required */ + Optimize = FALSE; + + /* Check if other threads are already queued */ + if(OldState.Value & KPUSHLOCK_WAITING) + { + /* Hook into the head of the existing LIFO wait list */ + WaitBlock.Last = NULLPTR; + WaitBlock.Next = (PKPUSH_LOCK_WAIT_BLOCK)(OldState.Value & ~KPUSHLOCK_PTR_BITS); + WaitBlock.ShareCount = 0; + + /* Construct the new pointer containing wait block and preserved flags */ + NewState.Value = (OldState.Value & KPUSHLOCK_MULTIPLE_SHARED) | + KPUSHLOCK_LOCK | + KPUSHLOCK_WAITING | + (ULONG_PTR)&WaitBlock; + + /* Check if no one is currently organizing the list */ + if(!(OldState.Value & KPUSHLOCK_WAKING)) + { + /* Take responsibility for optimizing the wait list */ + Optimize = TRUE; + } + } + else + { + /* Mark this block as the tail of the new wait list and preserve the shared reader count */ + WaitBlock.Last = &WaitBlock; + WaitBlock.ShareCount = (ULONG)OldState.Shared; + + /* Check if multiple readers currently hold the lock */ + if(OldState.Shared > 1) + { + /* Inject the wait block and preserve the multiple shared state */ + NewState.Value = KPUSHLOCK_MULTIPLE_SHARED | KPUSHLOCK_LOCK | KPUSHLOCK_WAITING | (ULONG_PTR)&WaitBlock; + } + else + { + /* Inject the wait block for a single owner */ + NewState.Value = KPUSHLOCK_LOCK | KPUSHLOCK_WAITING | (ULONG_PTR)&WaitBlock; + } + } + + /* Insert the wait block into the PushLock */ + TempState.Ptr = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(TempState.Ptr != OldState.Ptr) + { + /* Lost the queue race, retry */ + OldState.Ptr = TempState.Ptr; + continue; + } + + /* Check if this thread took the optimization role */ + if(Optimize) + { + /* Convert the LIFO wait list into a FIFO list */ + OptimizePushLockList(PushLock, NewState); + } + + /* Block the thread */ + SpinPushLock(&WaitBlock); + + /* Exit loop */ + return; + } + } +} + +/** + * Prepares a push lock wait block and enqueues it onto the lock's contention stack. + * + * @param PushLock + * Supplies a pointer to the push lock being contended. + * + * @param WaitBlock + * Supplies a pointer to the caller-allocated wait block to be enqueued. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::BlockPushLock(IN PKPUSH_LOCK PushLock, + IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock) +{ + PVOID OldValue; + + /* Initialize the synchronization event */ + KE::Event::InitializeEvent(&WaitBlock->WakeEvent, SynchronizationEvent, FALSE); + + /* Set the wait flag */ + WaitBlock->Flags = KPUSHLOCK_WAITING; + + /* Enter a retry loop */ + while(TRUE) + { + /* Capture the current head of the wait stack */ + OldValue = *(VOLATILE PVOID *)&PushLock->Ptr; + + /* Link new wait block to the captured head */ + WaitBlock->Next = (PKPUSH_LOCK_WAIT_BLOCK)OldValue; + + /* Attempt to swap the lock's head pointer*/ + if (RTL::Atomic::CompareExchangePointer((PVOID *)&PushLock->Ptr, (PVOID)WaitBlock, OldValue) == OldValue) + { + /* Successfully enqueued the wait block, return */ + return; + } + } +} + +/** + * Attempts to convert a push lock from shared to exclusive access. + * + * @param PushLock + * Supplies a pointer to the push lock structure. + * + * @return This routine returns TRUE if the lock was successfully converted to exclusive mode, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::PushLock::ConvertSharedPushLockToExclusive(IN PKPUSH_LOCK PushLock) +{ + PVOID OldValue; + + /* Swap the push lock state */ + OldValue = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, + (PVOID)KPUSHLOCK_INCREMENT_SHARED, + (PVOID)KPUSHLOCK_LOCK); + + /* Return conversion result */ + return (OldValue == (PVOID)KPUSHLOCK_INCREMENT_SHARED); +} + +/** + * Initializes a push lock. + * + * @param PushLock + * Supplies a pointer to the push lock to be initialized. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + * + */ +XTFASTCALL +VOID +KE::PushLock::InitializePushLock(IN PKPUSH_LOCK PushLock) +{ + /* Initialize the push lock state */ + PushLock->Value = 0; +} + +/** + * Optimizes the push lock wait list by converting it from a singly-linked LIFO list into a doubly-linked FIFO list. + * + * @param PushLock + * Supplies a pointer to the push lock whose list is being optimized. + * + * @param OldValue + * Supplies the snapshot of the push lock state containing the pointer to the list head. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTINLINE +VOID +KE::PushLock::OptimizePushLockList(IN PKPUSH_LOCK PushLock, + IN KPUSH_LOCK OldValue) +{ + PKPUSH_LOCK_WAIT_BLOCK CurrentBlock, NextBlock; + + /* Extract the pointer to the head of the wait block list */ + CurrentBlock = (PKPUSH_LOCK_WAIT_BLOCK)(OldValue.Value & ~KPUSHLOCK_PTR_BITS); + + /* Ensure the list is not empty */ + if(CurrentBlock) + { + /* Traverse the list */ + while((NextBlock = CurrentBlock->Next)) + { + /* Link the next block back to the current block */ + NextBlock->Previous = CurrentBlock; + CurrentBlock = NextBlock; + } + } +} + +/** + * Releases a push lock that was acquired for exclusive access. + * + * @param PushLock + * Supplies a pointer to the push lock to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::ReleaseExclusivePushLock(IN PKPUSH_LOCK PushLock) +{ + KPUSH_LOCK OldState; + + /* Subtract the LOCK bit */ + OldState.Value = RTL::Atomic::ExchangeAdd64((PLONG_PTR)&PushLock->Value, -(SSIZE_T)KPUSHLOCK_LOCK); + + /* Check if waiters are queued and no one is currently waking them */ + if((OldState.Value & KPUSHLOCK_WAITING) && !(OldState.Value & KPUSHLOCK_WAKING)) + { + /* Initiate the wake sequence */ + TryWakePushLock(PushLock); + } +} + +/** + * Attempts to release the lock immediately via the fast-path. + * + * @param PushLock + * Supplies a pointer to the push lock to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::ReleasePushLock(IN PKPUSH_LOCK PushLock) +{ + KPUSH_LOCK NewState, OldState; + + /* Capture the snapshot of the push lock pointer */ + OldState.Ptr = PushLock->Ptr; + + /* Check if the push lock is held by multiple readers */ + if(OldState.Value & KPUSHLOCK_MULTIPLE_SHARED) + { + /* Decrement the shared reader count */ + NewState.Value = OldState.Value - KPUSHLOCK_INCREMENT_SHARED; + } + else + { + /* Clear the push lock state */ + NewState.Value = 0; + } + + /* Check if there are waiting threads or if the swap fails due to state changes */ + if((OldState.Value & KPUSHLOCK_WAITING) || + (RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr) != OldState.Ptr)) + { + /* Contention or waiters present, execute the slow-path release */ + ReleaseWaitPushLock(PushLock); + } +} + +/** + * Releases a push lock that was acquired for shared access. + * + * @param PushLock + * Supplies a pointer to the push lock to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::ReleaseSharedPushLock(IN PKPUSH_LOCK PushLock) +{ + /* Attempt to clear the lock */ + if(RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, (PVOID)(KPUSHLOCK_LOCK | KPUSHLOCK_INCREMENT_SHARED), NULLPTR) + != (PVOID)(KPUSHLOCK_LOCK | KPUSHLOCK_INCREMENT_SHARED)) + { + /* Contention or multiple readers detected, call slow-path */ + ReleaseWaitSharedPushLock(PushLock); + } +} + +/** + * Drops the lock bit and transitions into the waking phase. + * + * @param PushLock + * Supplies a pointer to the push lock to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::ReleaseWaitExclusivePushLock(IN PKPUSH_LOCK PushLock) +{ + KPUSH_LOCK NewState, OldState; + PVOID ActualState; + + /* Capture the snapshot of the push lock pointer */ + OldState.Ptr = PushLock->Ptr; + + /* Enter release loop */ + while(TRUE) + { + /* Strip the lock bit from the current state */ + NewState.Value = OldState.Value & ~KPUSHLOCK_LOCK; + + /* Check if waiters are queued and no thread is waking them */ + if((OldState.Value & KPUSHLOCK_WAITING) && !(OldState.Value & KPUSHLOCK_WAKING)) + { + /* Add the waking flag to the state */ + NewState.Value |= KPUSHLOCK_WAKING; + } + + /* Commit the modified state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Verify if acquired the waking role */ + if((OldState.Value & KPUSHLOCK_WAITING) && !(OldState.Value & KPUSHLOCK_WAKING)) + { + /* Execute the wake sequence */ + WakePushLockWaiters(PushLock, NewState); + } + return; + } + + /* State changed, update snapshot and retry */ + OldState.Ptr = ActualState; + } +} + +/** + * Handles decrements under contention and delegates to the wake mechanism if threads are queued + * and the lock becomes fully available. + * + * @param PushLock + * Supplies a pointer to the push lock to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::ReleaseWaitPushLock(IN PKPUSH_LOCK PushLock) +{ + PKPUSH_LOCK_WAIT_BLOCK WaitBlock; + KPUSH_LOCK NewState, OldState; + PVOID ActualState; + + /* Capture the snapshot of the push lock pointer */ + OldState.Ptr = PushLock->Ptr; + + /* Enter release loop */ + while(TRUE) + { + /* Check if there are no waiters queued */ + if(!(OldState.Value & KPUSHLOCK_WAITING)) + { + /* Check if the lock is held by multiple readers */ + if(OldState.Value & KPUSHLOCK_MULTIPLE_SHARED) + { + /* Decrement the shared reader count in the new state */ + NewState.Value = OldState.Value - KPUSHLOCK_INCREMENT_SHARED; + } + else + { + /* Clear the new state */ + NewState.Value = 0; + } + + /* Commit the new state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Lock released, return */ + return; + } + + /* State changed, retry */ + OldState.Ptr = ActualState; + continue; + } + + /* Check if multiple readers hold the lock while waiters are queued */ + if(OldState.Value & KPUSHLOCK_MULTIPLE_SHARED) + { + /* Extract the wait block list head */ + WaitBlock = (PKPUSH_LOCK_WAIT_BLOCK)(OldState.Value & ~KPUSHLOCK_PTR_BITS); + + /* Traverse to find the last wait block */ + while(WaitBlock->Next) + { + /* Check if the last block pointer is already cached */ + if(WaitBlock->Last) + { + /* Jump directly to the cached last block */ + WaitBlock = WaitBlock->Last; + break; + } + + /* Advance to the next wait block */ + WaitBlock = WaitBlock->Next; + } + + /* Check if the last block is a reader block */ + if(WaitBlock->ShareCount > 0) + { + /* Decrement the block's reader share count */ + if(RTL::Atomic::Decrement32((PLONG)&WaitBlock->ShareCount) > 0) + { + /* There are still active readers, return */ + return; + } + } + } + + /* Strip the lock and multiple shared flags from the current state */ + NewState.Value = OldState.Value & ~(KPUSHLOCK_LOCK | KPUSHLOCK_MULTIPLE_SHARED); + + /* Check if another thread is already handling the wake process */ + if(OldState.Value & KPUSHLOCK_WAKING) + { + /* Commit the new state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Lock released, return */ + return; + } + } + else + { + /* Add the waking flag to the new state */ + NewState.Value |= KPUSHLOCK_WAKING; + + /* Commit the new state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Assumed the waking role, execute wake sequence and return */ + WakePushLockWaiters(PushLock, NewState); + return; + } + } + + /* State changed, update snapshot and retry */ + OldState.Ptr = ActualState; + } +} + +/** + * Handles decrements under contention and delegates to the wake mechanism if needed. + * + * @param PushLock + * Supplies a pointer to the push lock to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::ReleaseWaitSharedPushLock(IN PKPUSH_LOCK PushLock) +{ + PKPUSH_LOCK_WAIT_BLOCK WaitBlock; + KPUSH_LOCK NewState, OldState; + PVOID ActualState; + + /* Capture the snapshot of the pointer */ + OldState.Ptr = PushLock->Ptr; + + /* Enter release loop */ + while(TRUE) + { + /* Check if there are no waiters currently queued */ + if(!(OldState.Value & KPUSHLOCK_WAITING)) + { + /* Check if the lock is held by multiple readers */ + if(OldState.Value & KPUSHLOCK_MULTIPLE_SHARED) + { + /* Decrement the shared reader count in the new state */ + NewState.Value = OldState.Value - KPUSHLOCK_INCREMENT_SHARED; + } + else + { + /* Clear the new state completely */ + NewState.Value = 0; + } + + /* Commit the new state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) return; + + /* State changed, retry */ + OldState.Ptr = ActualState; + continue; + } + + /* Check if multiple readers hold the lock while waiters are queued */ + if(OldState.Value & KPUSHLOCK_MULTIPLE_SHARED) + { + /* Extract the wait block list head */ + WaitBlock = (PKPUSH_LOCK_WAIT_BLOCK)(OldState.Value & ~KPUSHLOCK_PTR_BITS); + + /* Traverse to find the last wait block */ + while(WaitBlock->Next) + { + /* Check if the last block pointer is already cached */ + if(WaitBlock->Last) + { + /* Jump to the cached last block */ + WaitBlock = WaitBlock->Last; + break; + } + + /* Advance to the next wait block */ + WaitBlock = WaitBlock->Next; + } + + /* Check if the last block is a reader block */ + if(WaitBlock->ShareCount > 0) + { + /* Decrement the block's reader share count */ + if(RTL::Atomic::Decrement32((PLONG)&WaitBlock->ShareCount) > 0) return; + } + } + + /* Strip the lock and multiple shared flags from the current state */ + NewState.Value = OldState.Value & ~(KPUSHLOCK_LOCK | KPUSHLOCK_MULTIPLE_SHARED); + + /* Check if another thread is already handling the wake process */ + if(OldState.Value & KPUSHLOCK_WAKING) + { + /* Commit the new state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) return; + } + else + { + /* Add the waking flag to the new state */ + NewState.Value |= KPUSHLOCK_WAKING; + + /* Commit the new state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Execute wake sequence */ + WakePushLockWaiters(PushLock, NewState); + return; + } + } + + /* State changed, update snapshot and retry */ + OldState.Ptr = ActualState; + } +} + +/** + * Handles the blocking phase for a thread waiting on a push lock. + * + * @param WaitBlock + * Supplies a pointer to the thread's local wait block allocated on the stack. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTINLINE +VOID +KE::PushLock::SpinPushLock(IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock) +{ + ULONG SpinCount; + + /* Initialize the spin count */ + SpinCount = KPUSH_LOCK_SPIN_COUNT; + + /* Enter adaptive Spin loop */ + while(SpinCount--) + { + /* Check if the unlocker cleared our wait flag */ + if(!(WaitBlock->Flags & KPUSHLOCK_WAITING)) + { + /* Wait flag cleared, return */ + return; + } + + /* Yield processor */ + AR::CpuFunctions::YieldProcessor(); + } + + /* Test and clear the WAIT bit */ + if(RTL::Atomic::BitTestAndReset((PLONG)&WaitBlock->Flags, 1)) + { + /* Delegate to the Dispatcher */ + KE::Dispatcher::WaitForSingleObject(&WaitBlock->WakeEvent, WrPushLock, KernelMode, FALSE, NULLPTR); + } +} + +/** + * Attempts to acquire a push lock for exclusive access without entering a wait state. + * + * @param PushLock + * Supplies a pointer to the push lock to be acquired. + * + * @return This routine returns TRUE if the exclusive lock was successfully acquired, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::PushLock::TryAcquireExclusivePushLock(PKPUSH_LOCK PushLock) +{ + /* Acquire the lock */ + if(RTL::Atomic::BitTestAndSet((PLONG)&PushLock->Value, KPUSHLOCK_INDEX)) + { + /* Lock not acquired, return FALSE */ + return FALSE; + } + + /* Lock acquired, return TRUE */ + return TRUE; +} + +/** + * Initiates the wake sequence for queued waiters if the lock is free and no other thread is already performing + * the wake operation. + * + * @param PushLock + * Supplies a pointer to the push lock to evaluate. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::TryWakePushLock(IN PKPUSH_LOCK PushLock) +{ + KPUSH_LOCK NewState, OldState; + PVOID ActualState; + + /* Capture the snapshot of the pointer */ + OldState.Ptr = PushLock->Ptr; + + /* Enter evaluation loop */ + while(TRUE) + { + /* Check if already waking, locked, or no one is waiting */ + if((OldState.Value & KPUSHLOCK_WAKING) || + (OldState.Value & KPUSHLOCK_LOCK) || + !(OldState.Value & KPUSHLOCK_WAITING)) + { + /* Abort */ + return; + } + + /* Add the waking flag to the state */ + NewState.Value = OldState.Value | KPUSHLOCK_WAKING; + + /* Commit the waking state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Assumed the waking role, execute wake sequence */ + WakePushLockWaiters(PushLock, NewState); + return; + } + + /* State changed, update snapshot and retry */ + OldState.Ptr = ActualState; + } +} + +/** + * Unblocks an executive push lock and wakes up any pending threads waiting on it. + * + * @param PushLock + * Supplies a pointer to the executive push lock being unblocked. + * + * @param CurrentWaitBlock + * Optionally supplies a pointer to the current thread's push lock wait block. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::UnblockPushLock(IN PKPUSH_LOCK PushLock, + IN PKPUSH_LOCK_WAIT_BLOCK WaitBlock) +{ + PKPUSH_LOCK_WAIT_BLOCK CurrentWaitBlock, NextWaitBlock; + + /* Capture the entire chain of wait blocks and clear the push lock pointer */ + CurrentWaitBlock = (PKPUSH_LOCK_WAIT_BLOCK)RTL::Atomic::ExchangePointer((PVOID *)&PushLock->Ptr, NULLPTR); + + /* Check if any wait blocks are present */ + if(CurrentWaitBlock) + { + /* Raise runlevel to DISPATCH level */ + KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL, CurrentWaitBlock->Next); + + /* Iterate through the captured chain of wait blocks */ + while(CurrentWaitBlock) + { + /* Cache the next block pointer */ + NextWaitBlock = CurrentWaitBlock->Next; + + /* Test and clear the lock flag */ + if(!RTL::Atomic::BitTestAndReset((VOLATILE PLONG)&CurrentWaitBlock->Flags, KPUSHLOCK_LOCK)) + { + /* Boost priority and signal the wake event */ + KE::Event::SetEventBoostPriority(&CurrentWaitBlock->WakeEvent, NULLPTR); + } + + /* Advance to the next wait block */ + CurrentWaitBlock = NextWaitBlock; + } + } + + /* Check if a wait context was provided and its wait flag is pending */ + if(WaitBlock && (WaitBlock->Flags & KPUSHLOCK_WAITING)) + { + /* Suspend the thread until push lock wake event is signaled */ + KE::Dispatcher::WaitForSingleObject(&WaitBlock->WakeEvent, WrPushLock, KernelMode, FALSE, NULLPTR); + } +} + +/** + * Wakes threads waiting on a PushLock. + * + * @param PushLock + * Supplies a pointer to the push lock being processed. + * + * @param OldState + * Supplies the current snapshot of the push lock state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::WakePushLockWaiters(IN PKPUSH_LOCK PushLock, IN KPUSH_LOCK OldState) +{ + PKPUSH_LOCK_WAIT_BLOCK FirstWaitBlock, PreviousWaitBlock, WaitBlock; + KPUSH_LOCK NewState; + PVOID ActualState; + + /* Loop while the push lock is held by another thread */ + while(OldState.Value & KPUSHLOCK_LOCK) + { + /* Strip the waking flag */ + NewState.Value = OldState.Value & ~KPUSHLOCK_WAKING; + + /* Commit the modified state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Lock released, return */ + return; + } + + /* Update the snapshot pointer */ + OldState.Ptr = ActualState; + } + + /* Extract the first wait block pointer */ + FirstWaitBlock = (PKPUSH_LOCK_WAIT_BLOCK)(OldState.Value & ~KPUSHLOCK_PTR_BITS); + WaitBlock = FirstWaitBlock; + + /* Loop through the wait block list */ + while(WaitBlock->Next) + { + /* Check if the last block pointer is cached */ + if(WaitBlock->Last) + { + /* Jump to the cached last block */ + WaitBlock = WaitBlock->Last; + break; + } + + /* Store the current block as the previous block */ + PreviousWaitBlock = WaitBlock; + + /* Advance to the next block and set the back-pointer to the previous block */ + WaitBlock = WaitBlock->Next; + WaitBlock->Previous = PreviousWaitBlock; + } + + /* Point WaitBlock to the oldest waiter */ + PreviousWaitBlock = WaitBlock->Previous; + + /* Check if the target is a reader block */ + if(!(WaitBlock->Flags & KPUSHLOCK_LOCK) || (PreviousWaitBlock == NULLPTR)) + { + /* Enter clearing loop */ + while(TRUE) + { + /* Clear the new state */ + NewState.Value = 0; + + /* Commit the cleared state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Cleared the lock state, break the loop */ + break; + } + + /* Update the snapshot pointer */ + OldState.Ptr = ActualState; + } + } + else + { + /* Update the cached last block pointer and unlink the target block */ + FirstWaitBlock->Last = PreviousWaitBlock; + WaitBlock->Previous = NULLPTR; + + /* Enter clearing loop */ + while(TRUE) + { + /* Strip the waking flag from the current state */ + NewState.Value = OldState.Value & ~KPUSHLOCK_WAKING; + + /* Commit the modified state */ + ActualState = RTL::Atomic::CompareExchangePointer(&PushLock->Ptr, OldState.Ptr, NewState.Ptr); + if(ActualState == OldState.Ptr) + { + /* Cleared the waking flag, break the loop */ + break; + } + + /* Update the snapshot pointer */ + OldState.Ptr = ActualState; + } + } + + /* Raise runlevel to DISPATCH level if there are multiple blocks */ + KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL, WaitBlock->Previous != NULLPTR); + + /* Traverse the reversed list */ + while(WaitBlock) + { + /* Save previous wait block */ + PreviousWaitBlock = WaitBlock->Previous; + + /* Clear the WAIT flag */ + if(!RTL::Atomic::BitTestAndReset((PLONG)&WaitBlock->Flags, 1)) + { + /* Thread is fully asleep, Signal its event and boost priority */ + KE::Event::SetEventBoostPriority(&WaitBlock->WakeEvent, NULLPTR); + } + + /* Go to the next block */ + WaitBlock = PreviousWaitBlock; + } +} + +/** + * Synchronizes the current thread with the PushLock. + * + * @param PushLock + * Supplies a pointer to the push lock to wait on. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::PushLock::WaitOnPushLock(IN PKPUSH_LOCK PushLock) +{ + KPUSH_LOCK State; + + /* Capture the snapshot of the pointer */ + State.Ptr = PushLock->Ptr; + + /* Verify if the lock is actively held by any thread */ + if(State.Value & KPUSHLOCK_LOCK) + { + /* Force serialization by acquiring the lock */ + AcquireExclusivePushLock(PushLock); + + /* Immediately release the lock */ + ReleaseExclusivePushLock(PushLock); + } +} diff --git a/xtoskrnl/ke/schedule.cc b/xtoskrnl/ke/schedule.cc new file mode 100644 index 0000000..5ebf8ad --- /dev/null +++ b/xtoskrnl/ke/schedule.cc @@ -0,0 +1,132 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/schedule.cc + * DESCRIPTION: XT Kernel Thread Scheduler + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Inserts a thread into the current processor's deferred ready list. + * + * @param Thread + * Supplies a pointer to the thread being deferred. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Scheduler::InsertDeferredReadyList(IN PKTHREAD Thread) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + + /* Retrieve the Processor Control Block (PRCB) for the executing core */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Tag the thread with the current CPU and update its scheduling state */ + Thread->DeferredProcessor = Prcb->CpuNumber; + Thread->State = DeferredReady; + + /* Insert the thread into the deferred ready list */ + RTL::LifoQueue::PushEntryList(&Prcb->DeferredReadyListHead, &Thread->SwapListEntry); +} + +/** + * Handles the expiration of the currently executing thread's time quantum. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Scheduler::ProcessQuantumEnd(VOID) +{ + UNIMPLEMENTED; +} + +/** + * Transitions a thread to the ready state and queues it for execution within the dispatcher database. + * + * @param Thread + * Supplies a pointer to the thread to be dispatched. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Scheduler::ProcessReadyThread(IN PKTHREAD Thread) +{ + PKPROCESS Process; + + /* Extract the process from the thread's APC state */ + Process = Thread->ApcState.Process; + + /* Verify if the process and thread are resident in physical memory */ + if(Process->State != ProcessInMemory) + { + /* Process is swapped out, place the thread in a transition state */ + Thread->State = Transition; + } + else if(!Thread->KernelStackResident) + { + /* Increment the active stack count and transition the thread */ + Process->StackCount++; + Thread->State = Transition; + } + else + { + /* Both process and thread's stack are fully resident, queue the thread for execution */ + InsertDeferredReadyList(Thread); + } +} + +/** + * Enqueues a thread into the target processor's execution queue. + * + * @param Thread + * Supplies a pointer to the thread that is ready for execution. + * + * @param Prcb + * Supplies a pointer to the Processor Control Block of the target core. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::Scheduler::QueueReadyThread(IN PKTHREAD Thread, + IN PKPROCESSOR_CONTROL_BLOCK Prcb) +{ + UNIMPLEMENTED; +} + +/** + * Prepares a thread for execution by safely acquiring the dispatcher database lock. + * + * @param Thread + * Supplies a pointer to the thread to be readied. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Scheduler::ReadyThread(IN PKTHREAD Thread) +{ + /* Raise runlevel to SYNC level and acquire the dispatcher database lock */ + KE::RaiseRunLevel RunLevel(SYNC_LEVEL); + KE::SystemQueuedSpinLockGuard DispatcherGuard(DispatcherLock); + + /* Evaluate residency and queue the thread */ + ProcessReadyThread(Thread); +} diff --git a/xtoskrnl/ke/spinlock.cc b/xtoskrnl/ke/spinlock.cc index 68ddc2c..a5131b3 100644 --- a/xtoskrnl/ke/spinlock.cc +++ b/xtoskrnl/ke/spinlock.cc @@ -11,7 +11,7 @@ /** - * Acquires a specified queued spinlock. + * Acquires a pre-allocated system queued spinlock. * * @param LockLevel * Supplies the queued spinlock level. @@ -25,7 +25,66 @@ VOID KE::SpinLock::AcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel) { /* Acquire the queued spinlock */ - AcquireSpinLock(KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel].Lock); + AcquireQueuedSpinLock(&KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel]); +} + +/** + * Initializes a lock queue handle and acquires an in-stack queued spin lock. + * + * @param SpinLock + * Supplies a pointer to the global queued spin lock to be acquired. + * + * @param LockQueueHandle + * Supplies a pointer to a caller-allocated lock queue handle. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::SpinLock::AcquireQueuedSpinLock(IN PKSPIN_LOCK SpinLock, + IN PKLOCK_QUEUE_HANDLE LockQueueHandle) +{ + /* Initialize the queue node */ + LockQueueHandle->LockQueue.Lock = SpinLock; + LockQueueHandle->LockQueue.Next = NULLPTR; + + /* Acquire queued spin lock */ + AcquireQueuedSpinLock(&LockQueueHandle->LockQueue); +} + +/** + * Acquires an in-stack queued spin lock. + * + * @param LockQueue + * Supplies a pointer to the local, stack-allocated lock queue entry. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::SpinLock::AcquireQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue) +{ + PKSPIN_LOCK_QUEUE LockQueueTail; + + /* Swap the global lock pointer */ + LockQueueTail = (PKSPIN_LOCK_QUEUE)RTL::Atomic::ExchangePointer((PVOID*)LockQueue->Lock, LockQueue); + if(LockQueueTail) + { + /* Mark the lock state as waiting and link local node to the previous queue tail */ + LockQueue->Lock = (PKSPIN_LOCK)((ULONG_PTR)LockQueue->Lock | LOCK_QUEUE_WAIT); + LockQueueTail->Next = LockQueue; + + /* Spin until the previous owner clears the wait flag */ + while((*(VOLATILE PULONG_PTR)&LockQueue->Lock) & LOCK_QUEUE_WAIT) + { + /* Yield the processor*/ + AR::CpuFunctions::YieldProcessor(); + } + } } /** @@ -148,7 +207,7 @@ KE::SpinLock::InitializeSpinLock(IN PKSPIN_LOCK SpinLock) } /** - * Releases a queued spinlock. + * Releases a pre-allocated system queued spinlock. * * @param LockLevel * Supplies the queued spinlock level. @@ -162,7 +221,65 @@ VOID KE::SpinLock::ReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_LEVEL LockLevel) { /* Clear the lock */ - ReleaseSpinLock(KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel].Lock); + ReleaseQueuedSpinLock(&KE::Processor::GetCurrentProcessorControlBlock()->LockQueue[LockLevel]); +} + +/** + * Releases an in-stack queued spin lock using the provided lock queue handle. + * + * @param LockQueueHandle + * Supplies a pointer to the lock queue handle that currently holds the lock. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::SpinLock::ReleaseQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockQueueHandle) +{ + /* Release queued spin lock */ + ReleaseQueuedSpinLock(&LockQueueHandle->LockQueue); +} + +/** + * Releases an in-stack queued spin lock. + * + * @param LockQueue + * Supplies a pointer to the local, stack-allocated lock queue entry that currently holds the lock. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::SpinLock::ReleaseQueuedSpinLock(IN PKSPIN_LOCK_QUEUE LockQueue) +{ + PKSPIN_LOCK_QUEUE NextLockQueue; + + /* Get the pointer to the next waiting processor in the queue */ + NextLockQueue = LockQueue->Next; + if(!NextLockQueue) + { + /* Remove the lock */ + if(RTL::Atomic::CompareExchangePointer((PVOID *)LockQueue->Lock, LockQueue, NULLPTR) == LockQueue) + { + /* Lock removed, exit */ + return; + } + + /* Wait until next pointer is updated */ + while(!(NextLockQueue = *(VOLATILE PKSPIN_LOCK_QUEUE *)&LockQueue->Next)) + { + /* Yield the processor*/ + AR::CpuFunctions::YieldProcessor(); + } + } + + /* Clean up local node and clear wait flag */ + LockQueue->Next = NULLPTR; + NextLockQueue->Lock = (PKSPIN_LOCK)((ULONG_PTR)NextLockQueue->Lock ^ LOCK_QUEUE_WAIT); } /** diff --git a/xtoskrnl/ke/sysserv.cc b/xtoskrnl/ke/sysserv.cc new file mode 100644 index 0000000..1afb3fd --- /dev/null +++ b/xtoskrnl/ke/sysserv.cc @@ -0,0 +1,25 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/sysserv.cc + * DESCRIPTION: System Services Descriptor Table + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Retrieves a pointer to the System Services Descriptor Table. + * + * @return This routine returns a pointer to the system services descriptor table. + * + * @since XT 1.0 + */ +XTAPI +PKSERVICE_DESCRIPTOR_TABLE +KE::SystemServices::GetSystemServicesDescriptorTable(VOID) +{ + /* Return NULLPTR as the system services table is not yet implemented */ + return NULLPTR; +} diff --git a/xtoskrnl/ke/systime.cc b/xtoskrnl/ke/systime.cc index 0c965e9..55bae7f 100644 --- a/xtoskrnl/ke/systime.cc +++ b/xtoskrnl/ke/systime.cc @@ -9,6 +9,26 @@ #include +/** + * Returns the current interrupt time. + * + * @param SystemTime + * Supplies a pointer to a variable that receives the current interrupt time. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::SystemTime::GetInterruptTime(OUT PLARGE_INTEGER InterruptTime) +{ + LARGE_INTEGER CurrentTime; + + /* Fetch the time using the lock-free shared data mechanism and return it */ + CurrentTime = KE::SharedData::GetInterruptTime(); + InterruptTime->QuadPart = CurrentTime.QuadPart; +} /** * Returns the current system time. @@ -152,6 +172,7 @@ KE::SystemTime::UpdateSystemTime(IN PKTRAP_FRAME TrapFrame, IN KRUNLEVEL RunLevel) { LARGE_INTEGER InterruptTime, SystemTime; + PKPROCESSOR_CONTROL_BLOCK ControlBlock; LONG CurrentTickOffset; /* Advance the global interrupt time on every hardware tick */ @@ -162,6 +183,12 @@ KE::SystemTime::UpdateSystemTime(IN PKTRAP_FRAME TrapFrame, /* Atomically consume the current tick budget and retrieve the pre-decrement value */ CurrentTickOffset = RTL::Atomic::ExchangeAdd32((PLONG)&TickOffset, -(LONG)Increment); + /* Retrieve the current processor control block */ + ControlBlock = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Verify the system timer expiration */ + KE::Timer::VerifySystemTimerExpiration(ControlBlock, TrapFrame, InterruptTime); + /* Determine whether the accumulated increments have crossed the full tick boundary */ if(CurrentTickOffset <= (LONG)Increment) { @@ -170,8 +197,9 @@ KE::SystemTime::UpdateSystemTime(IN PKTRAP_FRAME TrapFrame, SystemTime.QuadPart += TimeAdjustment; KE::SharedData::SetSystemTime(SystemTime); - /* Update the tick count */ + /* Update the tick count and reverify the system timer expiration */ KE::SharedData::IncrementTickCount(); + KE::Timer::VerifySystemTimerExpiration(ControlBlock, TrapFrame, InterruptTime); /* Reload the tick offset accumulator for the next full tick period */ TickOffset += MaximumIncrement; @@ -179,4 +207,9 @@ KE::SystemTime::UpdateSystemTime(IN PKTRAP_FRAME TrapFrame, /* Update processor and thread runtime accounting */ KE::Dispatcher::UpdateRunTime(TrapFrame, RunLevel); } + else + { + /* Increment the interrupt count */ + ControlBlock->InterruptCount++; + } } diff --git a/xtoskrnl/ke/timer.cc b/xtoskrnl/ke/timer.cc index 73d9d66..d6a3d53 100644 --- a/xtoskrnl/ke/timer.cc +++ b/xtoskrnl/ke/timer.cc @@ -4,6 +4,7 @@ * FILE: xtoskrnl/ke/timer.cc * DESCRIPTION: Kernel timer object support * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #include @@ -156,6 +157,25 @@ KE::Timer::QueryTimer(IN PKTIMER Timer) return DueTime; } +/** + * Removes a specified timer from the timer list. + * + * @param Timer + * Supplies a pointer to a timer object. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Timer::RemoveTimer(IN OUT PKTIMER Timer) +{ + /* Remove the timer from the list */ + Timer->Header.Inserted = FALSE; + RTL::LinkedList::RemoveEntryList(&Timer->TimerListEntry); +} + /** * Sets the supplied timer to expire at the specified time. * @@ -186,10 +206,17 @@ KE::Timer::SetTimer(IN PKTIMER Timer, } /** - * Removes a specified timer from the timer list. + * Verifies if any system timers have expired for the current tick and requests a software + * DISPATCH interrupt to process them if necessary. * - * @param Timer - * Supplies a pointer to a timer object. + * @param Prcb + * Supplies a pointer to the current Processor Control Block. + * + * @param TrapFrame + * Supplies a pointer to the trap frame representing the interrupted context. + * + * @param Time + * Supplies the current absolute interrupt time. * * @return This routine does not return any value. * @@ -197,9 +224,37 @@ KE::Timer::SetTimer(IN PKTIMER Timer, */ XTAPI VOID -KE::Timer::RemoveTimer(IN OUT PKTIMER Timer) +KE::Timer::VerifySystemTimerExpiration(IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PKTRAP_FRAME TrapFrame, + IN LARGE_INTEGER Time) { - /* Remove the timer from the list */ - Timer->Header.Inserted = FALSE; - RTL::LinkedList::RemoveEntryList(&Timer->TimerListEntry); + LARGE_INTEGER TickCount; + ULONG TimerHand; + PKTIMER Timer; + + /* Retrieve the current system tick count and calculate the index into the timer table */ + TickCount = KE::SharedData::GetTickCount(); + TimerHand = TickCount.LowPart & (KTIMER_TABLE_SIZE - 1); + + /* Check if there are any active timers scheduled */ + if(!RTL::LinkedList::ListEmpty(&TimerTableListHead[TimerHand])) + { + /* Retrieve the first timer object from the list */ + Timer = CONTAIN_RECORD((&TimerTableListHead[TimerHand])->Flink, KTIMER, TimerListEntry); + + /* Check if the timer due time has been reached */ + if(Timer->DueTime.QuadPart <= Time.QuadPart) + { + /* Ensure there is no pending timer expiration request */ + if(!Prcb->TimerRequest) + { + /* Register the timer expiration request and record a timer slot */ + Prcb->TimerRequest = (ULONG_PTR)TrapFrame; + Prcb->TimerHand = TimerHand; + + /* Request a DPC to safely retire the timer */ + HL::Irq::SendSoftwareInterrupt(DISPATCH_LEVEL); + } + } + } } diff --git a/xtoskrnl/mm/alloc.cc b/xtoskrnl/mm/alloc.cc index b6c6c6a..8841b56 100644 --- a/xtoskrnl/mm/alloc.cc +++ b/xtoskrnl/mm/alloc.cc @@ -46,7 +46,7 @@ MM::Allocator::AllocateNonPagedPoolPages(IN PFN_COUNT Pages, { /* Acquire the Non-Paged pool lock and raise runlevel to DISPATCH level */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard NonPagedPoolSpinLock(NonPagedPoolLock); + KE::SystemQueuedSpinLockGuard NonPagedPoolSpinLock(NonPagedPoolLock); /* Iterate through the free lists */ do @@ -124,10 +124,10 @@ MM::Allocator::AllocateNonPagedPoolPages(IN PFN_COUNT Pages, /* Acquire the Non-Paged pool lock and raise runlevel to DISPATCH level */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard NonPagedPoolSpinLock(NonPagedPoolLock); + KE::SystemQueuedSpinLockGuard NonPagedPoolSpinLock(NonPagedPoolLock); /* Acquire the PFN database lock */ - KE::QueuedSpinLockGuard PfnSpinLock(PfnLock); + KE::SystemQueuedSpinLockGuard PfnSpinLock(PfnLock); /* Check if there are enough available physical pages to back the allocation */ if(Pages >= MM::Pfn::GetAvailablePages()) @@ -203,8 +203,8 @@ MM::Allocator::AllocatePagedPoolPages(IN PFN_COUNT Pages, { UNIMPLEMENTED; - /* Return not implemented status code */ - return STATUS_NOT_IMPLEMENTED; + /* Temporarily fall back to non-paged pool */ + return AllocateNonPagedPoolPages(Pages, Memory); } /** @@ -282,7 +282,7 @@ MM::Allocator::AllocatePool(IN MMPOOL_TYPE PoolType, OUT PVOID *Memory) { /* Allocate pool */ - return AllocatePool(PoolType, Bytes, Memory, SIGNATURE32('N', 'o', 'n', 'e')); + return AllocatePool(PoolType, Bytes, Memory, TAG_MM_NONE); } /** @@ -351,7 +351,7 @@ MM::Allocator::AllocatePool(IN MMPOOL_TYPE PoolType, if(!RegisterBigAllocationTag(PoolEntry, Tag, (ULONG)SIZE_TO_PAGES(Bytes), PoolType)) { /* Fallback to a default tag */ - Tag = SIGNATURE32('B', 'i', 'g', 'A'); + Tag = TAG_MM_BIG_ALLOC; } /* Register the allocation in the tracking table */ @@ -721,8 +721,8 @@ MM::Allocator::ExpandBigAllocationsTable(VOID) FreePages(OldTable, &PagesFreed); /* Update the pool tracking statistics */ - UnregisterAllocationTag(SIGNATURE32('M', 'M', 'g', 'r'), PagesFreed << MM_PAGE_SHIFT, (MMPOOL_TYPE)0); - RegisterAllocationTag(SIGNATURE32('M', 'M', 'g', 'r'), ROUND_UP(AllocationBytes, MM_PAGE_SIZE), (MMPOOL_TYPE)0); + UnregisterAllocationTag(TAG_MM_MEMORY_MGR, PagesFreed << MM_PAGE_SHIFT, (MMPOOL_TYPE)0); + RegisterAllocationTag(TAG_MM_MEMORY_MGR, ROUND_UP(AllocationBytes, MM_PAGE_SIZE), (MMPOOL_TYPE)0); /* Return success */ return TRUE; @@ -798,7 +798,7 @@ MM::Allocator::FreeNonPagedPoolPages(IN PVOID VirtualAddress, /* Acquire the Non-Paged pool lock and raise runlevel to DISPATCH level */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard NonPagedPoolSpinLock(NonPagedPoolLock); + KE::SystemQueuedSpinLockGuard NonPagedPoolSpinLock(NonPagedPoolLock); /* Denote allocation boundaries */ FirstPfn->u3.e1.ReadInProgress = 0; @@ -1068,7 +1068,7 @@ XTSTATUS MM::Allocator::FreePool(IN PVOID VirtualAddress) { /* Free pool */ - return FreePool(VirtualAddress, SIGNATURE32('N', 'o', 'n', 'e')); + return FreePool(VirtualAddress, TAG_MM_NONE); } /** @@ -1116,7 +1116,7 @@ MM::Allocator::FreePool(IN PVOID VirtualAddress, else if(!Tag) { /* Fallback to a default tag */ - Tag = SIGNATURE32('B', 'i', 'g', 'A'); + Tag = TAG_MM_BIG_ALLOC; PageCount = 1; } @@ -1500,7 +1500,7 @@ MM::Allocator::InitializeBigAllocationsTracking(VOID) KE::SpinLock::InitializeSpinLock(&BigAllocationsTrackingTableLock); /* Register the allocation in the tracking table */ - RegisterAllocationTag(SIGNATURE32('M', 'M', 'g', 'r'), + RegisterAllocationTag(TAG_MM_MEMORY_MGR, SIZE_TO_PAGES(BigAllocationsTrackingTableSize * sizeof(POOL_TRACKING_BIG_ALLOCATIONS)), NonPagedPool); } @@ -1520,10 +1520,10 @@ MM::Allocator::PopulateAllocationTags(VOID) CULONG HotTags[] = { - SIGNATURE32('B', 'i', 'g', 'A'), /* Big Allocations */ - SIGNATURE32('M', 'M', 'g', 'r'), /* Memory Manager Internal */ - SIGNATURE32('N', 'o', 'n', 'e'), /* Untagged allocations */ - SIGNATURE32('O', 'v', 'f', 'l'), /* Global table expansion overflow fallback */ + TAG_MM_BIG_ALLOC, /* Big Allocations */ + TAG_MM_MEMORY_MGR, /* Memory Manager Internal */ + TAG_MM_NONE, /* Untagged allocations */ + TAG_MM_OVERFLOW, /* Global table expansion overflow fallback */ }; /* Seed all tags */ @@ -1754,7 +1754,7 @@ MM::Allocator::RegisterAllocationTagExpansion(IN ULONG Tag, if(Status != STATUS_SUCCESS || !NewTrackingTable) { /* Activate the global overflow bucket */ - AllocationsTrackingTable[AllocationsTrackingTableSize - 1].Tag = SIGNATURE32('O', 'v', 'f', 'l'); + AllocationsTrackingTable[AllocationsTrackingTableSize - 1].Tag = TAG_MM_OVERFLOW; UseOverflowBucket = TRUE; } else @@ -1775,7 +1775,7 @@ MM::Allocator::RegisterAllocationTagExpansion(IN ULONG Tag, AllocationsTrackingExpansionTableSize = Footprint / sizeof(POOL_TRACKING_TABLE);; /* Register the new allocation tag */ - RegisterAllocationTag(SIGNATURE32('M', 'M', 'g', 'r'), Footprint, NonPagedPool); + RegisterAllocationTag(TAG_MM_MEMORY_MGR, Footprint, NonPagedPool); } } } @@ -1809,7 +1809,7 @@ MM::Allocator::RegisterAllocationTagExpansion(IN ULONG Tag, { /* Free the old tracking table and unregister the allocation tag */ FreePages(OldTrackingTable, &FreedPages); - UnregisterAllocationTag(SIGNATURE32('M', 'M', 'g', 'r'), (SIZE_T)FreedPages * MM_PAGE_SIZE, NonPagedPool); + UnregisterAllocationTag(TAG_MM_MEMORY_MGR, (SIZE_T)FreedPages * MM_PAGE_SIZE, NonPagedPool); } /* Register the caller's original allocation */ @@ -2181,5 +2181,5 @@ MM::Allocator::UnregisterBigAllocationTag(IN PVOID VirtualAddress, /* Return an empty page count and a fallback tag */ *Pages = 0; - return SIGNATURE32('B', 'i', 'g', 'A'); + return TAG_MM_BIG_ALLOC; } diff --git a/xtoskrnl/mm/amd64/pagemap.cc b/xtoskrnl/mm/amd64/pagemap.cc index 932a447..8d749f3 100644 --- a/xtoskrnl/mm/amd64/pagemap.cc +++ b/xtoskrnl/mm/amd64/pagemap.cc @@ -755,6 +755,21 @@ MM::PageMapBasic::GetPxeVirtualAddress(IN PMMPXE PxePointer) return (PVOID)(((LONGLONG)PxePointer << 52) >> 16); } +/** + * Retrieves the maximum valid memory address accessible to user-mode applications. + * + * @return This routine returns the user-mode probe address boundary. + * + * @since XT 1.0 + */ +XTAPI +ULONG_PTR +MM::PageMapBasic::GetUserProbeAddress(VOID) +{ + /* Return user probe address */ + return MM_USER_PROBE_ADDRESS; +} + /** * Initializes page map information for basic paging (PML4). * @@ -852,6 +867,21 @@ MM::PageMapXpa::GetPxeVirtualAddress(IN PMMPXE PxePointer) return (PVOID)(((LONGLONG)PxePointer << 43) >> 7); } +/** + * Retrieves the maximum valid memory address accessible to user-mode applications. + * + * @return This routine returns the user-mode probe address boundary. + * + * @since XT 1.0 + */ +XTAPI +ULONG_PTR +MM::PageMapXpa::GetUserProbeAddress(VOID) +{ + /* Return user probe address */ + return MM_USER_PROBE_LA57_ADDRESS; +} + /** * Initializes page map information for XPA paging (PML5). * diff --git a/xtoskrnl/mm/amd64/pfn.cc b/xtoskrnl/mm/amd64/pfn.cc index 130d849..eaa4d5d 100644 --- a/xtoskrnl/mm/amd64/pfn.cc +++ b/xtoskrnl/mm/amd64/pfn.cc @@ -129,7 +129,7 @@ MM::Pfn::InitializePfnDatabase(VOID) /* Raise runlevel and acquire the PFN lock */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock); + KE::SystemQueuedSpinLockGuard SpinLock(SystemSpaceLock); /* Get the kernel initialization block */ InitializationBlock = KE::BootInformation::GetInitializationBlock(); diff --git a/xtoskrnl/mm/amd64/pte.cc b/xtoskrnl/mm/amd64/pte.cc index 5fdc2b2..1bac100 100644 --- a/xtoskrnl/mm/amd64/pte.cc +++ b/xtoskrnl/mm/amd64/pte.cc @@ -176,6 +176,7 @@ MM::Pte::MapP5E(IN PVOID StartAddress, IN PMMP5E TemplateP5e) { PMMP5E EndSpace, PointerP5e; + PFN_NUMBER PageFrameNumber; /* Get P5E addresses */ PointerP5e = MM::Paging::GetP5eAddress(StartAddress); @@ -187,8 +188,18 @@ MM::Pte::MapP5E(IN PVOID StartAddress, /* Check if P5E is already mapped */ if(!MM::Paging::PteValid(PointerP5e)) { - /* Map P5E */ - MM::Paging::SetPte(TemplateP5e, MM::Pfn::AllocateBootstrapPages(1), 0); + /* Attempt to allocate a physical page from the PFN database */ + PageFrameNumber = MM::Pfn::AllocatePhysicalPage(0); + + /* Check if the primary allocation failed */ + if(!PageFrameNumber) + { + /* Allocate a physical page from the fallback allocator */ + PageFrameNumber = MM::Pfn::AllocateBootstrapPages(1); + } + + /* Update the template with new page frame and write the PTE */ + MM::Paging::SetPte(TemplateP5e, PageFrameNumber, 0); *PointerP5e = *TemplateP5e; /* Clear the page table */ @@ -223,6 +234,7 @@ MM::Pte::MapPPE(IN PVOID StartAddress, IN PMMPPE TemplatePpe) { PMMPPE EndSpace, PointerPpe; + PFN_NUMBER PageFrameNumber; /* Get PPE addresses */ PointerPpe = MM::Paging::GetPpeAddress(StartAddress); @@ -234,8 +246,18 @@ MM::Pte::MapPPE(IN PVOID StartAddress, /* Check if PPE is already mapped */ if(!MM::Paging::PteValid(PointerPpe)) { - /* Map PPE */ - MM::Paging::SetPte(TemplatePpe, MM::Pfn::AllocateBootstrapPages(1), 0); + /* Attempt to allocate a physical page from the PFN database */ + PageFrameNumber = MM::Pfn::AllocatePhysicalPage(0); + + /* Check if the primary allocation failed */ + if(!PageFrameNumber) + { + /* Allocate a physical page from the fallback allocator */ + PageFrameNumber = MM::Pfn::AllocateBootstrapPages(1); + } + + /* Update the template with new page frame and write the PTE */ + MM::Paging::SetPte(TemplatePpe, PageFrameNumber, 0); *PointerPpe = *TemplatePpe; /* Clear the page table */ @@ -270,6 +292,7 @@ MM::Pte::MapPXE(IN PVOID StartAddress, IN PMMPXE TemplatePxe) { PMMPXE EndSpace, PointerPxe; + PFN_NUMBER PageFrameNumber; /* Get PXE addresses */ PointerPxe = MM::Paging::GetPxeAddress(StartAddress); @@ -281,8 +304,18 @@ MM::Pte::MapPXE(IN PVOID StartAddress, /* Check if PTE is already mapped */ if(!MM::Paging::PteValid(PointerPxe)) { - /* Map PTE */ - MM::Paging::SetPte(TemplatePxe, MM::Pfn::AllocateBootstrapPages(1), 0); + /* Attempt to allocate a physical page from the PFN database */ + PageFrameNumber = MM::Pfn::AllocatePhysicalPage(0); + + /* Check if the primary allocation failed */ + if(!PageFrameNumber) + { + /* Allocate a physical page from the fallback allocator */ + PageFrameNumber = MM::Pfn::AllocateBootstrapPages(1); + } + + /* Update the template with new page frame and write the PTE */ + MM::Paging::SetPte(TemplatePxe, PageFrameNumber, 0); *PointerPxe = *TemplatePxe; /* Clear the page table */ diff --git a/xtoskrnl/mm/data.cc b/xtoskrnl/mm/data.cc index 3505807..81af48f 100644 --- a/xtoskrnl/mm/data.cc +++ b/xtoskrnl/mm/data.cc @@ -60,6 +60,12 @@ LOADER_MEMORY_DESCRIPTOR MM::HardwarePool::HardwareAllocationDescriptors[MM_HARD /* Live address of kernel's hardware heap */ PVOID MM::HardwarePool::HardwareHeapStart = MM_HARDWARE_HEAP_START_ADDRESS; +/* Physical address of kernel's low memory region */ +PHYSICAL_ADDRESS MM::HardwarePool::LowMemoryPhysicalAddress; + +/* Virtual address of kernel's low memory region */ +PVOID MM::HardwarePool::LowMemoryVirtualAddress; + /* Number of used hardware allocation descriptors */ ULONG MM::HardwarePool::UsedHardwareAllocationDescriptors = 0; @@ -162,3 +168,9 @@ PFN_COUNT MM::Pte::TotalSystemFreePtes[MaximumPtePoolTypes]; /* Template PTE entry containing standard flags for a valid, present kernel page */ MMPTE MM::Pte::ValidPte; + +/* Global limit for system-wide non-paged pool quota allocations */ +SIZE_T MM::Quota::NonPagedPoolQuota; + +/* Global limit for system-wide paged pool quota allocations */ +SIZE_T MM::Quota::PagedPoolQuota; diff --git a/xtoskrnl/mm/hlpool.cc b/xtoskrnl/mm/hlpool.cc index c57ef3f..d958913 100644 --- a/xtoskrnl/mm/hlpool.cc +++ b/xtoskrnl/mm/hlpool.cc @@ -150,8 +150,11 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount, /** * Allocates a physical page in low memory (addressable in real-mode) and maps it into the virtual address space. * - * @param MemoryAddress - * Supplies a pointer to a variable that receives the identity-mapped virtual address of the allocated memory. + * @param PhysicalAddress + * Supplies a pointer to a variable that receives the physical address of the allocated memory. + * + * @param VirtualAddress + * Supplies a pointer to a variable that receives the virtual address of the allocated memory. * * @return This routine returns a status code indicating the success or failure of the operation. * @@ -159,39 +162,141 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount, */ XTAPI XTSTATUS -MM::HardwarePool::AllocateRealModeMemory(IN PFN_NUMBER PageCount, - OUT PVOID *MemoryAddress) +MM::HardwarePool::AllocateLowMemory(OUT PPHYSICAL_ADDRESS PhysicalAddress, + OUT PVOID *VirtualAddress) { - PHYSICAL_ADDRESS PhysicalAddress; - PFN_NUMBER PageFrameNumber; - PVOID VirtualAddress; + ULONG AllocationPages, TrampolineCodeSize; + PVOID TrampolineCode; XTSTATUS Status; + /* Check if low memory is already allocated and mapped */ + if(LowMemoryVirtualAddress && LowMemoryPhysicalAddress.QuadPart != 0) + { + /* Check if the caller requested the allocated addresses */ + if(PhysicalAddress != NULLPTR && VirtualAddress != NULLPTR) + { + /* Set the trampoline physical and virtual address and return success */ + *PhysicalAddress = LowMemoryPhysicalAddress; + *VirtualAddress = LowMemoryVirtualAddress; + } + + /* Return success */ + return STATUS_SUCCESS; + } + + /* Get trampoline information */ + AR::ProcessorSupport::GetTrampolineInformation(TrampolineApStartup, &TrampolineCode, &TrampolineCodeSize); + + /* Verify trampoline information */ + if(TrampolineCode == NULLPTR || TrampolineCodeSize == 0) + { + /* Failed to get trampoline information, return error */ + return STATUS_UNSUCCESSFUL; + } + + /* Compute number of pages for real-mode memory allocation (trampoline + processor start block + temporary stack) */ + AllocationPages = CalculateRealModeAllocationPages(TrampolineCodeSize); + /* Allocate physical memory in first 1MB */ - Status = AllocateHardwareMemory(PageCount, TRUE, 0x100000, &PhysicalAddress); + Status = AllocateHardwareMemory(AllocationPages, TRUE, 0x100000, &LowMemoryPhysicalAddress); if(Status != STATUS_SUCCESS) { /* Failed to allocate memory, return error */ return Status; } - /* Calculate virtual address and page frame number */ - VirtualAddress = (PVOID)(ULONG_PTR)PhysicalAddress.QuadPart; - PageFrameNumber = PhysicalAddress.QuadPart >> MM_PAGE_SHIFT; - - /* Identity map the memory to the virtual address */ - Status = MM::Paging::MapVirtualAddress(VirtualAddress, PageFrameNumber, MM_PTE_EXECUTE_READWRITE); + /* Map the memory to the virtual address */ + Status = MapHardwareMemory(LowMemoryPhysicalAddress, AllocationPages, FALSE, &LowMemoryVirtualAddress); if(Status != STATUS_SUCCESS) { - /* Failed to map memory, return error */ + /* Failed to map memory, free memory and return error */ + FreeHardwareMemory(LowMemoryPhysicalAddress, AllocationPages); return Status; } - /* Set the trampoline virtual address and return success */ - *MemoryAddress = VirtualAddress; + /* Check if the caller requested the allocated addresses */ + if(PhysicalAddress != NULLPTR && VirtualAddress != NULLPTR) + { + /* Set the trampoline physical and virtual address and return success */ + *PhysicalAddress = LowMemoryPhysicalAddress; + *VirtualAddress = LowMemoryVirtualAddress; + } + + /* Return success */ return STATUS_SUCCESS; } +/** + * Computes the total memory allocation size required for the real-mode trampoline execution environment. + * + * @param TrampolineCodeSize + * Supplies the size of the trampoline code in bytes. + * + * @return This routine returns the computed allocation size in pages. + * + * @since XT 1.0 + */ +XTAPI +ULONG +MM::HardwarePool::CalculateRealModeAllocationPages(IN ULONG TrampolineCodeSize) +{ + ULONG Size; + + /* Compute real-mode memory allocation size (trampoline + processor start block + temporary stack) */ + Size = TrampolineCodeSize + sizeof(PROCESSOR_START_BLOCK) + 512; + + /* Calculate and return number of pages */ + return (ULONG)(ROUND_UP(Size, MM_PAGE_SIZE) / MM_PAGE_SIZE); +} + +/** + * Releases physical memory allocated for kernel hardware layer. + * + * @param PhysicalAddress + * Supplies the physical address of the memory block to be freed. + * + * @param PageCount + * Supplies the number of pages associated with the allocation descriptor. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +MM::HardwarePool::FreeHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress, + IN PFN_NUMBER PageCount) +{ + PLOADER_MEMORY_DESCRIPTOR Descriptor; + PFN_NUMBER BasePage; + ULONG Index; + + /* Calculate base page from physical address */ + BasePage = PhysicalAddress.QuadPart >> MM_PAGE_SHIFT; + + /* Iterate through recorded hardware descriptors to find the matching allocation */ + for(Index = 0; Index < UsedHardwareAllocationDescriptors; Index++) + { + /* Get current hardware allocation descriptor */ + Descriptor = &HardwareAllocationDescriptors[Index]; + + /* Verify descriptor properties */ + if(Descriptor->MemoryType == LoaderHardwareCachedMemory && + Descriptor->BasePage == BasePage && + Descriptor->PageCount == PageCount) + { + /* Make descriptor available again */ + Descriptor->MemoryType = LoaderFree; + + /* Return success */ + return STATUS_SUCCESS; + } + } + + /* Descriptors not found, return error */ + return STATUS_INVALID_PARAMETER; +} + /** * Maps physical address to the virtual memory area used by kernel hardware layer. * @@ -291,6 +396,46 @@ MM::HardwarePool::MapHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress, return STATUS_SUCCESS; } +/** + * Establishes a temporary identity mapping for a specified physical memory range to facilitate real-mode execution. + * + * @param PhysicalAddress + * Supplies the physical address of the trampoline memory. + * + * @param Size + * Supplies the size of the trampoline memory allocation. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +MM::HardwarePool::MapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG Pages) +{ + PFN_NUMBER Index; + XTSTATUS Status; + + /* Identity map each page of the real-mode memory allocation */ + for(Index = 0; Index < Pages; Index++) + { + /* Map the current physical page */ + Status = MM::Paging::MapVirtualAddress((PVOID)(PhysicalAddress.QuadPart + (Index * MM_PAGE_SIZE)), + (PhysicalAddress.QuadPart >> MM_PAGE_SHIFT) + Index, + MM_PTE_EXECUTE_READWRITE); + if(Status != STATUS_SUCCESS) + { + /* Failed to map the page, unmap previously mapped pages and return the error code */ + UnmapRealModeMemory(PhysicalAddress, Index * MM_PAGE_SIZE); + return Status; + } + } + + /* Return success */ + return STATUS_SUCCESS; +} + /** * Marks existing mapping as CD/WT to avoid delays in write-back cache. * @@ -425,3 +570,34 @@ MM::HardwarePool::UnmapHardwareMemory(IN PVOID VirtualAddress, /* Return success */ return STATUS_SUCCESS; } + +/** + * Removes the temporary identity mapping for a real-mode memory region. + * + * @param PhysicalAddress + * Supplies the physical address of the trampoline memory. + * + * @param Size + * Supplies the size of the trampoline memory allocation. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +MM::HardwarePool::UnmapRealModeMemory(IN PHYSICAL_ADDRESS PhysicalAddress, + IN ULONG Size) +{ + PFN_NUMBER AllocationPages, Index; + + /* Calculate number of pages to unmap */ + AllocationPages = (ULONG)(ROUND_UP(Size, MM_PAGE_SIZE) / MM_PAGE_SIZE); + + /* Iterate over the allocation pages to remove the identity mapping */ + for(Index = 0; Index < AllocationPages; Index++) + { + /* Clear the page table entry for the current virtual address */ + MM::Paging::ClearPte(MM::Paging::GetPteAddress((PVOID)(PhysicalAddress.QuadPart + (Index * MM_PAGE_SIZE)))); + } +} diff --git a/xtoskrnl/mm/i686/pagemap.cc b/xtoskrnl/mm/i686/pagemap.cc index 9fe00e5..3a22c00 100644 --- a/xtoskrnl/mm/i686/pagemap.cc +++ b/xtoskrnl/mm/i686/pagemap.cc @@ -173,6 +173,21 @@ MM::PageMap::GetPteOffset(IN PVOID Address) return ((((ULONG_PTR)(Address)) >> MM_PTI_SHIFT) & (PageMapInfo.Xpa ? 0x1FF : 0x3FF)); } +/** + * Retrieves the maximum valid memory address accessible to user-mode applications. + * + * @return This routine returns the user-mode probe address boundary. + * + * @since XT 1.0 + */ +XTAPI +ULONG_PTR +MM::PageMap::GetUserProbeAddress(VOID) +{ + /* Return user probe address */ + return MM_USER_PROBE_ADDRESS; +} + /** * Gets the status of Extended Paging Address (XPA) mode. * diff --git a/xtoskrnl/mm/i686/pfn.cc b/xtoskrnl/mm/i686/pfn.cc index 34d5ae2..cebe5e8 100644 --- a/xtoskrnl/mm/i686/pfn.cc +++ b/xtoskrnl/mm/i686/pfn.cc @@ -51,7 +51,7 @@ MM::Pfn::InitializePfnDatabase(VOID) /* Raise runlevel and acquire PFN lock */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock); + KE::SystemQueuedSpinLockGuard SpinLock(SystemSpaceLock); /* Get the kernel initialization block */ InitializationBlock = KE::BootInformation::GetInitializationBlock(); diff --git a/xtoskrnl/mm/kpool.cc b/xtoskrnl/mm/kpool.cc index 0c49dfd..e083063 100644 --- a/xtoskrnl/mm/kpool.cc +++ b/xtoskrnl/mm/kpool.cc @@ -57,7 +57,7 @@ MM::KernelPool::AllocateKernelStack(OUT PVOID *Stack, /* Acquire the PFN database lock and raise runlevel to DISPATCH_LEVEL */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock); + KE::SystemQueuedSpinLockGuard SpinLock(SystemSpaceLock); /* Start iterating from the base of the reserved PTE block */ PointerPte = StackPte; @@ -155,7 +155,7 @@ MM::KernelPool::FreeKernelStack(IN PVOID Stack, /* Start a guarded code block */ { /* Acquire the PFN database lock */ - KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock); + KE::SystemQueuedSpinLockGuard SpinLock(SystemSpaceLock); /* Loop through each page of the stack that needs to be freed */ for(Index = 0; Index < StackPages; Index++) diff --git a/xtoskrnl/mm/mmgr.cc b/xtoskrnl/mm/mmgr.cc index b854db6..472cd4b 100644 --- a/xtoskrnl/mm/mmgr.cc +++ b/xtoskrnl/mm/mmgr.cc @@ -141,7 +141,7 @@ MM::Manager::GetPhysicalMemoryBlock(VOID) sizeof(PHYSICAL_MEMORY_RUN) * (DescriptorCount - 1), (PVOID*)&PrimaryBuffer, - SIGNATURE32('M', 'M', 'g', 'r')); + TAG_MM_MEMORY_MGR); if(Status != STATUS_SUCCESS || !PrimaryBuffer) { /* Primary pool allocation failed, return NULLPTR */ @@ -197,14 +197,14 @@ MM::Manager::GetPhysicalMemoryBlock(VOID) sizeof(PHYSICAL_MEMORY_RUN) * (RunCount - 1), (PVOID*)&SecondaryBuffer, - SIGNATURE32('M', 'M', 'g', 'r')); + TAG_MM_MEMORY_MGR); if(Status == STATUS_SUCCESS && SecondaryBuffer) { /* Copy the coalesced runs from the oversized primary buffer */ RtlCopyMemory(SecondaryBuffer->Run, PrimaryBuffer->Run, sizeof(PHYSICAL_MEMORY_RUN) * RunCount); /* Free the primary buffer */ - MM::Allocator::FreePool(PrimaryBuffer, SIGNATURE32('M', 'M', 'g', 'r')); + MM::Allocator::FreePool(PrimaryBuffer, TAG_MM_MEMORY_MGR); /* Update the primary buffer pointer */ PrimaryBuffer = SecondaryBuffer; @@ -232,6 +232,9 @@ XTAPI VOID MM::Manager::InitializeMemoryManager(VOID) { + /* Allocate low memory from the hardware pool before initializing the memory manager */ + MM::HardwarePool::AllocateLowMemory(NULLPTR, NULLPTR); + /* Scan memory descriptors provided by the boot loader */ MM::Pfn::ScanMemoryDescriptors(); @@ -256,6 +259,9 @@ MM::Manager::InitializeMemoryManager(VOID) /* Initialize page table */ MM::Pte::InitializePageTable(); + /* Initialize PFN database */ + MM::Pfn::InitializePfnDatabase(); + /* Initialize system PTE space */ MM::Pte::InitializeSystemPteSpace(); @@ -265,9 +271,6 @@ MM::Manager::InitializeMemoryManager(VOID) /* Initialize non-paged pool */ MM::Pool::InitializeNonPagedPool(); - /* Initialize PFN database */ - MM::Pfn::InitializePfnDatabase(); - /* Initialize allocations tracking tables */ MM::Allocator::InitializeAllocationsTracking(); MM::Allocator::InitializeBigAllocationsTracking(); diff --git a/xtoskrnl/mm/paging.cc b/xtoskrnl/mm/paging.cc index fb56317..4c6e81b 100644 --- a/xtoskrnl/mm/paging.cc +++ b/xtoskrnl/mm/paging.cc @@ -470,6 +470,21 @@ MM::Paging::GetPteVirtualAddress(IN PMMPTE PtePointer) return PmlRoutines->GetPteVirtualAddress(PtePointer); } +/** + * Retrieves the maximum valid memory address accessible to user-mode applications. + * + * @return This routine returns the user-mode probe address boundary. + * + * @since XT 1.0 + */ +XTAPI +ULONG_PTR +MM::Paging::GetUserProbeAddress(VOID) +{ + /* Return user probe address */ + return PmlRoutines->GetUserProbeAddress(); +} + /** * Gets current status of eXtended Physical Addressing (XPA). * diff --git a/xtoskrnl/mm/pfn.cc b/xtoskrnl/mm/pfn.cc index 5e8afee..9d72980 100644 --- a/xtoskrnl/mm/pfn.cc +++ b/xtoskrnl/mm/pfn.cc @@ -482,7 +482,7 @@ MM::Pfn::InitializePfnBitmap(VOID) Status = MM::Allocator::AllocatePool(NonPagedPool, (((HighestPhysicalPage + 1) + 31) / 32) * 4, (PVOID *)&BitMap, - SIGNATURE32('M', 'M', 'g', 'r')); + TAG_MM_MEMORY_MGR); if(Status != STATUS_SUCCESS || !BitMap) { /* Memory allocation failed, kernel panic */ diff --git a/xtoskrnl/mm/pool.cc b/xtoskrnl/mm/pool.cc index d231dcf..d171d86 100644 --- a/xtoskrnl/mm/pool.cc +++ b/xtoskrnl/mm/pool.cc @@ -261,7 +261,24 @@ XTAPI VOID MM::Pool::InitializePagedPool(VOID) { + PPOOL_DESCRIPTOR PoolDescriptor; + XTSTATUS Status; + + /* Not implemented */ UNIMPLEMENTED; + + /* Allocate a pool descriptor for the paged pool */ + Status = MM::Allocator::AllocatePool(NonPagedPool, sizeof(POOL_DESCRIPTOR), + (PVOID *)&PoolDescriptor, TAG_MM_MEMORY_POOL); + if(Status != STATUS_SUCCESS) + { + /* Allocation failed, raise kernel panic */ + KE::Crash::Panic(0x41, 0, -1, -1, -1); + } + + /* Store paged pool descriptor in the pool vector and initialize it */ + PoolVector[PagedPool] = PoolDescriptor; + InitializePoolDescriptor(PoolVector[PagedPool], PagedPool, 0, 0, NULLPTR); } /** diff --git a/xtoskrnl/mm/probe.cc b/xtoskrnl/mm/probe.cc new file mode 100644 index 0000000..d15f186 --- /dev/null +++ b/xtoskrnl/mm/probe.cc @@ -0,0 +1,278 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/mm/probe.cc + * DESCRIPTION: Memory Manager read/write probe support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** +* Probes a generic memory buffer for read accessibility. +* +* @param Address +* Supplies the base address of the buffer to probe. +* +* @param Size +* Supplies the size of the buffer in bytes. +* +* @param Alignment +* Supplies the required data alignment (must be 1, 2, 4, 8, or 16). +* +* @return This routine does not return any value. +* +* @since XT 1.0 +*/ +XTAPI +VOID +MM::Probe::ProbeForRead(IN CONST PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment) +{ + /* Check if the buffer size is non-zero */ + if(Size) + { + /* Check if the base address violates the required alignment */ + if(((ULONG_PTR)Address & (Alignment - 1)) != 0) + { + /* Raise datatype misalignment exception */ + RTL::Exception::RaiseStatus(STATUS_DATATYPE_MISALIGNMENT); + } + + /* Verify that the end address do not overflow and remains within user space */ + if((((ULONG_PTR)Address + Size) < (ULONG_PTR)Address) || + (((ULONG_PTR)Address + Size) > MM::Paging::GetUserProbeAddress())) + { + /* Raise access violation exception */ + RTL::Exception::RaiseStatus(STATUS_ACCESS_VIOLATION); + } + } +} + +/** + * Probes an array of fixed-size items for read accessibility. + * + * @param Array + * Supplies the base address of the array. + * + * @param ItemSize + * Supplies the size of a single array element in bytes. + * + * @param ItemCount + * Supplies the total number of elements in the array. + * + * @param Alignment + * Supplies the required array alignment (must be 1, 2, 4, 8, or 16). + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +MM::Probe::ProbeForReadArray(IN CONST PVOID Array, + IN ULONG ItemSize, + IN ULONG ItemCount, + IN ULONG Alignment) +{ + ULONG ArraySize; + + /* Calculate total array size */ + ArraySize = ItemSize * ItemCount; + + /* Check for integer overflow */ + if((ItemSize != 0) && (ArraySize / ItemSize != ItemCount)) + { + RTL::Exception::RaiseStatus(STATUS_INVALID_PARAMETER); + } + + /* Perform boundary and alignment verification */ + ProbeForRead(Array, ArraySize, Alignment); +} + +/** + * Probes a structure for read accessibility. + * + * @param Address + * Supplies the base address of the structure to probe. + * + * @param Size + * Supplies the total size of the structure in bytes. + * + * @param Alignment + * Supplies the required structure alignment (must be 1, 2, 4, 8, or 16). + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +MM::Probe::ProbeForReadStructure(IN CONST PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment) +{ + /* Check if the buffer size is zero or greater than 64k */ + if((Size == 0) || (Size > 0x10000)) + { + /* Perform boundary and alignment verification */ + ProbeForRead(Address, Size, Alignment); + } + else + { + /* Check if the base address violates the required alignment */ + if(((ULONG_PTR)Address & (Alignment - 1)) != 0) + { + /* Raise datatype misalignment exception */ + RTL::Exception::RaiseStatus(STATUS_DATATYPE_MISALIGNMENT); + } + + /* Check address space boundary */ + if((ULONG_PTR)Address >= (ULONG_PTR)MM::Paging::GetUserProbeAddress()) + { + /* Force access violation on the invalid probe boundary */ + *(VOLATILE PULONG CONST)MM::Paging::GetUserProbeAddress() = 0; + } + } +} + +/** + * Probes a generic memory buffer for write accessibility. + * + * @param Address + * Supplies the base address of the buffer to probe. + * + * @param Size + * Supplies the size of the buffer in bytes. + * + * @param Alignment + * Supplies the required data alignment (must be 1, 2, 4, 8, or 16). + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +MM::Probe::ProbeForWrite(IN PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment) +{ + ULONG_PTR CurrentAddress, LastAddress; + + /* Check if the buffer size is non-zero */ + if(Size) + { + /* Perform boundary and alignment verification */ + ProbeForRead(Address, Size, Alignment); + + /* Store the current address */ + CurrentAddress = (ULONG_PTR)Address; + + /* Calculate the end boundary of the requested buffer */ + LastAddress = CurrentAddress + Size - 1; + LastAddress = (LastAddress & ~(MM_PAGE_SIZE - 1)) + MM_PAGE_SIZE; + + /* Loop through each page in the range */ + while(CurrentAddress < LastAddress) + { + /* Touch the page with a read-write cycle */ + *(VOLATILE PCHAR)CurrentAddress = *(volatile CHAR*)CurrentAddress; + + /* Advance to the next page */ + CurrentAddress = (CurrentAddress & ~(MM_PAGE_SIZE - 1)) + MM_PAGE_SIZE; + } + } +} + +/** + * Probes an array of fixed-size items for write accessibility. + * + * @param Array + * Supplies the base address of the array. + * + * @param ItemSize + * Supplies the size of a single array element in bytes. + * + * @param ItemCount + * Supplies the total number of elements in the array. + * + * @param Alignment + * Supplies the required data alignment (must be 1, 2, 4, 8, or 16). + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +MM::Probe::ProbeForWriteArray(IN OUT PVOID Array, + IN ULONG ItemSize, + IN ULONG ItemCount, + IN ULONG Alignment) +{ + ULONG ArraySize; + + /* Calculate total array size */ + ArraySize = ItemSize * ItemCount; + + /* Check for integer overflow */ + if((ItemSize != 0) && (ArraySize / ItemSize != ItemCount)) + { + RTL::Exception::RaiseStatus(STATUS_INVALID_PARAMETER); + } + + /* Perform write accessibility verification */ + ProbeForWrite(Array, ArraySize, Alignment); +} + + + + +/** + * Probes a structure for write accessibility. + * + * @param Address + * Supplies the base address of the structure to probe. + * + * @param Size + * Supplies the total size of the structure in bytes. + * + * @param Alignment + * Supplies the required structure alignment (must be 1, 2, 4, 8, or 16). + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +MM::Probe::ProbeForWriteStructure(IN PVOID Address, + IN SIZE_T Size, + IN ULONG Alignment) +{ + /* Delegate fast-path boundary and alignment verification to the Read probe (DRY) */ + ProbeForReadStructure(Address, Size, Alignment); + + /* Check if the buffer size is zero or exceeds the page size */ + if((Size == 0) || (Size >= MM_PAGE_SIZE)) + { + /* Perform write accessibility verification */ + ProbeForWrite(Address, Size, Alignment); + } + else + { + /* Touch the first byte to verify write access */ + *(VOLATILE PUCHAR)Address = *(VOLATILE PUCHAR)Address; + + /* Check if the buffer size exceeds the alignment */ + if(Size > Alignment) + { + /* Touch the last byte to ensure full structure spans valid memory */ + ((VOLATILE PUCHAR)Address)[(Size - 1) & ~(SIZE_T)(Alignment - 1)] = + ((VOLATILE PUCHAR)Address)[(Size - 1) & ~(SIZE_T)(Alignment - 1)]; + } + } +} diff --git a/xtoskrnl/mm/pte.cc b/xtoskrnl/mm/pte.cc index de380f0..48b196c 100644 --- a/xtoskrnl/mm/pte.cc +++ b/xtoskrnl/mm/pte.cc @@ -242,6 +242,7 @@ MM::Pte::MapPDE(IN PVOID StartAddress, IN PMMPDE TemplatePde) { PMMPDE EndSpace, PointerPde; + PFN_NUMBER PageFrameNumber; /* Get PDE addresses */ PointerPde = MM::Paging::GetPdeAddress(StartAddress); @@ -253,8 +254,18 @@ MM::Pte::MapPDE(IN PVOID StartAddress, /* Check if PDE is already mapped */ if(!MM::Paging::PteValid(PointerPde)) { - /* Map PDE */ - MM::Paging::SetPte(TemplatePde, MM::Pfn::AllocateBootstrapPages(1), 0); + /* Attempt to allocate a physical page from the PFN database */ + PageFrameNumber = MM::Pfn::AllocatePhysicalPage(0); + + /* Check if the primary allocation failed */ + if(!PageFrameNumber) + { + /* Allocate a physical page from the fallback allocator */ + PageFrameNumber = MM::Pfn::AllocateBootstrapPages(1); + } + + /* Update the template with new page frame and write the PTE */ + MM::Paging::SetPte(TemplatePde, PageFrameNumber, 0); MM::Paging::WritePte(PointerPde, *TemplatePde); /* Clear the page table */ @@ -289,6 +300,7 @@ MM::Pte::MapPTE(IN PVOID StartAddress, IN PMMPTE TemplatePte) { PMMPTE EndSpace, PointerPte; + PFN_NUMBER PageFrameNumber; /* Get PTE addresses */ PointerPte = MM::Paging::GetPteAddress(StartAddress); @@ -300,8 +312,18 @@ MM::Pte::MapPTE(IN PVOID StartAddress, /* Check if PTE is already mapped */ if(!MM::Paging::PteValid(PointerPte)) { - /* Map PTE */ - MM::Paging::SetPte(TemplatePte, MM::Pfn::AllocateBootstrapPages(1), 0); + /* Attempt to allocate a physical page from the PFN database */ + PageFrameNumber = MM::Pfn::AllocatePhysicalPage(0); + + /* Check if the primary allocation failed */ + if(!PageFrameNumber) + { + /* Allocate a physical page from the fallback allocator */ + PageFrameNumber = MM::Pfn::AllocateBootstrapPages(1); + } + + /* Update the template with new page frame and write the PTE */ + MM::Paging::SetPte(TemplatePte, PageFrameNumber, 0); MM::Paging::WritePte(PointerPte, *TemplatePte); /* Clear the page table */ @@ -313,7 +335,6 @@ MM::Pte::MapPTE(IN PVOID StartAddress, } } - /** * Releases a block of system PTEs into a specified pool. * @@ -344,7 +365,7 @@ MM::Pte::ReleaseSystemPtes(IN PMMPTE StartingPte, /* Raise runlevel and acquire lock to protect the PTE pool */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock); + KE::SystemQueuedSpinLockGuard SpinLock(SystemSpaceLock); /* Increment the total number of available PTEs in this pool */ TotalSystemFreePtes[SystemPtePoolType] += NumberOfPtes; @@ -457,7 +478,7 @@ MM::Pte::ReserveSystemPtes(IN PFN_COUNT NumberOfPtes, /* Raise runlevel and acquire lock to protect the PTE pool */ KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); - KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock); + KE::SystemQueuedSpinLockGuard SpinLock(SystemSpaceLock); /* Find a free PTE cluster large enough for the request */ if(!FindFreeCluster(NumberOfPtes, SystemPtePoolType, &NextPte, &PreviousPte)) diff --git a/xtoskrnl/mm/quota.cc b/xtoskrnl/mm/quota.cc new file mode 100644 index 0000000..927412a --- /dev/null +++ b/xtoskrnl/mm/quota.cc @@ -0,0 +1,69 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/mm/quota.cc + * DESCRIPTION: Memory Manager Quota support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Attempts to increase the pool quota limit. + * + * @param PoolType + * Supplies the type of memory pool whose quota limit is being evaluated for an increase. + * + * @param CurrentQuotaLimit + * Supplies the current quota limit, in bytes, for the requested pool. + * + * @param NewQuotaLimit + * Receives the newly established quota limit if the increase was successful. + * + * @return This routine returns TRUE if the quota limit was successfully raised, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +MM::Quota::RaisePoolQuota(IN MMPOOL_TYPE PoolType, + IN SIZE_T CurrentQuotaLimit, + OUT PSIZE_T NewQuotaLimit +) +{ + UNIMPLEMENTED; + return FALSE; +} + +/** + * Returns a specified amount of quota back to the global system pool. + * + * @param PoolType + * Supplies the type of memory pool receiving the returned quota. + * + * @param ReturnedQuota + * Supplies the amount of quota, in bytes, being returned to the system. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +MM::Quota::ReturnPoolQuota(IN MMPOOL_TYPE PoolType, + IN SIZE_T ReturnedQuota) +{ + /* Route the returned quota to the appropriate pool */ + switch(PoolType) + { + case PagedPool: + /* Return quota to the paged pool */ + PagedPoolQuota -= ReturnedQuota; + break; + default: + /* Return quota to the non-paged pool */ + NonPagedPoolQuota -= ReturnedQuota; + break; + } +} diff --git a/xtoskrnl/ob/data.cc b/xtoskrnl/ob/data.cc new file mode 100644 index 0000000..cd8cea5 --- /dev/null +++ b/xtoskrnl/ob/data.cc @@ -0,0 +1,52 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/data.cc + * DESCRIPTION: Object Manager global and static data + * DEVELOPERS: Aiken Harris + */ + +#include + + +/* Synchronizes shared read and exclusive write access to system device map structures */ +KPUSH_LOCK OB::DeviceMap::DeviceMapLock; + +/* Pointer to the system device map */ +PDEVICE_MAP OB::DeviceMap::SystemDeviceMap = NULLPTR; + +/* Indicates whether the system employs unique device maps */ +BOOLEAN OB::DeviceMap::UniqueDeviceMaps; + +/* The list head for all active handle tables in the system */ +LIST_ENTRY OB::HandleTable::HandleTableListHead; + +/* Pushlock used to synchronize access to the handle table list */ +KPUSH_LOCK OB::HandleTable::HandleTableListLock; + +/* Pointer to the system-wide kernel handle table */ +PHANDLE_TABLE OB::LifeCycle::KernelHandleTable; + +/* System work queue item responsible for scheduling the deferred object deletion */ +WORK_QUEUE_ITEM OB::LifeCycle::RemoveObjectWorkItem; + +/* The list head for tracking objects that have been marked for deferred deletion */ +PVOID OB::LifeCycle::RemoveObjectList; + +/* General lookaside list used for allocation and deallocation of OBJECT_CREATE_INFORMATION structures */ +GENERAL_LOOKASIDE OB::Manager::CreateInfoList; + +/* General lookaside list used for allocation and deallocation buffers for Unicode object names */ +GENERAL_LOOKASIDE OB::Manager::NameBufferList; + +/* Default kernel event utilized by the Object Manager */ +KEVENT OB::TypeRegistry::DefaultEvent; + +/* Fundamental Type object type */ +POBJECT_TYPE OB::TypeRegistry::MasterObjectType; + +/* Points to the Object Types directory */ +POBJECT_DIRECTORY OB::TypeRegistry::ObjectTypeDirectory; + +/* Index-based lookup for all registered object types */ +POBJECT_TYPE OB::TypeRegistry::ObjectTypesTable[OBJECT_MAX_DEFINED_OBJECT_TYPES]; diff --git a/xtoskrnl/ob/devmap.cc b/xtoskrnl/ob/devmap.cc new file mode 100644 index 0000000..7e8bfe4 --- /dev/null +++ b/xtoskrnl/ob/devmap.cc @@ -0,0 +1,125 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/devmap.cc + * DESCRIPTION: Object Manager Device Map + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Retrieves the Global Devices Directory associated with a given directory's device map. + * + * @param Directory + * Supplies a pointer to the object directory to query. + * + * @return Returns a pointer to the global devices directory, or NULLPTR if none exists. + * + * @since XT 1.0 + */ +XTAPI +POBJECT_DIRECTORY +OB::DeviceMap::GetGlobalDevicesDirectory(IN POBJECT_DIRECTORY Directory) +{ + POBJECT_DIRECTORY GlobalDevicesDirectory; + + /* Assume no mapping exists */ + GlobalDevicesDirectory = NULLPTR; + + /* Enter guarded region and acquire the device map lock */ + KE::GuardedRegionGuard GuardedRegion; + KE::PushLockExclusiveGuard PushLock(&DeviceMapLock); + + /* Check if the directory has an associated device map */ + if(Directory->DeviceMap) + { + /* Extract the global devices directory */ + GlobalDevicesDirectory = Directory->DeviceMap->GlobalDevicesDirectory; + } + + /* Return the resolved directory */ + return GlobalDevicesDirectory; +} + +/** + * Retrieves the current state of the unique device maps configuration. + * + * @return This routine returns TRUE if unique device maps are enabled, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::DeviceMap::GetUniqueDeviceMaps(VOID) +{ + /* Return the unique device maps flag */ + return UniqueDeviceMaps; +} + +/** + * Inherits the device map from a parent process or assigns the system default. + * + * @param NewProcess + * Supplies the newly created process that will inherit the device map. + * + * @param ParentProcess + * Supplies the optional parent process to inherit the device map from. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +VOID +OB::DeviceMap::InheritDeviceMap(IN PEPROCESS NewProcess, + IN PEPROCESS ParentProcess) +{ + PDEVICE_MAP TargetDeviceMap; + + /* Acquire the device map lock */ + KE::PushLockExclusiveGuard PushLock(&DeviceMapLock); + + /* Determine the source of the device map */ + if(ParentProcess) + { + /* Inherit the device map from the provided parent process */ + TargetDeviceMap = (PDEVICE_MAP)ParentProcess->DeviceMap; + } + else + { + /* No parent process provided, use system device map */ + TargetDeviceMap = SystemDeviceMap; + } + + /* Check if a valid device map was resolved */ + if(TargetDeviceMap) + { + /* Increment the reference count of the target device map */ + TargetDeviceMap->ReferenceCount++; + + /* Assign the device map to the process */ + NewProcess->DeviceMap = TargetDeviceMap; + } +} + +/** + * Initializes the Object Manager's device map subsystem. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::DeviceMap::InitializeDeviceMap(VOID) +{ + /* Initialize device map lock */ + KE::PushLock::InitializePushLock(&DeviceMapLock); + + /* Temporarily disable unique device maps */ + UniqueDeviceMaps = FALSE; + + /* Return success */ + return STATUS_SUCCESS; +} diff --git a/xtoskrnl/ob/handle.cc b/xtoskrnl/ob/handle.cc new file mode 100644 index 0000000..74be1c1 --- /dev/null +++ b/xtoskrnl/ob/handle.cc @@ -0,0 +1,76 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/handle.cc + * DESCRIPTION: Object Manager Handle Management + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Encodes a standard handle into a kernel-space handle. + * + * @param Handle + * Supplies the raw standard handle to be encoded. + * + * @return This routine returns the encoded kernel handle. + * + * @since XT 1.0 + */ +XTFASTCALL +HANDLE +OB::Handle::DecodeKernelHandle(IN HANDLE Handle) +{ + /* Clear the kernel handle flag */ + return (HANDLE)(OBJECT_HANDLE_KERNEL_MASK ^ (ULONG_PTR)Handle); +} + +/** + * Decodes a kernel-space handle into a standard handle. + * + * @param Handle + * Supplies the encoded kernel handle to be decoded. + * + * @return This routine returns the decoded standard handle. + * + * @since XT 1.0 + */ +XTFASTCALL +HANDLE +OB::Handle::EncodeKernelHandle(IN HANDLE Handle) +{ + /* Set the kernel handle flag */ + return (HANDLE)(OBJECT_HANDLE_KERNEL_MASK | (ULONG_PTR)Handle); +} + +/** + * Retrieves and decodes the handle attributes from a given handle table entry. + * + * @param HandleTableEntry + * Supplies a pointer to the handle table entry to inspect. + * + * @return This routine returns a bitmask representing the active handle attributes. + * + * @since XT 1.0 + */ +XTFASTCALL +ULONG +OB::Handle::GetHandleAttributes(IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + ULONG Attributes; + + /* Extract the base attributes */ + Attributes = HandleTableEntry->ObAttributes; + + /* Check if the protect-on-close access bit is set */ + if(HandleTableEntry->GrantedAccess & OBJECT_ACCESS_PROTECT_CLOSE_BIT) + { + /* Retain valid handle attributes and set the protect-close flag */ + return (Attributes & OBJECT_HANDLE_ATTRIBUTES) | OBJECT_PROTECT_CLOSE; + } + + /* Isolate and return the inherit and audit-on-close flags */ + return Attributes & (OBJECT_INHERIT | OBJECT_AUDIT_OBJECT_CLOSE); +} diff --git a/xtoskrnl/ob/hndltlb.cc b/xtoskrnl/ob/hndltlb.cc new file mode 100644 index 0000000..ec799bd --- /dev/null +++ b/xtoskrnl/ob/hndltlb.cc @@ -0,0 +1,2358 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/hndltbl.cc + * DESCRIPTION: Object Manager Handle Table Management Interface + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Allocates and initializes a new handle table structure. + * + * @param Process + * Supplies the optional process to charge quota against. + * + * @param Initialize + * Indicates whether to build the initial free list. + * + * @return This routine returns a pointer to the handle table, or NULL pointer on failure. + * + * @since XT 1.0 + */ +PHANDLE_TABLE +OB::HandleTable::AllocateHandleTable(IN PEPROCESS Process, + IN BOOLEAN Initialize) +{ + PHANDLE_TABLE_ENTRY HandleEntry, LowLevelTable; + PHANDLE_TABLE HandleTable; + ULONG Index; + + /* Allocate a memory block for the handle table structure */ + HandleTable = (PHANDLE_TABLE)AllocateTableMemory(Process, sizeof(HANDLE_TABLE), TRUE); + if(!HandleTable) + { + /* Memory allocation failed, return a NULL pointer */ + return NULLPTR; + } + + /* Allocate a memory block for the initial low-level handle array */ + LowLevelTable = (PHANDLE_TABLE_ENTRY)AllocateTableMemory(Process, MM_PAGE_SIZE, FALSE); + if(!LowLevelTable) + { + /* Allocation failed, free the handle table structure and return a NULL pointer */ + FreeTableMemory(Process, HandleTable, sizeof(HANDLE_TABLE)); + return NULLPTR; + } + + /* Publish the low-level table into the handle table structure */ + HandleTable->TableCode = (ULONG_PTR)LowLevelTable; + + /* Initialize the first entry of the root table */ + HandleEntry = &LowLevelTable[0]; + HandleEntry->NextFreeTableEntry = OBJECT_HANDLE_ADDITIONAL_INFO_SIGNATURE; + HandleEntry->Value = 0; + + /* Check if the initialization is required */ + if(Initialize) + { + /* Advance to the first handle entry */ + HandleEntry++; + + /* Iterate through the low-level table block */ + for(Index = 1; Index < OBJECT_HANDLE_LOWLEVEL_COUNT - 1; Index++) + { + /* Link the current entry to the next available handle index */ + HandleEntry->Value = 0; + HandleEntry->NextFreeTableEntry = (Index + 1) * OBJECT_HANDLE_VALUE_INCREMENT; + + /* Advance the pointer */ + HandleEntry++; + } + + /* Terminate the free list chain */ + HandleEntry->Value = 0; + HandleEntry->NextFreeTableEntry = 0; + + /* Initialize the free list head */ + HandleTable->FirstFreeHandle = (PHANDLE_TABLE_ENTRY)(ULONG_PTR)OBJECT_HANDLE_VALUE_INCREMENT; + } + + /* Set the next handle needing pool */ + HandleTable->NextHandleNeedingPool = OBJECT_HANDLE_LOWLEVEL_COUNT * OBJECT_HANDLE_VALUE_INCREMENT; + + /* Associate the handle table with the target process */ + HandleTable->QuotaProcess = Process; + + /* Check if a target quota process was provided */ + if(Process) + { + /* Inherit the process identifier */ + HandleTable->UniqueProcessId = Process->UniqueProcessId; + } + else + { + /* Inherit the process identifier from the current process */ + HandleTable->UniqueProcessId = PS::Process::GetCurrentProcess()->UniqueProcessId; + } + + /* Clear all flags */ + HandleTable->Flags = 0; + + /* Iterate through the handle table pushlocks */ + for(Index = 0; Index < OBJECT_HANDLE_VALUE_INCREMENT; Index++) + { + /* Initialize the pushlock */ + KE::PushLock::InitializePushLock(&HandleTable->HandleTableLock[Index]); + } + + /* Initialize the pushlock used for handle contention synchronization */ + KE::PushLock::InitializePushLock(&HandleTable->HandleContentionEvent); + + /* Return the pointer to the handle table */ + return HandleTable; +} + +/** + * Allocates a new handle table entry. + * + * @param HandleTable + * Supplies the handle table to allocate from. + * + * @param Initialize + * Indicates whether to initialize the free list for new entries. + * + * @return This routine returns TRUE on success, or FALSE otherwise. + * + * @since XT 1.0 + */ +BOOLEAN +OB::HandleTable::AllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN BOOLEAN Initialize) +{ + PHANDLE_TABLE_ENTRY **HighLevelTable, **HighLevelTableEntry, LowLevelTable, *MediumLevelTable, *MediumLevelTableEntry; + ULONG FirstFree, FirstFreeIndex, HighLevelIndex, MediumLevelIndex, OldIndex, RemainingIndex, TableLevel; + ULONG_PTR CapturedTable; + + /* Capture the current table structure */ + CapturedTable = HandleTable->TableCode; + + /* Extract the depth level of the handle table */ + TableLevel = (ULONG)(CapturedTable & OBJECT_HANDLE_LEVEL_CODE_MASK); + + /* Mask out the level bits */ + CapturedTable = CapturedTable & ~OBJECT_HANDLE_LEVEL_CODE_MASK; + + /* Initialize the low-level table pointer */ + LowLevelTable = NULLPTR; + + /* Check if the handle table is currently operating as a single-level structure */ + if(!TableLevel) + { + /* Allocate a medium-level table directory */ + MediumLevelTable = AllocateMediumLevelTable(HandleTable, Initialize, &LowLevelTable); + if(!MediumLevelTable) + { + /* Table directory allocation failed, return FALSE */ + return FALSE; + } + + /* Link the low-level table into the medium-level directory */ + MediumLevelTable[1] = MediumLevelTable[0]; + + /* Set the original flat table as the first entry in the medium-level directory */ + MediumLevelTable[0] = (PHANDLE_TABLE_ENTRY)CapturedTable; + + /* Encode the table pointer */ + CapturedTable = ((ULONG_PTR)MediumLevelTable) | 1; + + /* Publish the multi-level table structure */ + RTL::Atomic::ExchangePointer((PVOID *)&HandleTable->TableCode, (PVOID)CapturedTable); + } + else if(TableLevel == 1) + { + /* Cast the captured table pointer to a medium-level directory array */ + MediumLevelTableEntry = (PHANDLE_TABLE_ENTRY *)CapturedTable; + + /* Calculate the directory index */ + MediumLevelIndex = HandleTable->NextHandleNeedingPool / + (OBJECT_HANDLE_LOWLEVEL_COUNT * OBJECT_HANDLE_VALUE_INCREMENT); + + /* Check if the current medium-level directory has remaining capacity */ + if(MediumLevelIndex < OBJECT_HANDLE_MEDIUMLEVEL_COUNT) + { + /* Allocate a low-level table leaf */ + LowLevelTable = AllocateLowLevelTable(HandleTable, Initialize); + if(!LowLevelTable) + { + /* Table allocation failed, return FALSE */ + return FALSE; + } + + /* Publish the low-level table */ + RTL::Atomic::ExchangePointer((PVOID *)(&MediumLevelTableEntry[MediumLevelIndex]), LowLevelTable); + } + else + { + /* The medium-level directory is exhausted, allocate a high-level table directory */ + HighLevelTable = (PHANDLE_TABLE_ENTRY**)AllocateTableMemory(HandleTable->QuotaProcess, + OBJECT_HANDLE_HIGHLEVEL_SIZE, TRUE); + if(!HighLevelTable) + { + /* Table allocation failed, return FALSE */ + return FALSE; + } + + /* Allocate a medium-level directory */ + MediumLevelTable = AllocateMediumLevelTable(HandleTable, Initialize, &LowLevelTable); + if(!MediumLevelTable) + { + /* Free the high-level table and return FALSE */ + FreeTableMemory(HandleTable->QuotaProcess, HighLevelTable, OBJECT_HANDLE_HIGHLEVEL_SIZE); + return FALSE; + } + + /* Link the medium-level structure as the first branch */ + HighLevelTable[0] = (PHANDLE_TABLE_ENTRY *)CapturedTable; + + /* Link the medium-level structure as the second branch */ + HighLevelTable[1] = MediumLevelTable; + + /* Encode the table pointer */ + CapturedTable = ((ULONG_PTR)HighLevelTable) | 2; + + /* Publish the high-level table structure */ + RTL::Atomic::ExchangePointer((PVOID *)&HandleTable->TableCode, (PVOID)CapturedTable); + } + } + else if(TableLevel == 2) + { + /* Cast the captured table pointer to a high-level directory array */ + HighLevelTableEntry = (PHANDLE_TABLE_ENTRY **)CapturedTable; + + /* Calculate the root index into the high-level table */ + HighLevelIndex = HandleTable->NextHandleNeedingPool / + (OBJECT_HANDLE_MEDIUMLEVEL_THRESHOLD * OBJECT_HANDLE_VALUE_INCREMENT); + + /* Ensure there is room in the high-level table for the entry */ + if(HighLevelIndex >= OBJECT_HANDLE_HIGHLEVEL_COUNT) + { + /* Table is full, return FALSE */ + return FALSE; + } + + /* Check if the required medium-level directory branch needs to be created */ + if(!HighLevelTableEntry[HighLevelIndex]) + { + /* Allocate a medium-level table directory */ + MediumLevelTable = AllocateMediumLevelTable(HandleTable, Initialize, &LowLevelTable); + if(!MediumLevelTable) + { + /* Table allocation failed, return FALSE */ + return FALSE; + } + + /* Publish the medium-level directory */ + RTL::Atomic::ExchangePointer((PVOID *)&HighLevelTableEntry[HighLevelIndex], MediumLevelTable); + } + else + { + /* Calculate the localized index within the medium-level branch */ + RemainingIndex = (HandleTable->NextHandleNeedingPool / OBJECT_HANDLE_VALUE_INCREMENT) - + HighLevelIndex * OBJECT_HANDLE_MEDIUMLEVEL_THRESHOLD; + MediumLevelIndex = RemainingIndex / OBJECT_HANDLE_LOWLEVEL_COUNT; + + /* Allocate a low-level table leaf */ + LowLevelTable = AllocateLowLevelTable(HandleTable, Initialize); + if(!LowLevelTable) + { + /* Table allocation failed, return FALSE */ + return FALSE; + } + + /* Publish the low-level table */ + RTL::Atomic::ExchangePointer((PVOID *)(&HighLevelTableEntry[HighLevelIndex][MediumLevelIndex]), + LowLevelTable); + } + } + + /* Reserve the allocated index block and capture the base handle value */ + OldIndex = RTL::Atomic::ExchangeAdd32((PLONG)&HandleTable->NextHandleNeedingPool, + OBJECT_HANDLE_LOWLEVEL_COUNT * OBJECT_HANDLE_VALUE_INCREMENT); + + /* Check if the initialization flag is set */ + if(Initialize) + { + /* Calculate the starting index */ + FirstFreeIndex = OldIndex + OBJECT_HANDLE_VALUE_INCREMENT; + + /* Enter exchange loop */ + while(TRUE) + { + /* Capture the state of the primary free list */ + FirstFree = *(VOLATILE ULONG *)&HandleTable->FirstFreeHandle; + + /* Chain the tail of allocated page to the current list head */ + LowLevelTable[OBJECT_HANDLE_LOWLEVEL_COUNT - 1].NextFreeTableEntry = FirstFree; + + /* Swap the new chain head */ + if (FirstFree == (ULONG)RTL::Atomic::CompareExchange32((PLONG)&HandleTable->FirstFreeHandle, + FirstFreeIndex, + FirstFree)) + { + /* Exchange succeeded, break the loop */ + break; + } + } + } + + /* Handle allocation succeeded, return TRUE */ + return TRUE; +} + +/** + * Allocates a new handle table entry. + * + * @param HandleTable + * Supplies the handle table to allocate from. + * + * @param Handle + * Receives the allocated handle value. + * + * @return This routine returns a pointer to the allocated entry, or NULL pointer on failure. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY +OB::HandleTable::AllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, + OUT POBJECT_HANDLE Handle) +{ + ULONG FreeHandle, LockIndex, NextFreeHandle, OldFreeHandle; + PHANDLE_TABLE_ENTRY TableEntry; + BOOLEAN ExpansionSucceeded; + OBJECT_HANDLE LocalHandle; + PKTHREAD CurrentThread; + + /* Retrieve the currently executing thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Enter the retry loop */ + while(TRUE) + { + /* Get the current head of the primary free list */ + OldFreeHandle = (ULONG)(ULONG_PTR)HandleTable->FirstFreeHandle; + + /* Enter the replenishment loop */ + while(!OldFreeHandle) + { + /* Start a guarded code block */ + { + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + + /* Acquire the handle table lock */ + KE::PushLockExclusiveGuard PushLock(&HandleTable->HandleTableLock[0]); + + /* Check if another thread replenished the free list */ + OldFreeHandle = (ULONG)(ULONG_PTR)HandleTable->FirstFreeHandle; + if(OldFreeHandle) + { + /* The free list was replenished, break the loop execution */ + break; + } + + /* Pull available handles */ + OldFreeHandle = MoveFreeHandles(HandleTable); + if(OldFreeHandle) + { + /* Break the loop execution */ + break; + } + + /* Allocate a handle table entry */ + ExpansionSucceeded = AllocateHandleTableEntry(HandleTable, TRUE); + } + + /* Get the free list head */ + OldFreeHandle = (ULONG)(ULONG_PTR)HandleTable->FirstFreeHandle; + + /* Check if the block allocation failed */ + if(!ExpansionSucceeded) + { + /* Verify if the free list remains depleted */ + if(!OldFreeHandle) + { + /* Fail the allocation request and return NULL pointer */ + Handle->GenericHandleOverlay = NULLPTR; + return NULLPTR; + } + } + } + + /* Extract the handle value and retrieve its underlying table entry */ + LocalHandle.Value = (OldFreeHandle & OBJECT_FREE_HANDLE_MASK); + TableEntry = LookupHandleTableEntry(HandleTable, LocalHandle); + + /* Calculate the specific lock index */ + LockIndex = ((OldFreeHandle & OBJECT_FREE_HANDLE_MASK) >> 2) % OBJECT_HANDLE_VALUE_INCREMENT; + + /* Start a guarded code block */ + { + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + + /* Acquire the handle table lock */ + KE::PushLockSharedGuard PushLock(&HandleTable->HandleTableLock[LockIndex]); + + /* Verify that the free list head has not been modified */ + if(OldFreeHandle != *(volatile ULONG *)&HandleTable->FirstFreeHandle) + { + /* The list changed, restart the allocation */ + continue; + } + + /* Memory barrier */ + AR::CpuFunctions::MemoryBarrier(); + + /* Retrieve the index of the next free entry in the chain */ + NextFreeHandle = *(volatile ULONG *)&TableEntry->NextFreeTableEntry; + + /* Replace the free list head with the next index */ + FreeHandle = RTL::Atomic::CompareExchange32((PLONG)&HandleTable->FirstFreeHandle, + NextFreeHandle, + OldFreeHandle); + } + + /* Check if the replace succeeded */ + if(FreeHandle == OldFreeHandle) + { + /* Exit the retry loop */ + break; + } + } + + /* Increment the handle allocation count */ + RTL::Atomic::Increment32(&HandleTable->HandleCount); + + /* Store the handle and return a pointer to the allocated entry */ + *Handle = LocalHandle; + return TableEntry; +} + +/** + * Allocates a low-level handle table page. + * + * @param HandleTable + * Supplies the parent handle table. + * + * @param Initialize + * Indicates whether to initialize the free list within the page. + * + * @return This routine returns a pointer to the allocated table, or NULL pointer on failure. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY +OB::HandleTable::AllocateLowLevelTable(IN PHANDLE_TABLE HandleTable, + IN BOOLEAN Initialize) +{ + PHANDLE_TABLE_ENTRY HandleEntry, LowLevelEntry; + ULONG BaseHandle, Index; + + /* Allocate a memory block for the handle table */ + LowLevelEntry = (PHANDLE_TABLE_ENTRY)AllocateTableMemory(HandleTable->QuotaProcess, MM_PAGE_SIZE, FALSE); + if(!LowLevelEntry) + { + /* Memory allocation failed, return a NULL pointer */ + return NULLPTR; + } + + /* Initialize the first entry of the page as the extended information header */ + HandleEntry = &LowLevelEntry[0]; + HandleEntry->NextFreeTableEntry = OBJECT_HANDLE_ADDITIONAL_INFO_SIGNATURE; + HandleEntry->Value = 0; + + /* Check if initialization requested */ + if(Initialize) + { + /* Advance to the first usable handle entry */ + HandleEntry++; + + /* Calculate the base handle index */ + BaseHandle = HandleTable->NextHandleNeedingPool + 2 * OBJECT_HANDLE_VALUE_INCREMENT; + + /* Iterate through the table block */ + for(Index = BaseHandle; + Index < BaseHandle + (OBJECT_HANDLE_LOWLEVEL_COUNT - 2) * OBJECT_HANDLE_VALUE_INCREMENT; + Index += OBJECT_HANDLE_VALUE_INCREMENT) + { + /* Link the current entry to the next available handle index */ + HandleEntry->NextFreeTableEntry = Index; + HandleEntry->Value = 0; + + /* Advance to the next handle table entry */ + HandleEntry++; + } + + /* Terminate the free list chain */ + HandleEntry->NextFreeTableEntry = 0; + HandleEntry->Value = 0; + } + + /* Return the pointer to the handle table */ + return LowLevelEntry; +} + +/** + * Allocates a mid-level table with an initial low-level table. + * + * @param HandleTable + * Supplies the parent handle table. + * + * @param Initialize + * Indicates whether to initialize the free list. + * + * @param LowLevelEntry + * Receives the pointer to the allocated low-level table. + * + * @return This routine returns a pointer to the mid-level table, or NULL on failure. + * + * @since XT 1.0 + */ +PHANDLE_TABLE_ENTRY* +OB::HandleTable::AllocateMediumLevelTable(IN PHANDLE_TABLE HandleTable, + IN BOOLEAN Initialize, + OUT PHANDLE_TABLE_ENTRY *LowLevelEntry) +{ + PHANDLE_TABLE_ENTRY *MediumLevelEntry; + PHANDLE_TABLE_ENTRY LowLevel; + + /* Allocate a memory block for the medium-level handle table */ + MediumLevelEntry = (PHANDLE_TABLE_ENTRY*)AllocateTableMemory(HandleTable->QuotaProcess, MM_PAGE_SIZE, TRUE); + if(!MediumLevelEntry) + { + /* Memory allocation failed, return a NULL pointer */ + return NULLPTR; + } + + /* Allocate the initial low-level handle table page */ + LowLevel = AllocateLowLevelTable(HandleTable, Initialize); + if(!LowLevel) + { + /* Allocation failed, free the medium-level table and return a NULL pointer */ + FreeTableMemory(HandleTable->QuotaProcess, MediumLevelEntry, MM_PAGE_SIZE); + return NULLPTR; + } + + /* Link the initial table into the first slot */ + MediumLevelEntry[0] = LowLevel; + *LowLevelEntry = LowLevel; + + /* Return the medium-level handle table */ + return MediumLevelEntry; +} + +/** + * Allocates a memory block for handle table structures. + * + * @param QuotaProcess + * Optionally supplies a pointer to the process object that will be charged for the memory quota. + * + * @param Size + * Supplies the size, in bytes, of the memory block to allocate. + * + * @param ZeroMemory + * Supplies a boolean value indicating whether the allocated memory block should be zero-initialized. + * + * @return This routine returns a pointer to the newly allocated memory block, or NULLPTR if the allocation fails. + * + * @since XT 1.0 + */ +XTAPI +PVOID +OB::HandleTable::AllocateTableMemory(IN PEPROCESS QuotaProcess, + IN SIZE_T Size, + IN BOOLEAN ZeroMemory) +{ + PVOID MemoryBuffer; + XTSTATUS Status; + + /* Allocate a paged pool memory block with the object table tag */ + MM::Allocator::AllocatePool(PagedPool, Size, &MemoryBuffer, TAG_OB_OBJECT_TABLE); + if(!MemoryBuffer) + { + /* Memory allocation failed, return a NULL pointer */ + return NULLPTR; + } + + /* Check if the caller requested zero-initialized memory */ + if(ZeroMemory) + { + /* Clear the contents of the allocated memory block */ + RTL::Memory::ZeroMemory(MemoryBuffer, Size); + } + + /* Check if a quota process was specified */ + if(QuotaProcess) + { + /* Charge the paged pool memory allocation against the target process quota */ + Status = PS::Quota::ChargeProcessQuota(QuotaProcess->QuotaBlock, QuotaProcess, PsPagedPool, Size); + if(Status != STATUS_SUCCESS) + { + /* Quota charge failed, free the allocated memory and return a NULL pointer */ + MM::Allocator::FreePool(MemoryBuffer, TAG_OB_OBJECT_TABLE); + return NULLPTR; + } + } + + /* Return a pointer to the allocated memory block */ + return MemoryBuffer; +} + +/** + * Changes the contents of a handle entry via a callback. + * + * @param HandleTable + * Supplies the handle table containing the entry. + * + * @param Handle + * Supplies the handle value to modify. + * + * @param Callback + * Supplies the callback that performs the modification. + * + * @param Parameter + * Supplies an opaque parameter passed to the callback. + * + * @return This routine returns TRUE if the change succeeded, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::HandleTable::ChangeHandle(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN POB_CHANGE_HANDLE_ROUTINE Callback, + IN ULONG_PTR Parameter + ) +{ + PHANDLE_TABLE_ENTRY HandleTableEntry; + OBJECT_HANDLE LocalHandle; + PKTHREAD CurrentThread; + BOOLEAN ReturnValue; + + /* Initialize the default return value */ + ReturnValue = FALSE; + + /* Overlay the generic handle value */ + LocalHandle.GenericHandleOverlay = Handle; + + /* Retrieve the currently executing thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Retrieve the corresponding handle table entry */ + HandleTableEntry = LookupHandleTableEntry(HandleTable, LocalHandle); + + /* Ensure the entry exists and points to an active object */ + if(HandleTableEntry && ValidateObjectEntry(HandleTableEntry)) + { + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + + /* Acquire the exclusive lock for this entry */ + if(LockHandleTableEntry(HandleTable, HandleTableEntry)) + { + /* Execute the provided callback */ + ReturnValue = (*Callback)(HandleTableEntry, Parameter); + + /* Release the lock */ + UnlockHandleTableEntry(HandleTable, HandleTableEntry); + } + } + + /* Return the callback result */ + return ReturnValue; +} + +/** + * Creates a new handle entry in a handle table. + * + * @param HandleTable + * Supplies the handle table to create the entry in. + * + * @param HandleTableEntry + * Supplies the template entry to copy. + * + * @return This routine returns the created handle value, or NULL on failure. + * + * @since XT 1.0 + */ +XTAPI +HANDLE +OB::HandleTable::CreateHandle(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + PHANDLE_TABLE_ENTRY NewHandleTableEntry; + PETHREAD CurrentThread; + OBJECT_HANDLE Handle; + + /* Initialize the generic handle overlay */ + Handle.GenericHandleOverlay = NULLPTR; + + /* Allocate a new handle table entry */ + NewHandleTableEntry = AllocateHandleTableEntry(HandleTable, &Handle); + if(NewHandleTableEntry) + { + /* Retrieve the current thread object */ + CurrentThread = PS::Thread::GetCurrentThread(); + + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(&CurrentThread->ThreadControlBlock); + + /* Copy the contents of the template entry */ + *NewHandleTableEntry = *HandleTableEntry; + + /* Unlock the handle table entry */ + UnlockHandleTableEntry(HandleTable, NewHandleTableEntry); + } + + /* Return the resulting handle value */ + return Handle.GenericHandleOverlay; +} + +/** + * Creates and initializes a new handle table. + * + * @param Process + * Supplies the optional process to charge quota against. + * + * @return This routine returns a pointer to the handle table, or NULL pointer on failure. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE +OB::HandleTable::CreateHandleTable(IN PEPROCESS Process) +{ + PKTHREAD CurrentThread; + PHANDLE_TABLE HandleTable; + + /* Get the current thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Allocate a new handle table */ + HandleTable = AllocateHandleTable(Process, TRUE); + if(!HandleTable) + { + /* Handle table allocation failure, return NULL pointer */ + return NULLPTR; + } + + /* Enter a critical region and acquire the handle table lock */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + KE::PushLockExclusiveGuard PushLock(&HandleTableListLock); + + /* Insert the new handle table into the global list */ + RTL::LinkedList::InsertTailList(&HandleTableListHead, &HandleTable->HandleTableList); + + /* Return the new handle table */ + return HandleTable; +} + +/** + * Removes a handle from a handle table. + * + * @param HandleTable + * Supplies the handle table containing the handle. + * + * @param Handle + * Supplies the handle value to remove. + * + * @param HandleTableEntry + * Optionally supplies a pre-locked entry pointer. + * + * @return This routine returns TRUE if the handle was removed, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::HandleTable::DestroyHandle(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + OBJECT_HANDLE LocalHandle; + PETHREAD CurrentThread; + + /* Capture the provided handle value */ + LocalHandle.GenericHandleOverlay = Handle; + + /* Retrieve the current thread object */ + CurrentThread = PS::Thread::GetCurrentThread(); + + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(&CurrentThread->ThreadControlBlock); + + /* Check if a handle table entry was provided by the caller */ + if(!HandleTableEntry) + { + /* Resolve the local handle to its corresponding handle table entry */ + HandleTableEntry = LookupHandleTableEntry(HandleTable, LocalHandle); + + /* Verify that the resolved entry points to a valid object */ + if(!ValidateObjectEntry(HandleTableEntry)) + { + /* Invalid object entry, return FALSE */ + return FALSE; + } + + /* Acquire the lock */ + if(!LockHandleTableEntry(HandleTable, HandleTableEntry)) + { + /* Entry locking failed, return FALSE */ + return FALSE; + } + } + + /* Clear the object pointer */ + RTL::Atomic::ExchangePointer(&HandleTableEntry->Object, NULLPTR); + + /* Unblock any threads waiting on the handle table */ + KE::PushLock::UnblockPushLock(&HandleTable->HandleContentionEvent, NULLPTR); + + /* Release the handle table entry */ + FreeHandleTableEntry(HandleTable, LocalHandle, HandleTableEntry); + + /* Return TRUE */ + return TRUE; +} + +/** + * Destroys a handle table and all its entries. + * + * @param HandleTable + * Supplies the handle table to destroy. + * + * @param Callback + * Supplies an optional callback invoked for each valid handle. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +VOID +OB::HandleTable::DestroyHandleTable(IN PHANDLE_TABLE HandleTable, + IN POB_DESTROY_HANDLE_ROUTINE Callback) +{ + PHANDLE_TABLE_ENTRY HandleTableEntry; + OBJECT_HANDLE Handle; + + /* Remove the handle table from the tracking list */ + RemoveHandleTable(HandleTable); + + /* Check if a handle destruction callback was provided */ + if(Callback) + { + /* Initialize the handle */ + Handle.Value = 0; + + /* Iterate through all handles within the table */ + while(TRUE) + { + /* Retrieve the underlying handle table entry */ + HandleTableEntry = LookupHandleTableEntry(HandleTable, Handle); + if(!HandleTableEntry) + { + /* Handle is out of bounds, abort the enumeration */ + break; + } + + /* Validate that the entry points to a registered object */ + if(ValidateObjectEntry(HandleTableEntry)) + { + /* Invoke the destruction callback */ + (*Callback)(Handle.GenericHandleOverlay); + } + + /* Advance to the next handle value */ + Handle.Value += OBJECT_HANDLE_VALUE_INCREMENT; + } + } + + /* Release all memory */ + FreeHandleTable(HandleTable); +} + +/** + * Duplicates copy of a handle table. + * + * @param Process + * Supplies the optional process to charge quota against. + * + * @param OldHandleTable + * Supplies the source handle table to duplicate. + * + * @param Callback + * Supplies the callback invoked for each duplicated handle. + * + * @param Mask + * Supplies a mask applied to object pointers during duplication. + * + * @return This routine returns a pointer to the new handle table, or NULL pointer on failure. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE +OB::HandleTable::DuplicateHandleTable(IN PEPROCESS Process, + IN PHANDLE_TABLE OldHandleTable, + IN POB_DUPLICATE_HANDLE_ROUTINE Callback, + IN ULONG_PTR Mask) +{ + PHANDLE_TABLE_ENTRY NewHandleTableEntry, OldHandleTableEntry; + PHANDLE_TABLE_ENTRY_INFO EntryInfo; + PHANDLE_TABLE DuplicateHandleTable; + ULONG Index, RemainingEntries; + BOOLEAN FreeEntry, Ready; + PKTHREAD CurrentThread; + OBJECT_HANDLE Handle; + + /* Retrieve the currently executing thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Allocate a handle table */ + DuplicateHandleTable = AllocateHandleTable(Process, FALSE); + if(!DuplicateHandleTable) + { + /* Allocation failed, return NULL pointer */ + return NULLPTR; + } + + /* Expand the handle table to match the capacity */ + while(DuplicateHandleTable->NextHandleNeedingPool < OldHandleTable->NextHandleNeedingPool) + { + /* Allocate the handle table entries */ + if(!AllocateHandleTableEntry(DuplicateHandleTable, FALSE)) + { + /* Allocation failed, free handle table and return NULL pointer */ + FreeHandleTable(DuplicateHandleTable); + return NULLPTR; + } + } + + /* Memory barrier */ + AR::CpuFunctions::MemoryBarrier(); + + /* Initialize the base state of the cloned table */ + DuplicateHandleTable->ExtraInfoPages = 0; + DuplicateHandleTable->FirstFreeHandle = 0; + DuplicateHandleTable->HandleCount = 0; + + /* Initialize the handle value */ + Handle.Value = OBJECT_HANDLE_VALUE_INCREMENT; + + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + + /* Enumerate all allocated handle table entry layers */ + while(TRUE) + { + /* Retrieve the physical pointer to the handle table entry */ + NewHandleTableEntry = LookupHandleTableEntry(DuplicateHandleTable, Handle); + if(!NewHandleTableEntry) + { + /* Allocated table layers exhausted, break the enumeration loop */ + break; + } + + /* Retrieve the pointer from the source table */ + OldHandleTableEntry = LookupHandleTableEntry(OldHandleTable, Handle); + + /* Calculate how many entries remain to be processed */ + RemainingEntries = OBJECT_HANDLE_LOWLEVEL_COUNT - + ((Handle.Value / OBJECT_HANDLE_VALUE_INCREMENT) % OBJECT_HANDLE_LOWLEVEL_COUNT); + + /* Process all entries */ + for(Index = 0; Index < RemainingEntries; Index++) + { + /* Check if the entry matches the required mask and lock it */ + if(!(OldHandleTableEntry->Value & Mask) || !LockHandleTableEntry(OldHandleTable, OldHandleTableEntry)) + { + /* Invalid or locked entry, push to free list */ + FreeEntry = TRUE; + } + else + { + /* Perform a raw memory copy */ + *NewHandleTableEntry = *OldHandleTableEntry; + + /* Retrieve extended information attached to the handle */ + EntryInfo = GetHandleInformation(OldHandleTable, Handle.GenericHandleOverlay, TRUE); + if(EntryInfo) + { + /* Check the readiness of the entry */ + Ready = (SetHandleInformation(DuplicateHandleTable, Handle.GenericHandleOverlay, + EntryInfo, TRUE) == STATUS_SUCCESS); + } + else + { + /* No extended info exists, ready to proceed */ + Ready = TRUE; + } + + /* Verify the readiness */ + if(Ready) + { + /* Invoke the duplication callback */ + if((*Callback)(Process, OldHandleTable, OldHandleTableEntry, NewHandleTableEntry)) + { + /* The callback accepted the duplication */ + FreeEntry = FALSE; + + /* Increment the handle count and ensure the new entry remains locked */ + DuplicateHandleTable->HandleCount += 1; + NewHandleTableEntry->Value |= OBJECT_HANDLE_TABLE_ENTRY_LOCK_BIT; + } + else + { + /* Check if extended information was attached */ + if(EntryInfo) + { + /* Clear the audit mask */ + EntryInfo->AuditMask = 0; + } + + /* Discarded entry, push to free list */ + FreeEntry = TRUE; + } + } + else + { + /* Setup failed, release the source entry lock */ + UnlockHandleTableEntry(OldHandleTable, OldHandleTableEntry); + + /* Unusable entry, push to free list */ + FreeEntry = TRUE; + } + } + + /* Process entries designated for the free list */ + if(FreeEntry) + { + /* Link the unused entry into the free list chain */ + NewHandleTableEntry->NextFreeTableEntry = (ULONG)(ULONG_PTR)DuplicateHandleTable->FirstFreeHandle; + NewHandleTableEntry->Object = NULLPTR; + + /* Update the head of the free list */ + DuplicateHandleTable->FirstFreeHandle = (PHANDLE_TABLE_ENTRY)(ULONG_PTR)Handle.Value; + } + + /* Advance the logical handle value */ + Handle.Value += OBJECT_HANDLE_VALUE_INCREMENT; + + /* Advance the table entry pointers */ + NewHandleTableEntry++; + OldHandleTableEntry++; + } + } + + /* Acquire the handle table lock */ + KE::PushLockExclusiveGuard PushLock(&HandleTableListLock); + + /* Insert the handle table into the global tracking list */ + RTL::LinkedList::InsertTailList(&HandleTableListHead, &DuplicateHandleTable->HandleTableList); + + /* Return the duplicated handle table */ + return DuplicateHandleTable; +} + +/** + * Enumerates all valid handles in a handle table. + * + * @param HandleTable + * Supplies the handle table to enumerate. + * + * @param Callback + * Supplies the callback invoked for each valid handle. + * + * @param Parameter + * Supplies an opaque parameter passed to the callback. + * + * @param Handle + * Optionally receives the handle where enumeration stopped. + * + * @return This routine returns TRUE if enumeration stopped early, FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::HandleTable::EnumerateHandleTable(IN PHANDLE_TABLE HandleTable, + IN POB_ENUMERATE_HANDLE_ROUTINE Callback, + IN PVOID Parameter, + OUT PHANDLE Handle) +{ + PHANDLE_TABLE_ENTRY HandleTableEntry; + OBJECT_HANDLE LocalHandle; + PKTHREAD CurrentThread; + BOOLEAN ResultValue; + + /* Initialize the default return value */ + ResultValue = FALSE; + + /* Retrieve the currently executing thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + + /* Initialize the handle value */ + LocalHandle.Value = 0; + + /* Iterate through all handles within the table */ + while(TRUE) + { + /* Retrieve the handle table entry for the current value */ + HandleTableEntry = LookupHandleTableEntry(HandleTable, LocalHandle); + if(!HandleTableEntry) + { + /* Handle is out of bounds, abort enumeration */ + break; + } + + /* Validate that the entry points to a registered object */ + if(ValidateObjectEntry(HandleTableEntry)) + { + /* Acquire the lock */ + if(LockHandleTableEntry(HandleTable, HandleTableEntry)) + { + /* Invoke the enumeration callback */ + ResultValue = (*Callback)(HandleTableEntry, LocalHandle.GenericHandleOverlay, Parameter); + + /* Release the lock */ + UnlockHandleTableEntry(HandleTable, HandleTableEntry); + + /* Check if the callback requested termination */ + if(ResultValue) + { + /* Check if the caller provided an output parameter */ + if(Handle) + { + /* Store the handle */ + *Handle = LocalHandle.GenericHandleOverlay; + } + + /* Exit the enumeration loop */ + break; + } + } + } + + /* Advance to the next handle value */ + LocalHandle.Value += OBJECT_HANDLE_VALUE_INCREMENT; + } + + /* Return enumeration result */ + return ResultValue; +} + +/** + * Frees and tears down a handle table structure. + * + * @param HandleTable + * Supplies the handle table to free. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +VOID +OB::HandleTable::FreeHandleTable(IN PHANDLE_TABLE HandleTable) +{ + PHANDLE_TABLE_ENTRY **HighLevelTable, LowLevelTable, *MediumLevelTable; + ULONG HighLevelIndex, MediumLevelIndex, TableLevel; + ULONG_PTR CapturedTable; + PEPROCESS Process; + + + /* Capture the current table */ + CapturedTable = HandleTable->TableCode; + + /* Extract the handle table depth level */ + TableLevel = (ULONG)(CapturedTable & OBJECT_HANDLE_LEVEL_CODE_MASK); + + /* Mask out the level bits */ + CapturedTable = CapturedTable & ~OBJECT_HANDLE_LEVEL_CODE_MASK; + + /* Retrieve the quota process associated with handle table */ + Process = HandleTable->QuotaProcess; + + /* Check if the handle table is currently operating as a single-level structure */ + if(!TableLevel) + { + /* Extract the low-level table */ + LowLevelTable = (PHANDLE_TABLE_ENTRY)CapturedTable; + + /* Free the low-level directly */ + FreeLowLevelTable(Process, LowLevelTable); + } + else if(TableLevel == 1) + { + /* Extract the medium-level directory */ + MediumLevelTable = (PHANDLE_TABLE_ENTRY *)CapturedTable; + + /* Initialize the medium-level directory index */ + MediumLevelIndex = 0; + + /* Enumerate and free all allocated low-level leaves */ + while(TRUE) + { + /* Check if the maximum count reached */ + if(MediumLevelIndex >= OBJECT_HANDLE_MEDIUMLEVEL_COUNT || !MediumLevelTable[MediumLevelIndex]) + { + /* Break the enumeration loop */ + break; + } + + /* Free the low-level table leaf */ + FreeLowLevelTable(Process, MediumLevelTable[MediumLevelIndex]); + + /* Advance to the next medium-level directory slot */ + MediumLevelIndex++; + } + + /* Free the medium-level directory itself */ + FreeTableMemory(Process, MediumLevelTable, MM_PAGE_SIZE); + } + else + { + /* Extract the high-level directory */ + HighLevelTable = (PHANDLE_TABLE_ENTRY **)CapturedTable; + + /* Initialize the high-level root index */ + HighLevelIndex = 0; + + /* Enumerate and free all allocated medium-level directories */ + while(TRUE) + { + /* Check if the maximum count reached */ + if(HighLevelIndex >= OBJECT_HANDLE_HIGHLEVEL_COUNT || !HighLevelTable[HighLevelIndex]) + { + /* Break the enumeration loop */ + break; + } + + /* Initialize the medium-level directory index */ + MediumLevelIndex = 0; + + /* Enumerate and free all allocated low-level leaves */ + while(TRUE) + { + /* Check if the maximum count reached */ + if(MediumLevelIndex >= OBJECT_HANDLE_MEDIUMLEVEL_COUNT || + !HighLevelTable[HighLevelIndex][MediumLevelIndex]) + { + /* Break the inner enumeration loop */ + break; + } + + /* Free the low-level table leaf */ + FreeLowLevelTable(Process, HighLevelTable[HighLevelIndex][MediumLevelIndex]); + + /* Advance to the next mediun-level directory slot */ + MediumLevelIndex++; + } + + /* Free the current medium-level directory page */ + FreeTableMemory(Process, HighLevelTable[HighLevelIndex], MM_PAGE_SIZE); + + /* Advance to the next high-level directory slot */ + HighLevelIndex++; + } + + /* Free the high-level root directory itself */ + FreeTableMemory(Process, HighLevelTable, OBJECT_HANDLE_HIGHLEVEL_SIZE); + } + + /* Free the base handle table */ + FreeTableMemory(Process, HandleTable, sizeof(HANDLE_TABLE)); +} + +/** + * Frees a handle table entry back to the free list. + * + * @param HandleTable + * Supplies the parent handle table. + * + * @param Handle + * Supplies the handle being freed. + * + * @param HandleTableEntry + * Supplies the entry being freed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +VOID +OB::HandleTable::FreeHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN OBJECT_HANDLE Handle, + IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + ULONG HandleValue, ListHead, LockIndex, SequenceTag; + PHANDLE_TABLE_ENTRY_INFO EntryInfo; + PULONG TargetListPointer; + + /* Retrieve the extended information attached to the handle */ + EntryInfo = GetHandleInformation(HandleTable, Handle.GenericHandleOverlay, TRUE); + if(EntryInfo) + { + /* Clear the audit mask */ + EntryInfo->AuditMask = 0; + } + + /* Decrement the handle allocation count */ + RTL::Atomic::Decrement32(&HandleTable->HandleCount); + + /* Mask out the lower control bits */ + HandleValue = (ULONG)Handle.Value & ~(OBJECT_HANDLE_VALUE_INCREMENT - 1); + + /* Check if strict FIFO mode is enabled */ + if(!HandleTable->StrictFIFO) + { + /* Calculate the lock index */ + LockIndex = (HandleValue >> 2) % OBJECT_HANDLE_VALUE_INCREMENT; + + /* Acquire the segment lock */ + if(KE::PushLock::TryAcquireExclusivePushLock(&HandleTable->HandleTableLock[LockIndex])) + { + /* Lock acquired, use the free list */ + SequenceTag = 0; + TargetListPointer = (PULONG)&HandleTable->FirstFreeHandle; + } + else + { + /* Lock contended, use the delayed list */ + SequenceTag = 0; + TargetListPointer = (PULONG)&HandleTable->LastFreeHandle; + } + } + else + { + /* Send freed handle to the delayed list */ + SequenceTag = 0; + TargetListPointer = (PULONG)&HandleTable->LastFreeHandle; + } + + /* Enter a loop to publish the freed handle */ + while(TRUE) + { + /* Capture the state of the targeted list head */ + ListHead = *(VOLATILE ULONG *)TargetListPointer; + + /* Chain the freed table entry to the list head */ + HandleTableEntry->NextFreeTableEntry = ListHead; + + /* Publish the freed handle */ + if((ULONG)RTL::Atomic::CompareExchange32((PLONG)TargetListPointer, + HandleValue + SequenceTag, + ListHead) == ListHead) + { + /* Publish succeeded, break the loop */ + break; + } + } +} + +/** + * Frees a low-level handle table page. + * + * @param QuotaProcess + * Supplies the process to return quota to. + * + * @param TableEntry + * Supplies the low-level table to free. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +VOID +OB::HandleTable::FreeLowLevelTable(IN PEPROCESS QuotaProcess, + IN PHANDLE_TABLE_ENTRY TableEntry) +{ + /* Check if an extended information table is attached */ + if(TableEntry[0].Object) + { + /* Free the handle information table */ + FreeTableMemory(QuotaProcess, TableEntry[0].Object, + OBJECT_HANDLE_LOWLEVEL_COUNT * sizeof(HANDLE_TABLE_ENTRY_INFO)); + } + + /* Release the handle table */ + FreeTableMemory(QuotaProcess, TableEntry, MM_PAGE_SIZE); +} + +/** + * Frees a handle table memory block and returns the associated quota. + * + * @param QuotaProcess + * Optionally supplies a pointer to the process object that will receive the memory quota reimbursement. + * + * @param MemoryBuffer + * Supplies a pointer to the allocated pool memory block to be freed. + * + * @param Size + * Supplies the size, in bytes, of the memory block being freed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::HandleTable::FreeTableMemory(IN PEPROCESS QuotaProcess, + IN PVOID MemoryBuffer, + IN SIZE_T Size) +{ + /* Release the allocated pool memory block associated with the object table tag */ + MM::Allocator::FreePool(MemoryBuffer, TAG_OB_OBJECT_TABLE); + + /* Check if a valid quota process object was specified */ + if(QuotaProcess) + { + /* Reimburse the paged pool memory quota to the specified process */ + PS::Quota::ReturnProcessQuota(QuotaProcess->QuotaBlock, QuotaProcess, PsPagedPool, Size); + } +} + +/** + * Retrieves the extended information for a specific handle table entry. + * + * @param HandleTable + * Supplies a pointer to the handle table containing the handle. + * + * @param Handle + * Supplies the handle for which the extended information is requested. + * + * @param Locked + * Specifies whether the handle table entry is currently locked by the caller. + * + * @return This routine returns a pointer to the handle table entry information, or NULL pointer if the table + * does not support extra info pages or lookup fails. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY_INFO +OB::HandleTable::GetHandleInformation(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN BOOLEAN Locked) +{ + PHANDLE_TABLE_ENTRY InfoStructure; + PHANDLE_TABLE_ENTRY TableEntry; + PHANDLE_TABLE_ENTRY_INFO ResultInfo; + OBJECT_HANDLE BaseHandle, ObHandle; + + /* Initialize local state */ + ResultInfo = NULLPTR; + TableEntry = NULLPTR; + + /* Check if the handle table maintains extra information pages */ + if(HandleTable->ExtraInfoPages) + { + /* Check if the caller has not locked the entry */ + if(!Locked) + { + /* Acquire the lock */ + TableEntry = MapHandleToPointer(HandleTable, Handle); + if(!TableEntry) + { + /* The handle is invalid or mapping failed, return NULL pointer */ + return NULLPTR; + } + } + + /* Isolate the base index of the handle table page */ + BaseHandle.GenericHandleOverlay = Handle; + BaseHandle.Index &= ~(OBJECT_HANDLE_LOWLEVEL_COUNT - 1); + + /* Fetch the base information structure */ + InfoStructure = LookupHandleTableEntry(HandleTable, BaseHandle); + + /* Validate the retrieved structure */ + if(InfoStructure && + InfoStructure->NextFreeTableEntry == OBJECT_HANDLE_ADDITIONAL_INFO_SIGNATURE && + InfoStructure->InfoTable) + { + /* Decode the target index */ + ObHandle.GenericHandleOverlay = Handle; + + /* Resolve the information entry pointer */ + ResultInfo = &InfoStructure->InfoTable[ObHandle.Index % OBJECT_HANDLE_LOWLEVEL_COUNT]; + } + else + { + /* Check if locked */ + if(TableEntry) + { + /* Release the lock */ + UnlockHandleTableEntry(HandleTable, TableEntry); + } + } + } + + /* Return the information pointer */ + return ResultInfo; +} + +/** + * Initializes the handle table. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::HandleTable::InitializeHandleTable(VOID) +{ + /* Initialize the handle table list and its synchronization pushlock */ + RTL::LinkedList::InitializeListHead(&HandleTableListHead); + KE::PushLock::InitializePushLock(&HandleTableListLock); +} + +/** + * Acquires the lock on a handle table entry, blocking the current thread if contention occurs. + * + * @param HandleTable + * Supplies a pointer to the handle table containing the entry. + * + * @param HandleTableEntry + * Supplies a pointer to the handle table entry to lock. + * + * @return This routine returns TRUE if the lock was successfully acquired, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::HandleTable::LockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + LONG_PTR CurrentValue, NewValue, OldValue; + KPUSH_LOCK_WAIT_BLOCK WaitBlock; + + /* Enter a retry loop */ + while(TRUE) + { + /* Get the state of the entry */ + OldValue = *(VOLATILE LONG_PTR *)&HandleTableEntry->Value; + + /* Check if the entry is currently unlocked */ + if(OldValue & OBJECT_HANDLE_TABLE_ENTRY_LOCK_BIT) + { + /* Clear the lock bit */ + NewValue = OldValue & ~OBJECT_HANDLE_TABLE_ENTRY_LOCK_BIT; + + /* Attempt to apply the lock */ + if(RTL::Atomic::CompareExchangePointer((PVOID *)&HandleTableEntry->Value, + (PVOID)NewValue, (PVOID)OldValue) == (PVOID)OldValue) + { + /* Lock acquired, return TRUE */ + return TRUE; + } + } + else + { + /* Check if the entry is completely empty */ + if(!OldValue) + { + /* Cannot proceed, return FALSE */ + return FALSE; + } + } + + /* The entry is locked by another thread, block thread */ + KE::PushLock::BlockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock); + + /* Check if the entry was freed or unlocked */ + CurrentValue = *(VOLATILE LONG_PTR *)&HandleTableEntry->Value; + if(!CurrentValue || (CurrentValue & OBJECT_HANDLE_TABLE_ENTRY_LOCK_BIT)) + { + /* The state changed, abort the wait */ + KE::PushLock::UnblockPushLock(&HandleTable->HandleContentionEvent, &WaitBlock); + } + else + { + /* The entry is locked, commit to the wait state */ + KE::Dispatcher::WaitForSingleObject(&WaitBlock.WakeEvent, Executive, KernelMode, FALSE, NULLPTR); + } + } +} + +/** + * Translates a generic handle into a pointer to its underlying handle table entry. + * + * @param HandleTable + * Supplies a pointer to the handle table performing the lookup. + * + * @param Handle + * Supplies the structured handle to be translated. + * + * @return This routine returns a pointer to the corresponding handle table entry, or NULL pointer if the handle + * is out of bounds or invalid. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY +OB::HandleTable::LookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN OBJECT_HANDLE Handle) +{ + PHANDLE_TABLE_ENTRY EntryTable; + ULONG MaxHandle, TableLevel; + ULONG_PTR Index, TableCode; + PVOID *DirectoryTable; + + /* Strip the tag bits */ + Handle.Value &= ~(ULONG_PTR)(OBJECT_HANDLE_VALUE_INCREMENT - 1); + + /* Read the maximum handle value */ + MaxHandle = *(VOLATILE ULONG *)&HandleTable->NextHandleNeedingPool; + if(Handle.Value >= MaxHandle) + { + /* Handle is out of bounds, return NULL pointer */ + return NULLPTR; + } + + /* Convert the raw handle value to an array index */ + Index = Handle.Value / OBJECT_HANDLE_VALUE_INCREMENT; + + /* Read the table routing state */ + TableCode = *(VOLATILE ULONG_PTR *)&HandleTable->TableCode; + + /* Extract the table depth level */ + TableLevel = (ULONG)(TableCode & OBJECT_HANDLE_LEVEL_CODE_MASK); + + /* Validate the structural integrity of the table */ + if(TableLevel > 2) + { + /* Invalid table level, return NULL pointer */ + return NULLPTR; + } + + /* Isolate the base address of the table */ + DirectoryTable = (PVOID *)(TableCode & ~(ULONG_PTR)OBJECT_HANDLE_LEVEL_CODE_MASK); + + /* Cascade through the directory levels */ + if(TableLevel == 2) + { + /* Resolve the highest level directory routing */ + DirectoryTable = (PVOID *)DirectoryTable[Index / (OBJECT_HANDLE_LOWLEVEL_COUNT * OBJECT_HANDLE_MEDIUMLEVEL_COUNT)]; + } + if(TableLevel >= 1) + { + /* Resolve the intermediate directory routing */ + DirectoryTable = (PVOID *)DirectoryTable[(Index / OBJECT_HANDLE_LOWLEVEL_COUNT) % OBJECT_HANDLE_MEDIUMLEVEL_COUNT]; + } + + /* Resolve the final entry page base */ + EntryTable = (PHANDLE_TABLE_ENTRY)DirectoryTable; + + /* Return the memory location of the requested handle table entry */ + return &EntryTable[Index % OBJECT_HANDLE_LOWLEVEL_COUNT]; +} + +/** + * Resolves a handle to its corresponding handle table entry and locks it. + * + * @param HandleTable + * Supplies a pointer to the handle table where the lookup will be performed. + * + * @param Handle + * Supplies the generic handle to map. + * + * @return This routine returns a pointer to the locked handle table entry on success, or NULL pointer on failure. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY +OB::HandleTable::MapHandleToPointer(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle) +{ + PHANDLE_TABLE_ENTRY TableEntry; + OBJECT_HANDLE LocalHandle; + + /* Assume failure initially */ + TableEntry = NULLPTR; + + /* Overlay the generic handle */ + LocalHandle.GenericHandleOverlay = Handle; + + /* Validate the handle index */ + if(LocalHandle.Index & (OBJECT_HANDLE_LOWLEVEL_COUNT - 1)) + { + /* Lookup the handle table entry */ + TableEntry = LookupHandleTableEntry(HandleTable, LocalHandle); + if(TableEntry) + { + /* Acquire the entry lock */ + if(!LockHandleTableEntry(HandleTable, TableEntry)) + { + /* Lock acquisition failed, reset the pointer */ + TableEntry = NULLPTR; + } + } + } + + /* Return the table entry pointer */ + return TableEntry; +} + +/** + * Maps a handle to a locked pointer with mode-specific error handling. + * + * @param HandleTable + * Supplies the handle table to query. + * + * @param Handle + * Supplies the handle value to map. + * + * @param ProcessorMode + * Supplies the previous processor mode of the caller. + * + * @return This routine returns a pointer to the locked entry, or NULL pointer on failure. + * + * @since XT 1.0 + */ +XTAPI +PHANDLE_TABLE_ENTRY +OB::HandleTable::MapHandleToPointer(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN KPROCESSOR_MODE ProcessorMode) +{ + PHANDLE_TABLE_ENTRY TableEntry; + OBJECT_HANDLE LocalHandle; + + /* Assume failure initially */ + TableEntry = NULLPTR; + + /* Overlay the generic handle */ + LocalHandle.GenericHandleOverlay = Handle; + + /* Validate the handle index */ + if(!(LocalHandle.Index & (OBJECT_HANDLE_LOWLEVEL_COUNT - 1))) + { + /* Invalid handle index alignment, return a NULL pointer */ + return NULLPTR; + } + + /* Retrieve the handle table entry corresponding to the specified handle value */ + TableEntry = LookupHandleTableEntry(HandleTable, LocalHandle); + if(!TableEntry) + { + /* Entry lookup failed, return a NULL pointer */ + return NULLPTR; + } + + /* Acquire the entry lock */ + if(!LockHandleTableEntry(HandleTable, TableEntry)) + { + /* Lock acquisition failed, reset the pointer */ + TableEntry = NULLPTR; + } + + /* Return a pointer to the handle table entry */ + return TableEntry; +} + +/** + * Moves free handles from the alternate free list to the primary free list. + * + * @param HandleTable + * Supplies the handle table to process. + * + * @return This routine returns the old value of the last free handle. + * + * @since XT 1.0 + */ +XTAPI +ULONG +OB::HandleTable::MoveFreeHandles(IN PHANDLE_TABLE HandleTable) +{ + ULONG CurrentFirstFree, FreeSize, Index, LockId, NewFirstFreeIndex, NewIndex, OldIndex, OldValue; + PHANDLE_TABLE_ENTRY Entry, FirstEntry; + BOOLEAN StrictFIFO; + OBJECT_HANDLE Handle; + + /* Extract the current free list and zero it out */ + OldValue = RTL::Atomic::Exchange32((PLONG)&HandleTable->LastFreeHandle, 0); + + /* Assign the extracted old value and check if there are any free handles */ + Index = OldValue; + if(!Index) + { + /* No free handles available, return old value */ + return OldValue; + } + + /* Acquire all secondary handle table locks for structural integrity */ + for(LockId = 1; LockId < OBJECT_HANDLE_VALUE_INCREMENT; LockId++) + { + /* Block on the designated segment lock */ + KE::PushLock::AcquireExclusivePushLock(&HandleTable->HandleTableLock[LockId]); + } + + /* Capture the FIFO requirement flag */ + StrictFIFO = HandleTable->StrictFIFO; + + /* Check if the handle table operates without strict FIFO ordering */ + if(!StrictFIFO) + { + /* Append the sequence */ + if(!RTL::Atomic::CompareExchange32((PLONG)&HandleTable->FirstFreeHandle, OldValue, 0)) + { + /* Release all secondary segment locks */ + for(LockId = 1; LockId < OBJECT_HANDLE_VALUE_INCREMENT; LockId++) + { + /* Unblock the designated segment lock */ + KE::PushLock::ReleaseExclusivePushLock(&HandleTable->HandleTableLock[LockId]); + } + + /* Return the old value */ + return OldValue; + } + } + + /* Initialize tracking variables */ + FirstEntry = NULLPTR; + FreeSize = 0; + OldIndex = 0; + + /* Traverse the alternate free list chain */ + while(Index) + { + /* Increment the free handle counter */ + FreeSize++; + + /* Map the raw index to its handle table entry */ + Handle.Value = Index; + Entry = LookupHandleTableEntry(HandleTable, Handle); + + /* Link the current entry to point backwards */ + NewIndex = Entry->NextFreeTableEntry; + Entry->NextFreeTableEntry = OldIndex; + + /* Check if the old index is zero */ + if(!OldIndex) + { + /* Store the pointer to the newly formed chain tail */ + FirstEntry = Entry; + } + + /* Advance the traversal pointers */ + OldIndex = Index; + Index = NewIndex; + } + + /* Calculate the target index */ + NewFirstFreeIndex = OldIndex; + + /* Loop until the exchange succeeds */ + while(TRUE) + { + /* Capture the state of the primary free list */ + CurrentFirstFree = *(VOLATILE ULONG *)&HandleTable->FirstFreeHandle; + + /* Chain tail to the current head of the primary list */ + FirstEntry->NextFreeTableEntry = CurrentFirstFree; + + /* Attempt to swap the new chain head */ + if(CurrentFirstFree == (ULONG)RTL::Atomic::CompareExchange32((PLONG)&HandleTable->FirstFreeHandle, + NewFirstFreeIndex, + CurrentFirstFree)) + { + /* The exchange succeeded, exit the loop */ + break; + } + } + + /* Release all handle table locks */ + for(LockId = 1; LockId < OBJECT_HANDLE_VALUE_INCREMENT; LockId++) + { + /* Unblock the designated segment lock */ + KE::PushLock::ReleaseExclusivePushLock(&HandleTable->HandleTableLock[LockId]); + } + + /* Check if the batch size is below the threshold */ + if(FreeSize < 100 && StrictFIFO) + { + /* Reset the old value to zero */ + OldValue = 0; + } + + /* Return the original first handle value */ + return OldValue; +} + +/** + * Removes a handle table from the global list. + * + * @param HandleTable + * Supplies the handle table to remove. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::HandleTable::RemoveHandleTable(IN PHANDLE_TABLE HandleTable) +{ + PKTHREAD CurrentThread; + + /* Get the current thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Enter a critical region and acquire the handle table lock */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + KE::PushLockExclusiveGuard PushLock(&HandleTableListLock); + + /* Remove the handle table from the global list and initialize the list head */ + RTL::LinkedList::RemoveEntryList(&HandleTable->HandleTableList); + RTL::LinkedList::InitializeListHead(&HandleTable->HandleTableList); +} + +/** + * Sets extended information for a handle table entry. + * + * @param HandleTable + * Supplies a pointer to the handle table containing the entry. + * + * @param Handle + * Supplies the handle for which the information is being updated. + * + * @param EntryInfo + * Supplies a pointer to the entry information structure to be copied. + * + * @param Locked + * Supplies a boolean value indicating whether the handle table is already locked. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::HandleTable::SetHandleInformation(IN PHANDLE_TABLE HandleTable, + IN HANDLE Handle, + IN PHANDLE_TABLE_ENTRY_INFO EntryInfo, + IN BOOLEAN Locked) +{ + PHANDLE_TABLE_ENTRY InfoStructure, TableEntry; + PHANDLE_TABLE_ENTRY_INFO InfoTable; + OBJECT_HANDLE ExHandle; + + /* Initialize local state tracking */ + ExHandle.GenericHandleOverlay = Handle; + ExHandle.Index &= ~(OBJECT_HANDLE_LOWLEVEL_COUNT - 1); + TableEntry = NULLPTR; + + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(NULLPTR, !Locked); + + /* Check if the caller specified that the handle table is unlocked */ + if(!Locked) + { + /* Map the supplied handle to its corresponding handle table entry */ + TableEntry = MapHandleToPointer(HandleTable, Handle); + if(!TableEntry) + { + /* Handle mapping failed, return error code */ + return STATUS_UNSUCCESSFUL; + } + } + + /* Retrieve the base info structure */ + InfoStructure = LookupHandleTableEntry(HandleTable, ExHandle); + if(!InfoStructure || InfoStructure->NextFreeTableEntry != OBJECT_HANDLE_ADDITIONAL_INFO_SIGNATURE) + { + /* Check if the handle table entry was mapped */ + if(TableEntry) + { + /* Unlock the mapped handle table entry */ + UnlockHandleTableEntry(HandleTable, TableEntry); + } + + /* Invalid info structure signature, return error code */ + return STATUS_UNSUCCESSFUL; + } + + /* Retrieve the pointer to the handle table entry info table */ + InfoTable = InfoStructure->InfoTable; + if(!InfoTable) + { + /* Allocate memory for the table */ + InfoTable = (PHANDLE_TABLE_ENTRY_INFO)AllocateTableMemory(HandleTable->QuotaProcess, + OBJECT_HANDLE_LOWLEVEL_COUNT * sizeof(HANDLE_TABLE_ENTRY_INFO), + FALSE); + if(InfoTable) + { + /* Attempt to publish the info table pointer */ + if(!RTL::Atomic::CompareExchangePointer((PVOID *)&InfoStructure->InfoTable, InfoTable, NULLPTR)) + { + /* Increment the extra info pages counter */ + RTL::Atomic::Increment32(&HandleTable->ExtraInfoPages); + } + else + { + /* Free the redundant info table */ + FreeTableMemory(HandleTable->QuotaProcess, InfoTable, + OBJECT_HANDLE_LOWLEVEL_COUNT * sizeof(HANDLE_TABLE_ENTRY_INFO)); + + /* Retrieve the info table pointer */ + InfoTable = InfoStructure->InfoTable; + } + } + } + + /* Verify that a valid info table pointer is available */ + if(!InfoTable) + { + /* Check if the handle table entry was mapped */ + if(TableEntry) + { + /* Unlock the mapped handle table entry */ + UnlockHandleTableEntry(HandleTable, TableEntry); + } + + /* Info table allocation failed, return error code */ + return STATUS_UNSUCCESSFUL; + } + + /* Restore the original handle */ + ExHandle.GenericHandleOverlay = Handle; + InfoTable[ExHandle.Index % OBJECT_HANDLE_LOWLEVEL_COUNT] = *EntryInfo; + + /* Check if the handle table entry is still locked */ + if(TableEntry) + { + /* Unlock the handle table entry */ + UnlockHandleTableEntry(HandleTable, TableEntry); + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Captures a snapshot of all handle tables in the system. + * + * @param SnapshotHandleEntry + * Supplies the callback invoked for each handle entry. + * + * @param HandleInformation + * Supplies the buffer to fill with handle information. + * + * @param Length + * Supplies the size of the buffer in bytes. + * + * @param RequiredLength + * Receives the required buffer size. + * + * @return This routine returns the status of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::HandleTable::SnapshotHandleTables(IN POB_SNAPSHOT_HANDLE_ENTRY SnapshotHandleEntry, + IN OUT PSYSTEM_HANDLE_INFORMATION HandleInformation, + IN ULONG Length, + IN OUT PULONG RequiredLength) +{ + PSYSTEM_HANDLE_TABLE_ENTRY_INFO HandleEntryInfo; + PHANDLE_TABLE_ENTRY HandleTableEntry; + PHANDLE_TABLE HandleTable; + PKTHREAD CurrentThread; + PLIST_ENTRY NextEntry; + OBJECT_HANDLE Handle; + XTSTATUS Status; + + /* Retrieve the currently executing thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Initialize the handle entry information */ + HandleEntryInfo = &HandleInformation->Handles[0]; + HandleInformation->NumberOfHandles = 0; + + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + + /* Acquire the global handle table list lock */ + KE::PushLockSharedGuard PushLock(&HandleTableListLock); + + /* Traverse the global list of handle tables */ + for(NextEntry = HandleTableListHead.Flink; NextEntry != &HandleTableListHead; NextEntry = NextEntry->Flink) + { + /* Resolve the handle table record */ + HandleTable = CONTAIN_RECORD(NextEntry, HANDLE_TABLE, HandleTableList); + + /* Initialize the handle value */ + Handle.Value = 0; + + /* Iterate through all handles within the current table */ + while (TRUE) + { + /* Retrieve the underlying handle table entry */ + HandleTableEntry = LookupHandleTableEntry(HandleTable, Handle); + if(!HandleTableEntry) + { + /* Handle is out of bounds, break the loop */ + break; + } + + /* Validate that the entry actually points to a registered object */ + if(ValidateObjectEntry(HandleTableEntry)) + { + /* Increment the global handle count */ + HandleInformation->NumberOfHandles += 1; + + /* Acquire the lock */ + if(LockHandleTableEntry(HandleTable, HandleTableEntry)) + { + /* Invoke the snapshot callback */ + Status = (*SnapshotHandleEntry)(&HandleEntryInfo, HandleTable->UniqueProcessId, HandleTableEntry, + Handle.GenericHandleOverlay, Length, RequiredLength); + + /* Release the lock */ + UnlockHandleTableEntry(HandleTable, HandleTableEntry); + + /* Check the callback status code */ + if(Status != STATUS_SUCCESS) + { + /* Callback routine failed, return status code */ + return Status; + } + } + } + + /* Advance to the next handle value */ + Handle.Value += OBJECT_HANDLE_VALUE_INCREMENT; + } + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Captures an extended snapshot of all handle tables in the system. + * + * @param SnapshotHandleEntry + * Supplies the callback invoked for each handle entry. + * + * @param HandleInformation + * Supplies the buffer to fill with extended handle information. + * + * @param Length + * Supplies the size of the buffer in bytes. + * + * @param RequiredLength + * Receives the required buffer size. + * + * @return This routine returns the status of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::HandleTable::SnapshotHandleTables(IN POB_SNAPSHOT_HANDLE_ENTRY_EX SnapshotHandleEntry, + IN OUT PSYSTEM_HANDLE_INFORMATION_EX HandleInformation, + IN ULONG Length, + IN OUT PULONG RequiredLength) +{ + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleEntryInfo; + PHANDLE_TABLE_ENTRY HandleTableEntry; + PHANDLE_TABLE HandleTable; + PKTHREAD CurrentThread; + PLIST_ENTRY NextEntry; + OBJECT_HANDLE Handle; + XTSTATUS Status; + + /* Retrieve the currently executing thread */ + CurrentThread = KE::Processor::GetCurrentThread(); + + /* Initialize the extended handle entry information */ + HandleEntryInfo = &HandleInformation->Handles[0]; + HandleInformation->NumberOfHandles = 0; + + /* Acquire a critical region guard */ + KE::CriticalRegionGuard CriticalRegion(CurrentThread); + + /* Acquire the global handle table list lock */ + KE::PushLockSharedGuard PushLock(&HandleTableListLock); + + /* Traverse the global list of handle tables */ + for(NextEntry = HandleTableListHead.Flink; NextEntry != &HandleTableListHead; NextEntry = NextEntry->Flink) + { + /* Resolve the handle table record */ + HandleTable = CONTAIN_RECORD(NextEntry, HANDLE_TABLE, HandleTableList); + + /* Initialize the handle value */ + Handle.Value = 0; + + /* Iterate through all handles within the current table */ + while (TRUE) + { + /* Retrieve the underlying handle table entry */ + HandleTableEntry = LookupHandleTableEntry(HandleTable, Handle); + if(!HandleTableEntry) + { + /* Handle is out of bounds, break the loop */ + break; + } + + /* Validate that the entry actually points to a registered object */ + if(ValidateObjectEntry(HandleTableEntry)) + { + /* Increment the global extended handle count */ + HandleInformation->NumberOfHandles += 1; + + /* Acquire the lock */ + if(LockHandleTableEntry(HandleTable, HandleTableEntry)) + { + /* Invoke the extended snapshot callback */ + Status = (*SnapshotHandleEntry)(&HandleEntryInfo, HandleTable->UniqueProcessId, HandleTableEntry, + Handle.GenericHandleOverlay, Length, RequiredLength); + + /* Release the lock */ + UnlockHandleTableEntry(HandleTable, HandleTableEntry); + + /* Check the callback status code */ + if(Status != STATUS_SUCCESS) + { + /* Callback routine failed, return status code */ + return Status; + } + } + } + + /* Advance to the next handle value */ + Handle.Value += OBJECT_HANDLE_VALUE_INCREMENT; + } + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Sweeps a handle table without synchronization. + * + * @param HandleTable + * Supplies the handle table to sweep. + * + * @param Callback + * Supplies the callback invoked for each valid handle. + * + * @param Parameter + * Supplies an opaque parameter passed to the callback. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::HandleTable::SweepHandleTable(IN PHANDLE_TABLE HandleTable, + IN POB_ENUMERATE_HANDLE_ROUTINE Callback, + IN PVOID Parameter) +{ + PHANDLE_TABLE_ENTRY HandleTableEntry; + ULONG Index, RemainingEntries; + OBJECT_HANDLE Handle; + + /* Initialize the handle value */ + Handle.Value = OBJECT_HANDLE_VALUE_INCREMENT; + + /* Traverse the handle table */ + while(TRUE) + { + /* Resolve the current handle value */ + HandleTableEntry = LookupHandleTableEntry(HandleTable, Handle); + if(!HandleTableEntry) + { + /* Handle entry lookup fails, break loop */ + break; + } + + /* Calculate the number of remaining entries */ + RemainingEntries = OBJECT_HANDLE_LOWLEVEL_COUNT - + ((Handle.Value / OBJECT_HANDLE_VALUE_INCREMENT) % OBJECT_HANDLE_LOWLEVEL_COUNT); + + /* Iterate through the remaining handle entries */ + for(Index = 0; Index < RemainingEntries; Index++) + { + /* Lock the current handle table entry */ + if(LockHandleTableEntry(HandleTable, HandleTableEntry)) + { + /* Execute the specified callback routine */ + (*Callback)(HandleTableEntry, Handle.GenericHandleOverlay, Parameter); + } + + /* Increment the handle value */ + Handle.Value += OBJECT_HANDLE_VALUE_INCREMENT; + + /* Advance to the next handle slot */ + HandleTableEntry++; + } + } +} + +/** + * Unlocks a previously locked handle table entry and wakes up any threads waiting on the table's contention event. + * + * @param HandleTable + * Supplies a pointer to the handle table containing the entry. + * + * @param HandleTableEntry + * Supplies a pointer to the handle table entry to be unlocked. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::HandleTable::UnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, + IN PHANDLE_TABLE_ENTRY HandleTableEntry) +{ + /* Unlock entry and signal the handle contention event */ + RTL::Atomic::Or64((VOLATILE PLONG_PTR)&HandleTableEntry->Value, (LONG_PTR)OBJECT_HANDLE_TABLE_ENTRY_LOCK_BIT); + KE::PushLock::UnblockPushLock(&HandleTable->HandleContentionEvent, NULLPTR); +} + +/** + * Checks if a handle table entry is valid and points to an actual object. + * + * @param Entry + * Supplies a pointer to the handle table entry to validate. + * + * @return This routine returns TRUE if the entry is valid, FALSE otherwise. + * + * @since XT 1.0 + */ +XTINLINE +BOOLEAN +OB::HandleTable::ValidateObjectEntry(IN PHANDLE_TABLE_ENTRY Entry) +{ + /* Return TRUE if the entry and its underlying object pointer exist */ + return (Entry && Entry->Object && Entry->NextFreeTableEntry != OBJECT_HANDLE_ADDITIONAL_INFO_SIGNATURE); +} diff --git a/xtoskrnl/ob/lifecycl.cc b/xtoskrnl/ob/lifecycl.cc new file mode 100644 index 0000000..616d88e --- /dev/null +++ b/xtoskrnl/ob/lifecycl.cc @@ -0,0 +1,1768 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/lifecycl.cc + * DESCRIPTION: Object Manager Lifecycle Management + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Allocates and initializes the memory block for a new object and its headers. + * + * @param CreateInfo + * Supplies a pointer to the object creation information. + * + * @param ProcessorMode + * Supplies the processor mode that will own the object. + * + * @param ObjectType + * Supplies an optional pointer to the object type definition. + * + * @param ObjectName + * Supplies an optional pointer to the unicode string representing the object's name. + * + * @param ObjectBodySize + * Supplies the size, in bytes, of the object body itself. + * + * @param ReturnedObjectHeader + * Receives a pointer to the newly allocated object header. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::LifeCycle::AllocateObject(IN POBJECT_CREATE_INFORMATION CreateInfo, + IN KPROCESSOR_MODE ProcessorMode, + IN POBJECT_TYPE ObjectType, + IN PUNICODE_STRING ObjectName, + IN ULONG ObjectBodySize, + OUT POBJECT_HEADER *ReturnedObjectHeader) +{ + POBJECT_HEADER_CREATOR_INFO CreatorInfoHeader; + POBJECT_HEADER_HANDLE_INFO HandleInfoHeader; + POBJECT_HEADER_QUOTA_INFO QuotaInfoHeader; + POBJECT_HEADER_NAME_INFO NameInfoHeader; + OBJECT_OPTIONAL_HEADER_LAYOUT Layout; + ULONG Tag, TotalAllocationSize; + POBJECT_HEADER ObjectHeader; + MMPOOL_TYPE PoolType; + PVOID PoolBuffer; + XTSTATUS Status; + PUCHAR Offset; + + /* Calculate the sizes for all optional headers */ + CalculateOptionalHeaderSize(CreateInfo, ObjectType, ObjectName, &Layout); + + /* Determine the pool type */ + if(ObjectType == NULLPTR || ObjectType->TypeInfo.PoolType == NonPagedPool) + { + /* Use non-paged pool */ + PoolType = NonPagedPool; + } + else + { + /* Use paged pool */ + PoolType = PagedPool; + } + + /* Compute the total required block size */ + TotalAllocationSize = Layout.TotalSize + sizeof(OBJECT_HEADER) + ObjectBodySize; + Tag = (ObjectType == NULLPTR) ? TAG_OB_OBJECT_TYPE : ObjectType->Key; + + /* Allocate the memory block from the selected pool */ + Status = MM::Allocator::AllocatePool(PoolType, TotalAllocationSize, &PoolBuffer, Tag); + if(Status != STATUS_SUCCESS || PoolBuffer == NULLPTR) + { + /* Allocation failed, return error code */ + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Set the initial offset */ + Offset = (PUCHAR)PoolBuffer; + + /* Check if there is a Quota Information header */ + if(Layout.QuotaInfoSize != 0) + { + /* Initialize the Quota Information header */ + QuotaInfoHeader = (POBJECT_HEADER_QUOTA_INFO)Offset; + QuotaInfoHeader->ExclusiveProcess = NULLPTR; + QuotaInfoHeader->NonPagedPoolCharge = CreateInfo->NonPagedPoolCharge; + QuotaInfoHeader->PagedPoolCharge = CreateInfo->PagedPoolCharge; + QuotaInfoHeader->SecurityDescriptorCharge = CreateInfo->SecurityDescriptorCharge; + + /* Advance the pointer */ + Offset += Layout.QuotaInfoSize; + } + + /* Check if there is a Handle Information header */ + if(Layout.HandleInfoSize != 0) + { + /* Initialize the Handle Information header */ + HandleInfoHeader = (POBJECT_HEADER_HANDLE_INFO)Offset; + HandleInfoHeader->SingleEntry.HandleCount = 0; + + /* Advance the pointer */ + Offset += Layout.HandleInfoSize; + } + + /* Check if there is a Name Information header */ + if(Layout.NameInfoSize != 0) + { + /* Initialize the Name Information header */ + NameInfoHeader = (POBJECT_HEADER_NAME_INFO)Offset; + NameInfoHeader->Directory = NULLPTR; + NameInfoHeader->Name = *ObjectName; + NameInfoHeader->QueryReferences = 1; + + /* Advance the pointer */ + Offset += Layout.NameInfoSize; + } + + /* Check if there is a Creator Information header */ + if(Layout.CreatorInfoSize != 0) + { + /* Initialize the Creator Information header */ + CreatorInfoHeader = (POBJECT_HEADER_CREATOR_INFO)Offset; + CreatorInfoHeader->CreatorBackTraceIndex = 0; + CreatorInfoHeader->CreatorUniqueProcess = PS::Process::GetCurrentProcess()->UniqueProcessId; + RTL::LinkedList::InitializeListHead(&CreatorInfoHeader->TypeList); + + /* Advance the pointer */ + Offset += Layout.CreatorInfoSize; + } + + /* Retrieve the object header */ + ObjectHeader = (POBJECT_HEADER)Offset; + + /* Initialize the object header */ + ObjectHeader->Flags = OBJECT_FLAG_NEW_OBJECT; + ObjectHeader->HandleInfoOffset = Layout.HandleInfoSize ? (UCHAR)(Layout.TotalSize - Layout.QuotaInfoSize) : 0; + ObjectHeader->NameInfoOffset = Layout.NameInfoSize ? (UCHAR)(Layout.CreatorInfoSize + Layout.NameInfoSize) : 0; + ObjectHeader->QuotaInfoOffset = Layout.QuotaInfoSize ? (UCHAR)Layout.TotalSize : 0; + + /* Check if there is creator information */ + if(Layout.CreatorInfoSize != 0) + { + /* Flag the presence of creator information */ + ObjectHeader->Flags |= OBJECT_FLAG_CREATOR_INFO; + } + + /* Check if there is handle information */ + if(Layout.HandleInfoSize != 0) + { + /* Flag the presence of handle information */ + ObjectHeader->Flags |= OBJECT_FLAG_SINGLE_PROCESS; + } + + /* Check if the object is being created in kernel mode */ + if(ProcessorMode == KernelMode) + { + /* Assign kernel mode ownership */ + ObjectHeader->Flags |= OBJECT_FLAG_KERNEL_MODE; + } + + /* Check if creation information was provided */ + if(CreateInfo) + { + /* Check if the object is permanent */ + if(CreateInfo->Attributes & OBJECT_PERMANENT) + { + /* Flag the object to prevent deletion */ + ObjectHeader->Flags |= OBJECT_FLAG_PERMANENT; + } + + /* Check if the object is exclusive */ + if(CreateInfo->Attributes & OBJECT_EXCLUSIVE) + { + /* Flag the object as exclusive to a single process */ + ObjectHeader->Flags |= OBJECT_FLAG_EXCLUSIVE; + } + } + + /* Initialize reference counters and data associations */ + ObjectHeader->HandleCount = 0; + ObjectHeader->ObjectCreateInfo = CreateInfo; + ObjectHeader->PointerCount = 1; + ObjectHeader->SecurityDescriptor = NULLPTR; + ObjectHeader->Type = ObjectType; + + /* Check if an object type was provided */ + if(ObjectType) + { + /* Increment the total active objects counter */ + RTL::Atomic::Increment32((VOLATILE PLONG)&ObjectType->TotalNumberOfObjects); + + /* Check if the current total exceeds the previous peak */ + if(ObjectType->TotalNumberOfObjects > ObjectType->HighWaterNumberOfObjects) + { + /* Update the high-water mark */ + ObjectType->HighWaterNumberOfObjects = ObjectType->TotalNumberOfObjects; + } + } + + /* Return the pointer to the initialized object */ + *ReturnedObjectHeader = ObjectHeader; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Allocates a buffer for an object name string. + * + * @param Length + * Supplies the exact length of the object name in bytes, excluding the NULL terminator. + * + * @param UseLookaside + * Indicates whether the allocation should attempt to draw from the paged pool lookaside list. + * + * @param ObjectName + * Supplies a pointer to the Unicode string descriptor to be initialized with the new buffer. + * + * @return This routine returns a pointer to the allocated buffer, or NULLPTR if allocation fails. + * + * @since XT 1.0 + */ +XTFASTCALL +PWCHAR +OB::LifeCycle::AllocateObjectName(IN ULONG Length, + IN BOOLEAN UseLookaside, + IN OUT PUNICODE_STRING ObjectName) +{ + ULONG MaximumLength; + PVOID Buffer; + + /* Calculate the required maximum length and initialize the buffer pointer */ + MaximumLength = Length + sizeof(WCHAR); + Buffer = NULLPTR; + + /* Check if the general pool must be used */ + if(!UseLookaside || MaximumLength > OBJECT_NAME_BUFFER_SIZE) + { + /* Allocate from the Memory Manager */ + MM::Allocator::AllocatePool(PagedPool, MaximumLength, (PVOID *)&Buffer, TAG_OB_NAME); + } + else + { + /* Set maximum length to the fixed lookaside entry size */ + MaximumLength = OBJECT_NAME_BUFFER_SIZE; + + /* Allocate from the lookaside list */ + Buffer = EX::LookasideList::AllocateFromPerProcessorList(LookasideNameBufferList); + } + + /* Initialize the Unicode string descriptor */ + ObjectName->Buffer = (PWCHAR)Buffer; + ObjectName->Length = (USHORT)Length; + ObjectName->MaximumLength = (USHORT)MaximumLength; + + /* Return the buffer pointer */ + return (PWCHAR)Buffer; +} + +/** + * Calculates the memory layout and sizes for optional object header components. + * + * @param CreateInfo + * Supplies a pointer to the object creation information. + * + * @param ObjectType + * Supplies an optional pointer to the object type definition. + * + * @param ObjectName + * Supplies an optional pointer to the unicode string representing the object's name. + * + * @param Layout + * Supplies a pointer to the layout structure that will receive the calculated sizes. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::LifeCycle::CalculateOptionalHeaderSize(IN POBJECT_CREATE_INFORMATION CreateInfo, + IN POBJECT_TYPE ObjectType, + IN PUNICODE_STRING ObjectName, + OUT POBJECT_OPTIONAL_HEADER_LAYOUT Layout) +{ + /* Zero the layout structure */ + RTL::Memory::ZeroMemory(Layout, sizeof(OBJECT_OPTIONAL_HEADER_LAYOUT)); + + /* Check if the CreateInfo pointer is valid */ + if(CreateInfo == NULLPTR) + { + /* Assign default sizes */ + Layout->NameInfoSize = sizeof(OBJECT_HEADER_NAME_INFO); + Layout->CreatorInfoSize = sizeof(OBJECT_HEADER_CREATOR_INFO); + } + else + { + /* Determine if quota tracking is required */ + if(ObjectType != NULLPTR && + (((CreateInfo->PagedPoolCharge != ObjectType->TypeInfo.DefaultPagedPoolCharge || + CreateInfo->NonPagedPoolCharge != ObjectType->TypeInfo.DefaultNonPagedPoolCharge || + CreateInfo->SecurityDescriptorCharge > SE_DEFAULT_SECURITY_QUOTA) && + PS::Process::GetCurrentProcess() != PS::Process::GetSystemProcess()) || + (CreateInfo->Attributes & OBJECT_EXCLUSIVE))) + { + /* Set the size for the Quota Information header */ + Layout->QuotaInfoSize = sizeof(OBJECT_HEADER_QUOTA_INFO); + } + + /* Check if the object type requires maintaining handle counts */ + if(ObjectType && ObjectType->TypeInfo.MaintainHandleCount) + { + /* Set the size for the Handle Information header */ + Layout->HandleInfoSize = sizeof(OBJECT_HEADER_HANDLE_INFO); + } + + /* Check if a valid object name was provided */ + if(ObjectName && ObjectName->Buffer) + { + /* Set the size for the Name Information header */ + Layout->NameInfoSize = sizeof(OBJECT_HEADER_NAME_INFO); + } + + /* Check if the object type requires maintaining a creator type list */ + if(ObjectType && ObjectType->TypeInfo.MaintainTypeList) + { + /* Set the size for the Creator Information header */ + Layout->CreatorInfoSize = sizeof(OBJECT_HEADER_CREATOR_INFO); + } + } + + /* Calculate the total size required for all optional headers */ + Layout->TotalSize = Layout->QuotaInfoSize + Layout->HandleInfoSize + + Layout->NameInfoSize + Layout->CreatorInfoSize; +} + +/** + * Captures and validates object creation information and attributes passed. + * + * @param ObjectType + * Optionally supplies a pointer to the type of object being created. + * + * @param ProcessorMode + * Supplies the processor mode used to probe user-mode structures for accessibility. + * + * @param OwnerProcessorMode + * Supplies the processor mode that will own the object. + * + * @param ObjectAttributes + * Supplies a pointer to the object attributes structure. + * + * @param CapturedObjectName + * Supplies a pointer to a Unicode string descriptor that will receive the captured name. + * + * @param ObjectCreateInfo + * Supplies a pointer to the internal structure receiving the validated creation parameters. + * + * @param UseLookaside + * Indicates whether lookaside lists should be used for name buffer allocations. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::LifeCycle::CaptureObjectCreateInformation(IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE ProcessorMode, + IN KPROCESSOR_MODE OwnerProcessorMode, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN OUT PUNICODE_STRING CapturedObjectName, + IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, + IN BOOLEAN UseLookaside) +{ + OBJECT_ATTRIBUTES CapturedAttributes; + PSECURITY_QUALITY_OF_SERVICE SecurityQos; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PUNICODE_STRING ObjectName; + XTSTATUS Status; + ULONG Size; + + /* Initialize local state variables */ + ObjectName = NULLPTR; + Status = STATUS_SUCCESS; + + /* Zero out the output structure */ + RTL::Memory::ZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION)); + + /* Check if the caller supplied object attributes */ + if(ObjectAttributes) + { + /* Enter structured exception handler for ObjectAttributes snapshot */ + __try + { + /* Check if the request originated from user mode */ + if(ProcessorMode != KernelMode) + { + /* Probe the object attributes structure */ + MM::Probe::ProbeForReadStructure(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG_PTR)); + + /* Snapshot the attributes to prevent TOCTOU and double-fetch vulnerabilities */ + CapturedAttributes = *(CONST VOLATILE POBJECT_ATTRIBUTES)ObjectAttributes; + } + else + { + /* Copy the descriptor directly */ + CapturedAttributes = *ObjectAttributes; + } + } + __except(RTL::Exception::SystemFilter()) + { + /* Catch memory access violations */ + return EXCEPTION_CODE; + } + + /* Validate structure length and verify that no unknown attributes are specified */ + if((CapturedAttributes.Length != sizeof(OBJECT_ATTRIBUTES)) || + (CapturedAttributes.Attributes & ~OBJECT_VALID_ATTRIBUTES)) + { + /* Return error code immediately */ + return STATUS_INVALID_PARAMETER; + } + + /* Capture the root directory and sanitize basic attribute flags */ + ObjectCreateInfo->RootDirectory = CapturedAttributes.RootDirectory; + ObjectCreateInfo->Attributes = CapturedAttributes.Attributes & OBJECT_VALID_ATTRIBUTES; + + /* Check if the owner works in user mode */ + if(OwnerProcessorMode != KernelMode) + { + /* Enforce kernel handle restrictions */ + ObjectCreateInfo->Attributes &= ~OBJECT_KERNEL_HANDLE; + } + + /* Cache pointers for subsequent capture and validation */ + ObjectName = CapturedAttributes.ObjectName; + SecurityDescriptor = CapturedAttributes.SecurityDescriptor; + SecurityQos = CapturedAttributes.SecurityQualityOfService; + + /* Check if QoS data is available */ + if(SecurityQos) + { + /* Enter structured exception handler for Security QoS snapshot */ + __try + { + /* Check if the request originated from user mode */ + if(ProcessorMode != KernelMode) + { + /* Probe the QoS structure */ + MM::Probe::ProbeForReadStructure(SecurityQos, sizeof(SECURITY_QUALITY_OF_SERVICE), sizeof(ULONG)); + + /* Snapshot QoS data to prevent TOCTOU vulnerabilities */ + ObjectCreateInfo->SecurityQualityOfService = *(CONST VOLATILE PSECURITY_QUALITY_OF_SERVICE)SecurityQos; + } + else + { + /* Copy QoS data directly */ + ObjectCreateInfo->SecurityQualityOfService = *SecurityQos; + } + } + __except(RTL::Exception::SystemFilter()) + { + /* Catch memory access violations */ + return EXCEPTION_CODE; + } + + /* Link the pointer */ + ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService; + } + + /* Capture Security Descriptor outside of the broad SEH to avoid masking kernel bugs */ + if(SecurityDescriptor) + { + /* Capture the security descriptor */ + Status = SE::Descriptor::CaptureSecurityDescriptor(SecurityDescriptor, ProcessorMode, PagedPool, + TRUE, &ObjectCreateInfo->SecurityDescriptor); + if(Status != STATUS_SUCCESS) + { + /* Clear the descriptor pointer on failure */ + ObjectCreateInfo->SecurityDescriptor = NULLPTR; + } + else + { + /* Compute and assign the security quota charge for the descriptor */ + SE::Descriptor::ComputeQuotaInformationSize(ObjectCreateInfo->SecurityDescriptor, &Size); + ObjectCreateInfo->ProbeMode = ProcessorMode; + ObjectCreateInfo->SecurityDescriptorCharge = SE::Descriptor::ComputeSecurityQuota(Size); + } + } + } + + /* Check If all structure and security captures succeeded */ + if(Status == STATUS_SUCCESS) + { + /* Validate if an object name is available */ + if(ObjectName) + { + /* Capture object name (This function has its own SEH protection) */ + Status = CaptureObjectName(ProcessorMode, ObjectName, CapturedObjectName, UseLookaside); + } + else + { + /* Initialize an empty name descriptor */ + CapturedObjectName->Buffer = NULLPTR; + CapturedObjectName->Length = 0; + CapturedObjectName->MaximumLength = 0; + + /* Check if this is a root directory */ + if(ObjectCreateInfo->RootDirectory) + { + /* Root directory cannot be used without an object name, set error code */ + Status = STATUS_OBJECT_NAME_INVALID; + } + } + } + + /* Check if any steps failed */ + if(Status != STATUS_SUCCESS) + { + /* Release object creation resources */ + ReleaseObjectCreateInformation(ObjectCreateInfo); + } + + /* Return status code */ + return Status; +} + +/** + * Captures an object name from user-mode or kernel-mode memory into a kernel buffer. + * + * @param ProcessorMode + * Supplies the processor mode used to probe user-mode structures for accessibility. + * + * @param ObjectName + * Supplies a pointer to the original Unicode string descriptor to be captured. + * + * @param CapturedObjectName + * Supplies a pointer to the Unicode string descriptor that will receive the captured buffer. + * + * @param UseLookaside + * Indicates whether a lookaside list should be used for the buffer allocation if applicable. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::LifeCycle::CaptureObjectName(IN KPROCESSOR_MODE ProcessorMode, + IN PUNICODE_STRING ObjectName, + IN OUT PUNICODE_STRING CapturedObjectName, + IN BOOLEAN UseLookaside) +{ + UNICODE_STRING InputObjectName; + XTSTATUS Status; + PWCHAR Buffer; + ULONG Length; + + /* Initialize local variables */ + Buffer = NULLPTR; + Status = STATUS_SUCCESS; + + /* Initialize the captured name descriptor */ + CapturedObjectName->Buffer = NULLPTR; + CapturedObjectName->Length = 0; + CapturedObjectName->MaximumLength = 0; + + /* Enter structural exception handler */ + __try + { + /* Check if the string originates from user-mode */ + if(ProcessorMode != KernelMode) + { + /* Probe and copy the Unicode string descriptor */ + MM::Probe::ProbeForRead(ObjectName, sizeof(UNICODE_STRING), alignof(UNICODE_STRING)); + InputObjectName = *(CONST VOLATILE PUNICODE_STRING)ObjectName; + + /* Probe the string buffer for read access */ + MM::Probe::ProbeForRead(InputObjectName.Buffer, InputObjectName.Length, sizeof(WCHAR)); + } + else + { + /* Copy the descriptor */ + InputObjectName = *ObjectName; + } + } + __except(RTL::Exception::SystemFilter()) + { + /* Catch memory access violations */ + Status = EXCEPTION_CODE; + } + + /* Check if the memory probing succeeded */ + if(Status == STATUS_SUCCESS) + { + /* Check if the string is not empty */ + Length = InputObjectName.Length; + if(Length > 0) + { + /* Ensure the length is properly aligned */ + if(((Length & (sizeof(WCHAR) - 1)) != 0) || (Length == (MAXUSHORT - sizeof(WCHAR) + 1))) + { + /* Set status code */ + Status = STATUS_OBJECT_NAME_INVALID; + } + else + { + /* Allocate the name buffer */ + Buffer = AllocateObjectName(Length, UseLookaside, CapturedObjectName); + if(!Buffer) + { + /* Buffer allocation failed, set status code */ + Status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + /* Enter structural exception handler */ + __try + { + /* Copy the string data into the buffer */ + RTL::Memory::CopyMemory(Buffer, InputObjectName.Buffer, Length); + + /* NULL-terminate the string */ + Buffer[Length / sizeof(WCHAR)] = (WCHAR)0; + } + __except(RTL::Exception::SystemFilter()) + { + /* Catch memory access violations */ + Status = EXCEPTION_CODE; + + /* Check if a buffer was allocated */ + if(Buffer) + { + /* Release the buffer */ + FreeObjectName(CapturedObjectName); + } + } + } + } + } + } + + /* Return status code */ + return Status; +} + +/** + * Creates a new object of the specified type and initializes it. + * + * @param ProcessorMode + * Supplies the processor mode used to probe parameters. + * + * @param ObjectType + * Supplies a pointer to the object type of the new object. + * + * @param ObjectAttributes + * Supplies an optional pointer to the object attributes structure. + * + * @param OwnerProcessorMode + * Supplies the processor mode that will own the object. + * + * @param ParseContext + * Supplies an optional pointer to a parse context structure. + * + * @param ObjectBodySize + * Supplies the size, in bytes, of the object body. + * + * @param PagedPoolCharge + * Supplies the paged pool charge for the object. If zero, default is used. + * + * @param NonPagedPoolCharge + * Supplies the non-paged pool charge for the object. If zero, default is used. + * + * @param Object + * Receives a pointer to the body of the newly created object. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::LifeCycle::CreateObject(IN KPROCESSOR_MODE ProcessorMode, + IN POBJECT_TYPE ObjectType, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN KPROCESSOR_MODE OwnerProcessorMode, + IN OUT PVOID ParseContext, + IN ULONG ObjectBodySize, + IN ULONG PagedPoolCharge, + IN ULONG NonPagedPoolCharge, + OUT PVOID *Object) +{ + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + UNICODE_STRING CapturedObjectName; + POBJECT_HEADER ObjectHeader; + XTSTATUS Status; + + /* Allocate the buffer for creation parameters */ + ObjectCreateInfo = (POBJECT_CREATE_INFORMATION)EX::LookasideList::AllocateFromPerProcessorList(LookasideCreateInfoList); + if(!ObjectCreateInfo) + { + /* Allocation failed, return error code */ + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Capture and probe the object attributes */ + Status = CaptureObjectCreateInformation(ObjectType, ProcessorMode, OwnerProcessorMode, ObjectAttributes, + &CapturedObjectName, ObjectCreateInfo, FALSE); + if(Status != STATUS_SUCCESS) + { + /* Capture failed, clean up and return error code */ + EX::LookasideList::FreeToPerProcessorList(LookasideCreateInfoList, ObjectCreateInfo); + return Status; + } + + /* Validate requested attributes */ + if(ObjectType && ObjectType->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes) + { + /* Release the captured creation info structure */ + FreeObjectCreateInformation(ObjectCreateInfo); + + /* Check if object name was captured */ + if(CapturedObjectName.Buffer) + { + /* Release the object name buffer */ + FreeObjectName(&CapturedObjectName); + } + + /* Return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Check if paged pool charge was specified */ + if(PagedPoolCharge == 0) + { + /* Use default paged pool charge */ + PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge; + } + + /* Check if non-paged pool charge was specified */ + if(NonPagedPoolCharge == 0) + { + /* Use default non-paged pool charge */ + NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge; + } + + /* Set the paged and non-paged pool charges */ + ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge; + ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge; + + /* Allocate the physical memory layout for the object */ + Status = AllocateObject(ObjectCreateInfo, OwnerProcessorMode, ObjectType, + &CapturedObjectName, ObjectBodySize, &ObjectHeader); + if(Status != STATUS_SUCCESS) + { + /* Allocation failed, cleanup the captured data */ + FreeObjectCreateInformation(ObjectCreateInfo); + + /* Check if object name was captured */ + if(CapturedObjectName.Buffer) + { + /* Free the captured object name */ + FreeObjectName(&CapturedObjectName); + } + + /* Return error code */ + return Status; + } + + /* Point the output pointer to the object */ + *Object = &ObjectHeader->Body; + + /* Check if the object is permanent */ + if(ObjectHeader->Flags & OBJECT_FLAG_PERMANENT) + { + /* Apply security constraints */ + if(!SE::Privileges::CheckSinglePrivilege(SE_LUID_CREATE_PERMANENT_PRIVILEGE, ProcessorMode)) + { + /* Privilege check failed, release the object and return error code */ + FreeObject(*Object); + return STATUS_PRIVILEGE_NOT_HELD; + } + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Enqueues an object header into a deferred deletion queue and queues a system worker thread if the list was empty. + * + * @param ObjectHeader + * Supplies a pointer to the object header to be queued for deletion. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::LifeCycle::DeferObjectDeletion(IN POBJECT_HEADER ObjectHeader) +{ + PVOID ListHead, OldListHead; + + /* Capture the snapshot of the removal list */ + OldListHead = RemoveObjectList; + + /* Process the deferred object deletion */ + while(TRUE) + { + /* Link the current head to object header */ + ObjectHeader->NextToFree = OldListHead; + + /* Push the header to the list head */ + ListHead = RTL::Atomic::CompareExchangePointer(&RemoveObjectList, OldListHead, ObjectHeader); + if(ListHead == OldListHead) + { + /* Successfully pushed to the stack, break the loop */ + break; + } + + /* The list changed mid-flight, update the snapshot and retry */ + OldListHead = ListHead; + } + + /* Check if the list was empty */ + if(!OldListHead) + { + /* Queue the deletion work item to the system worker queue */ + EX::WorkItem::QueueWorkItem(&RemoveObjectWorkItem, CriticalWorkQueue); + } +} + +/** + * Destructs an object, including invoking security and type-specific deletion callbacks and freeing memory. + * + * @param Object + * Supplies a pointer to the object being destroyed. + * + * @param WorkerThread + * Indicates whether this routine is executed in the context of the system worker thread. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::LifeCycle::DeleteObject(IN PVOID Object, + IN BOOLEAN WorkerThread) +{ + POBJECT_HEADER_CREATOR_INFO CreatorInfo; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER ObjectHeader; + POBJECT_TYPE ObjectType; + + /* Resolve object header */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + + /* Resolve creator information, name information pointers and object type*/ + CreatorInfo = GetObjectCreatorInformation(ObjectHeader); + NameInfo = GetObjectNameInformation(ObjectHeader); + ObjectType = ObjectHeader->Type; + + /* Check if the object has creator info and is linked in a type tracking list */ + if(CreatorInfo && !RTL::LinkedList::ListEmpty(&CreatorInfo->TypeList)) + { + /* Acquire exclusive access to the object type tracking list */ + KE::CriticalRegionGuard CriticalRegion; + KE::PushLockExclusiveGuard PushLock(&ObjectType->TypeLock); + + /* Unlink the object from the creator type list */ + RTL::LinkedList::RemoveEntryList(&CreatorInfo->TypeList); + } + + /* Check if the object has an allocated name buffer */ + if(NameInfo && NameInfo->Name.Buffer) + { + /* Free the name buffer pool allocation */ + FreeObjectName(&NameInfo->Name); + + /* Clear the name information fields */ + NameInfo->Name.Buffer = NULLPTR; + NameInfo->Name.Length = 0; + NameInfo->Name.MaximumLength = 0; + } + + /* Check if a security descriptor is attached */ + if(ObjectHeader->SecurityDescriptor) + { + /* Invoke the security procedure to delete the descriptor */ + ObjectType->TypeInfo.SecurityProcedure(Object, DeleteSecurityDescriptor, NULLPTR, NULLPTR, NULLPTR, + &ObjectHeader->SecurityDescriptor, NonPagedPool, NULLPTR); + } + + /* Check if a custom deletion procedure is registered */ + if(ObjectType->TypeInfo.DeleteProcedure) + { + /* Check if execution is occurring outside of the system worker thread */ + if(!WorkerThread) + { + /* Mark the object for deferred deletion */ + ObjectHeader->Flags |= OBJECT_FLAG_DEFER_DELETE; + } + + /* Invoke the type-specific delete procedure */ + ObjectType->TypeInfo.DeleteProcedure(Object); + } + + /* Free the object memory */ + FreeObject(Object); +} + +/** + * Decrements the pointer reference count of an object. + * + * @param Object + * Supplies a pointer to the object body to dereference. + * + * @return This routine returns the updated reference count. + */ +XTFASTCALL +LONG_PTR +OB::LifeCycle::DereferenceObject(IN PVOID Object) +{ + POBJECT_HEADER ObjectHeader; + LONG_PTR NewCount; + + /* Resolve the object header */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + + /* Decrement the reference count */ + NewCount = RTL::Atomic::Decrement64(&ObjectHeader->PointerCount); + + /* Check for object expiration */ + if(NewCount == 0) + { + /* Check if object can be deleted */ + if(KE::RunLevel::GetCurrentRunLevel() == PASSIVE_LEVEL) + { + /* Delete the object immediately */ + DeleteObject(Object, FALSE); + } + else + { + /* Defer deletion to worker thread */ + DeferObjectDeletion(ObjectHeader); + } + } + + /* Return the updated reference count */ + return NewCount; +} + +/** + * Decrements the pointer reference count of an object by a specified amount. + * + * @param Object + * Supplies a pointer to the object body to dereference. + * + * @param Count + * Specifies a number of references to release. + * + * @return This routine returns the updated reference count. + */ +XTFASTCALL +LONG_PTR +OB::LifeCycle::DereferenceObject(IN PVOID Object, + IN ULONG Count) +{ + POBJECT_HEADER ObjectHeader; + LONG_PTR ReferenceCount; + + /* Resolve the object header */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + + /* Decrement the reference count */ + ReferenceCount = RTL::Atomic::ExchangeAdd64(&ObjectHeader->PointerCount, -(LONG_PTR)(Count)) - Count; + + /* Check for object expiration */ + if(ReferenceCount == 0) + { + /* Defer deletion to worker thread */ + DeferObjectDeletion(ObjectHeader); + } + + /* Return the updated reference count */ + return ReferenceCount; +} + +/** + * Decrements the reference count of an object and defers its deletion to a worker thread if the count reaches zero. + * + * @param Object + * Supplies a pointer to the object body. + * + * @return This routine returns the updated reference count. + * + * @since XT 1.0 + */ +XTFASTCALL +LONG_PTR +OB::LifeCycle::DereferenceObjectDeferDelete(IN PVOID Object) +{ + POBJECT_HEADER ObjectHeader; + LONG_PTR ReferenceCount; + + /* Resolve the object header */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + + /* Decrement the reference count */ + ReferenceCount = RTL::Atomic::Decrement64(&ObjectHeader->PointerCount); + + /* Check for object expiration */ + if(ReferenceCount == 0) + { + /* Defer deletion to worker thread */ + DeferObjectDeletion(ObjectHeader); + } + + /* Return the updated reference count */ + return ReferenceCount; +} + +/** + * Decrements the query reference count of a NameInfo structure and frees its resources if the count reaches zero. + * + * @param NameInfo + * Supplies a pointer to the object header name information structure. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::LifeCycle::DereferenceObjectNameInformation(IN POBJECT_HEADER_NAME_INFO NameInfo) +{ + POBJECT_DIRECTORY Directory; + + /* Ensure the name info pointer is valid */ + if(!NameInfo) + { + /* Name info pointer is invalid, return */ + return; + } + + /* Decrement the query reference count */ + if(RTL::Atomic::Decrement32((PLONG)&NameInfo->QueryReferences) != 0) + { + /* References are still active, return */ + return; + } + + /* Check if the name buffer is allocated */ + if(NameInfo->Name.Buffer) + { + /* Free the name buffer */ + FreeObjectName(&NameInfo->Name); + + /* Reset the name string fields */ + NameInfo->Name.Buffer = NULLPTR; + NameInfo->Name.Length = 0; + NameInfo->Name.MaximumLength = 0; + } + + /* Extract the directory pointer and check if it is valid */ + Directory = NameInfo->Directory; + if(Directory != NULLPTR) + { + /* Clear the directory reference */ + NameInfo->Directory = NULLPTR; + + /* Defer the deletion of the directory object */ + DereferenceObjectDeferDelete(Directory); + } +} + +/** + * Frees the memory allocated for an object and its associated optional headers. + * + * @param Object + * Supplies a pointer to the object body to be freed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::LifeCycle::FreeObject(IN PVOID Object) +{ + POBJECT_HEADER_HANDLE_INFO HandleInfo; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER ObjectHeader; + POBJECT_TYPE ObjectType; + PVOID AllocationBase; + + /* Resolve the object header and object type */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + ObjectType = ObjectHeader->Type; + + /* Calculate the base of the pool allocation */ + AllocationBase = GetObjectAllocationBase(ObjectHeader); + + /* Check if the object type exists */ + if(ObjectType) + { + /* Decrement the count of active objects for this type */ + RTL::Atomic::Decrement32((VOLATILE PLONG)&ObjectType->TotalNumberOfObjects); + } + + /* Check if the object is not fully initialized */ + if(ObjectHeader->Flags & OBJECT_FLAG_NEW_OBJECT) + { + /* Check if creation information exists */ + if(ObjectHeader->ObjectCreateInfo) + { + /* Free the captured creation parameters */ + FreeObjectCreateInformation((ObjectHeader->ObjectCreateInfo)); + + /* Nullify the pointer */ + ObjectHeader->ObjectCreateInfo = NULLPTR; + } + } + else + { + /* Fully initialized object, return quotas */ + ReturnObjectQuota(ObjectHeader, ObjectType); + } + + /* Locate handle information */ + HandleInfo = (POBJECT_HEADER_HANDLE_INFO)(!ObjectHeader->HandleInfoOffset ? NULLPTR : (PCHAR)ObjectHeader - + ObjectHeader->HandleInfoOffset); + if(HandleInfo && !(ObjectHeader->Flags & OBJECT_FLAG_SINGLE_PROCESS)) + { + /* Free the handle */ + MM::Allocator::FreePool(HandleInfo->HandleCountDatabase); + } + + /* Locate name information */ + NameInfo = (POBJECT_HEADER_NAME_INFO)(!ObjectHeader->NameInfoOffset ? NULLPTR : (PCHAR)ObjectHeader - + ObjectHeader->NameInfoOffset); + if(NameInfo && NameInfo->Name.Buffer) + { + /* Free the object name buffer */ + FreeObjectName(&NameInfo->Name); + } + + /* Mark object type and free memory */ + ObjectHeader->Type = (POBJECT_TYPE)(ULONG_PTR)0xBAD0B0B0; + MM::Allocator::FreePool(AllocationBase, (ObjectType == NULLPTR ? TAG_OB_OBJECT_TYPE : ObjectType->Key)); +} + +/** + * Releases creation information resources and returns them back to the lookaside list. + * + * @param CreateInfo + * Supplies a pointer to the object creation information structure to be freed. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::LifeCycle::FreeObjectCreateInformation(IN POBJECT_CREATE_INFORMATION CreateInfo) +{ + /* Release the object creation information */ + ReleaseObjectCreateInformation(CreateInfo); + + /* Free the attributes from the lookaside list */ + EX::LookasideList::FreeToPerProcessorList(LookasideCreateInfoList, CreateInfo); +} + + +/** + * Frees an object name buffer either to the general pool or a dedicated lookaside list. + * + * @param ObjectName + * Supplies a pointer to the Unicode string whose buffer is being released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::LifeCycle::FreeObjectName(IN OUT PUNICODE_STRING ObjectName) +{ + /* Check if the buffer size differs from the lookaside list entry size */ + if(ObjectName->MaximumLength != OBJECT_NAME_BUFFER_SIZE) + { + /* Size mismatch, free the allocation to the system pool */ + MM::Allocator::FreePool(ObjectName->Buffer); + } + else + { + /* Size matches, return the buffer to the lookaside list */ + EX::LookasideList::FreeToPerProcessorList(LookasideNameBufferList, ObjectName->Buffer); + } +} + +/** + * Resolves the base address of the pool allocation for a given object. + * + * @param ObjectHeader + * Supplies a pointer to the object header. + * + * @return This routine returns the pointer to the start of the memory block. + * + * @since XT 1.0 + */ +XTAPI +PVOID +OB::LifeCycle::GetObjectAllocationBase(IN POBJECT_HEADER ObjectHeader) +{ + /* Check if the Quota Information header is present */ + if(ObjectHeader->QuotaInfoOffset) + { + /* Return the base address including the Quota Information header */ + return (PUCHAR)ObjectHeader - ObjectHeader->QuotaInfoOffset; + } + + /* Check if the Handle Information header is present */ + if(ObjectHeader->HandleInfoOffset) + { + /* Return the base address including the Handle Information header */ + return (PUCHAR)ObjectHeader - ObjectHeader->HandleInfoOffset; + } + + /* Check if the Name Information header is present */ + if(ObjectHeader->NameInfoOffset) + { + /* Return the base address including the Name Information header */ + return (PUCHAR)ObjectHeader - ObjectHeader->NameInfoOffset; + } + + /* Check if the Creator Information header is present */ + if(ObjectHeader->Flags & OBJECT_FLAG_CREATOR_INFO) + { + /* Return the base address including the Creator Information header */ + return (PUCHAR)ObjectHeader - sizeof(OBJECT_HEADER_CREATOR_INFO); + } + + /* No optional headers exist, return the header address */ + return ObjectHeader; +} + +/** + * Retrieves the optional creator information header for a given object. + * + * @param ObjectHeader + * Supplies a pointer to the object's base header. + * + * @return This routine returns a pointer to the creator information, or NULLPTR if not present. + * + * @since XT 1.0 + */ +XTFASTCALL +POBJECT_HEADER_CREATOR_INFO +OB::LifeCycle::GetObjectCreatorInformation(IN POBJECT_HEADER ObjectHeader) +{ + /* Verify if the creator flag is set */ + if((ObjectHeader->Flags & OBJECT_FLAG_CREATOR_INFO) == 0) + { + /* Creator information not present, return NULL pounter */ + return NULLPTR; + } + + /* Return the creator information */ + return (POBJECT_HEADER_CREATOR_INFO)((PCHAR)ObjectHeader - sizeof(OBJECT_HEADER_CREATOR_INFO)); +} + +/** + * Retrieves the optional name information header for a given object. + * + * @param ObjectHeader + * Supplies a pointer to the object's base header. + * + * @return This routine returns a pointer to the name information, or NULLPTR if not present. + * + * @since XT 1.0 + */ +XTFASTCALL +POBJECT_HEADER_NAME_INFO +OB::LifeCycle::GetObjectNameInformation(IN POBJECT_HEADER ObjectHeader) +{ + /* Check if the header is present */ + if(!ObjectHeader->NameInfoOffset) + { + /* Name information not present, return NULL pointer */ + return NULLPTR; + } + + /* Return the name information */ + return (POBJECT_HEADER_NAME_INFO)((PCHAR)ObjectHeader - ObjectHeader->NameInfoOffset); +} + +/** + * Initializes the Object lifecycle subsystem. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::LifeCycle::InitializeObjectLifeCycle(VOID) +{ + /* Clear tracking pointer */ + RemoveObjectList = NULLPTR; + + /* Create the kernel handle table and attach it to the current process */ + KernelHandleTable = OB::HandleTable::CreateHandleTable(NULLPTR); + PS::Process::GetCurrentProcess()->ObjectTable = KernelHandleTable; + + /* Initialize deferred removal work item */ + EX::WorkItem::InitializeWorkItem(&RemoveObjectWorkItem, ProcessDeferredDeletionQueue, NULLPTR); +} + +/** + * Processes the deferred object removal queue. + * + * @param Parameter + * Supplies an optional context parameter. + * + * @return This routine does not return a value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::LifeCycle::ProcessDeferredDeletionQueue(IN PVOID Parameter) +{ + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER NextObject; + PVOID OldValue; + + /* Process the deferred removal queue */ + while(TRUE) + { + /* Exchange the queue pointer */ + ObjectHeader = (POBJECT_HEADER)RTL::Atomic::ExchangePointer(&RemoveObjectList, OBJECT_REMOVE_QUEUE_LOCKED); + + /* Traverse and process the detached list */ + while(ObjectHeader && ObjectHeader != (POBJECT_HEADER)OBJECT_REMOVE_QUEUE_LOCKED) + { + /* Capture the pointer to the next object */ + NextObject = (POBJECT_HEADER)ObjectHeader->NextToFree; + + /* Destroy object */ + DeleteObject(&ObjectHeader->Body, TRUE); + + /* Advance to the next object */ + ObjectHeader = NextObject; + } + + /* Check if the queue is still locked */ + if(RemoveObjectList == OBJECT_REMOVE_QUEUE_LOCKED) + { + /* Clear the lock */ + OldValue = RTL::Atomic::CompareExchangePointer(&RemoveObjectList, OBJECT_REMOVE_QUEUE_LOCKED, NULLPTR); + if(OldValue == OBJECT_REMOVE_QUEUE_LOCKED) + { + /* Empty list, exit the worker */ + break; + } + } + } +} + +/** + * Increments the pointer reference count of an object. + * + * @param Object + * Supplies a pointer to the object body to reference. + * + * @return This routine returns the updated reference count. + */ +XTFASTCALL +LONG_PTR +OB::LifeCycle::ReferenceObject(IN PVOID Object) +{ + POBJECT_HEADER ObjectHeader; + + /* Resolve the object header */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + + /* Increment the reference count */ + return RTL::Atomic::Increment64(&ObjectHeader->PointerCount); +} + +/** + * Increments the pointer reference count of an object by a specified amount. + * + * @param Object + * Supplies a pointer to the object body to reference. + * + * @param Count + * Specifies a number of references to acquire. + * + * @return This routine returns the updated reference count. + */ +XTFASTCALL +LONG_PTR +OB::LifeCycle::ReferenceObject(IN PVOID Object, + IN ULONG Count) +{ + POBJECT_HEADER ObjectHeader; + + /* Resolve the object header */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + + /* Increment the reference count */ + return RTL::Atomic::ExchangeAdd64(&ObjectHeader->PointerCount, Count) + Count; +} + +/** + * Increments the pointer reference count on an object provided by a handle. + * + * @param Handle + * Supplies the handle to the object being referenced. + * + * @param AccessMask + * Supplies the access mask representing the requested access rights. + * + * @param ObjectType + * Optionally supplies a pointer to the expected object type to validate against. + * + * @param ProcessorMode + * Supplies the processor mode from which the handle is being accessed. + * + * @param Object + * Receives a pointer to the referenced object body upon success. + * + * @param HandleInformation + * Supplies an optional pointer that receives information regarding the handle's granted access and attributes. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::LifeCycle::ReferenceObject(IN HANDLE Handle, + IN ACCESS_MASK AccessMask, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE ProcessorMode, + OUT PVOID *Object, + OUT POBJECT_HANDLE_INFORMATION HandleInformation) +{ + PHANDLE_TABLE_ENTRY ObjectTableEntry; + PHANDLE_TABLE_ENTRY_INFO ObjectInfo; + POBJECT_TYPE PseudoObjectType; + POBJECT_HEADER ObjectHeader; + PHANDLE_TABLE HandleTable; + ACCESS_MASK GrantedAccess; + PVOID PseudoObject; + PEPROCESS Process; + PETHREAD Thread; + XTSTATUS Status; + + /* Initialize the output pointer */ + *Object = NULLPTR; + + /* Retrieve the current execution context */ + Thread = PS::Thread::GetCurrentThread(); + Process = PS::Process::GetCurrentProcess(); + + /* Determine if the handle is a special kernel handle or a pseudohandle */ + if((LONG)(ULONG_PTR)Handle < 0) + { + /* Check if the handle points to the current process or thread */ + if(Handle == PS_CURRENT_PROCESS_HANDLE || Handle == PS_CURRENT_THREAD_HANDLE) + { + /* Check if the handle points to the current process */ + if(Handle == PS_CURRENT_PROCESS_HANDLE) + { + /* Bind the execution context to the current process pseudohandle */ + PseudoObject = (PVOID)Process; + PseudoObjectType = PS::ProcessManager::GetProcessType(); + GrantedAccess = Process->GrantedAccess; + } + else + { + /* Bind the execution context to the current thread pseudohandle */ + PseudoObject = (PVOID)Thread; + PseudoObjectType = PS::ProcessManager::GetThreadType(); + GrantedAccess = Thread->GrantedAccess; + } + + /* Validate the object type */ + if(ObjectType && ObjectType != PseudoObjectType) + { + /* Object type does not match the pseudohandle type, return error code */ + return STATUS_OBJECT_TYPE_MISMATCH; + } + + /* Enforce security constraints for user-mode requests */ + if(ProcessorMode != KernelMode && SE::Access::ComputeDeniedAccesses(GrantedAccess, AccessMask)) + { + /* The caller lacks the requested access rights, return error code */ + return STATUS_ACCESS_DENIED; + } + + /* Resolve the object header */ + ObjectHeader = CONTAIN_RECORD(PseudoObject, OBJECT_HEADER, Body); + + /* Increment the reference count */ + RTL::Atomic::Increment64(&ObjectHeader->PointerCount); + + /* Check if handle information is requested */ + if(HandleInformation) + { + /* Populate the optional handle information descriptor */ + HandleInformation->GrantedAccess = GrantedAccess; + HandleInformation->HandleAttributes = 0; + } + + /* Assign the object pointer and return */ + *Object = PseudoObject; + return STATUS_SUCCESS; + } + + /* Check if request comes from a user-mode */ + if(ProcessorMode != KernelMode) + { + /* Reject user-mode attempt, return error code */ + return STATUS_INVALID_HANDLE; + } + + /* Decode the kernel handle and select the system handle table */ + Handle = OB::Handle::DecodeKernelHandle(Handle); + HandleTable = KernelHandleTable; + } + else + { + /* Use the process handle table */ + HandleTable = Process->ObjectTable; + } + + /* Enter a critical region */ + KE::CriticalRegionGuard CriticalRegion(&Thread->ThreadControlBlock); + + /* Map the given handle to its underlying physical table entry */ + ObjectTableEntry = OB::HandleTable::MapHandleToPointer(HandleTable, Handle); + if(!ObjectTableEntry) + { + /* The handle is invalid or closed, return error code */ + return STATUS_INVALID_HANDLE; + } + + /* Resolve the object header */ + ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)ObjectTableEntry->Object) & ~OBJECT_HANDLE_ATTRIBUTES); + + /* Verify object type consistency */ + if(ObjectType && ObjectHeader->Type != ObjectType) + { + /* Set status code */ + Status = STATUS_OBJECT_TYPE_MISMATCH; + } + else + { + /* Decode the granted access mask */ + GrantedAccess = ((ObjectTableEntry->GrantedAccess) & ~OBJECT_ACCESS_PROTECT_CLOSE_BIT); + + /* Verify if the caller possesses the requested access rights */ + if(ProcessorMode != KernelMode && SE::Access::ComputeDeniedAccesses(GrantedAccess, AccessMask)) + { + /* Set status code */ + Status = STATUS_ACCESS_DENIED; + } + else + { + /* Check if handle information is requested */ + if(HandleInformation) + { + /* Populate the optional handle information descriptor */ + HandleInformation->GrantedAccess = GrantedAccess; + HandleInformation->HandleAttributes = OB::Handle::GetHandleAttributes(ObjectTableEntry); + } + + /* Check if audit is required */ + if((ObjectTableEntry->ObAttributes & OBJECT_AUDIT_OBJECT_CLOSE) && AccessMask && ProcessorMode != KernelMode) + { + /* Fetch the handle information */ + ObjectInfo = OB::HandleTable::GetHandleInformation(HandleTable, Handle, TRUE); + if(ObjectInfo && ObjectInfo->AuditMask) + { + /* Generate a security audit event */ + OB::Security::AuditObjectAccess(Handle, ObjectInfo, &ObjectHeader->Type->Name, AccessMask); + } + } + + /* Increment the reference count */ + RTL::Atomic::Increment64(&ObjectHeader->PointerCount); + + /* Assign the object pointer and mark the operation as successful */ + *Object = &ObjectHeader->Body; + Status = STATUS_SUCCESS; + } + } + + /* Release the handle table */ + OB::HandleTable::UnlockHandleTableEntry(HandleTable, ObjectTableEntry); + + /* Return status code */ + return Status; +} + +/** + * Increments the query reference count of a NameInfo structure. + * + * @param ObjectHeader + * Supplies a pointer to the object header associated with the NameInfo. + * + * @return This routine returns a pointer to the referenced NameInfo, or NULLPTR if the reference could not be acquired. + * + * @since XT 1.0 + */ +XTFASTCALL +POBJECT_HEADER_NAME_INFO +OB::LifeCycle::ReferenceObjectNameInformation(IN POBJECT_HEADER ObjectHeader) +{ + LONG OldReferences, NewReferences, ActualReferences; + POBJECT_HEADER_NAME_INFO NameInfo; + + /* Resolve the name information structure from the object header */ + NameInfo = GetObjectNameInformation(ObjectHeader); + + /* Ensure the name info structure is present */ + if(!NameInfo) + { + /* Return NULL pointer */ + return NULLPTR; + } + + /* Initialize the old reference count snapshot */ + OldReferences = *(volatile LONG*)&NameInfo->QueryReferences; + + /* Process the reference count */ + while(TRUE) + { + /* Check if the reference count has dropped to zero */ + if((OldReferences & ~OBJECT_NAME_LOCKED) == 0) + { + /* Abort and return NULL pointer */ + return NULLPTR; + } + + /* Calculate the incremented reference count */ + NewReferences = OldReferences + 1; + + /* Commit the incremented count */ + ActualReferences = RTL::Atomic::CompareExchange32((PLONG)&NameInfo->QueryReferences, OldReferences, NewReferences); + if(ActualReferences == OldReferences) + { + /* Break the loop */ + break; + } + + /* State changed, update the snapshot and retry */ + OldReferences = ActualReferences; + } + + /* Check if the name is currently locked */ + if(OldReferences & OBJECT_NAME_LOCKED) + { + /* Synchronize with the directory lock */ + KE::PushLock::WaitOnPushLock(&NameInfo->Directory->Lock); + } + + /* Return the referenced name info */ + return NameInfo; +} + +/** + * Releases security resources associated with an object creation information structure. + * + * @param CreateInfo + * Supplies a pointer to the object creation information structure to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::LifeCycle::ReleaseObjectCreateInformation(IN POBJECT_CREATE_INFORMATION CreateInfo) +{ + /* Verify if a security descriptor was captured and is actively attached */ + if(CreateInfo->SecurityDescriptor) + { + /* Release the descriptor */ + SE::Descriptor::ReleaseSecurityDescriptor(CreateInfo->SecurityDescriptor, CreateInfo->ProbeMode, TRUE); + + /* Nullify the pointer */ + CreateInfo->SecurityDescriptor = NULLPTR; + } +} + +/** + * Processes and returns pool quotas associated with an object's execution block. + * + * @param ObjectHeader + * Supplies a pointer to the object header. + * + * @param ObjectType + * Supplies a pointer to the object type definition. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::LifeCycle::ReturnObjectQuota(IN POBJECT_HEADER ObjectHeader, + IN POBJECT_TYPE ObjectType) +{ + POBJECT_HEADER_QUOTA_INFO Quota; + ULONG NonPagedPoolCharge; + ULONG PagedPoolCharge; + + /* Verify if a quota block is charged for the object */ + if(!ObjectHeader->QuotaBlockCharged) + { + /* No quota charged, nothing to do */ + return; + } + + /* Retrieve the quota information header */ + Quota = (POBJECT_HEADER_QUOTA_INFO)(ObjectHeader->QuotaInfoOffset == 0 ? NULLPTR : ((PCHAR)ObjectHeader - ObjectHeader->QuotaInfoOffset)); + if(Quota) + { + /* Extract the pool charges */ + NonPagedPoolCharge = Quota->NonPagedPoolCharge; + PagedPoolCharge = Quota->PagedPoolCharge + Quota->SecurityDescriptorCharge; + } + else + { + /* No quota header present, use default charges */ + NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge; + PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge; + + /* Check if the object holds a default security descriptor quota */ + if(ObjectHeader->Flags & OBJECT_FLAG_SECURITY_QUOTA) + { + /* Add the default security quota to the paged pool charge */ + PagedPoolCharge += SE_DEFAULT_SECURITY_QUOTA; + } + } + + /* Return the calculated pool charges */ + PS::Quota::ReturnSharedPoolQuota((PEPROCESS_QUOTA_BLOCK)ObjectHeader->QuotaBlockCharged, + PagedPoolCharge, NonPagedPoolCharge); + + /* Nullify the quota block pointer */ + ObjectHeader->QuotaBlockCharged = NULLPTR; +} diff --git a/xtoskrnl/ob/obdir.cc b/xtoskrnl/ob/obdir.cc new file mode 100644 index 0000000..3881fa7 --- /dev/null +++ b/xtoskrnl/ob/obdir.cc @@ -0,0 +1,582 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/obdir.cc + * DESCRIPTION: Object Manager Directory + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Acquires an exclusive pushlock for the specified object directory. + * + * @param Directory + * Supplies a pointer to the object directory being locked. + * + * @param LookupContext + * Supplies a pointer to the lookup context used to track the lock state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Directory::AcquireExclusiveDirectoryLock(IN OUT POBJECT_DIRECTORY Directory, + IN OUT POBJECT_LOOKUP_CONTEXT LookupContext) +{ + /* Set the initial lock state */ + LookupContext->LockStateSignature = OBJECT_LOCK_STATE_WAIT_EXCLUSIVE; + + /* Disable kernel APCs */ + KE::KThread::EnterCriticalRegion(); + + /* Acquire the directory lock for exclusive access */ + KE::PushLock::AcquireExclusivePushLock(&Directory->Lock); + + /* Update the lock state */ + LookupContext->LockStateSignature = OBJECT_LOCK_STATE_OWNED_EXCLUSIVE; +} + +/** + * Acquires a shared pushlock for the specified object directory. + * + * @param Directory + * Supplies a pointer to the object directory being locked. + * + * @param LookupContext + * Supplies a pointer to the lookup context used to track the lock state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Directory::AcquireSharedDirectoryLock(IN POBJECT_DIRECTORY Directory, + IN POBJECT_LOOKUP_CONTEXT LookupContext) +{ + /* Set the initial lock state */ + LookupContext->LockStateSignature = OBJECT_LOCK_WAITSHARED_SIGNATURE; + + /* Disable kernel APCs */ + KE::KThread::EnterCriticalRegion(); + + /* Acquire the directory lock for shared access */ + KE::PushLock::AcquireSharedPushLock(&Directory->Lock); + + /* Update the lock state */ + LookupContext->LockStateSignature = OBJECT_LOCK_OWNEDSHARED_SIGNATURE; +} + +/** + * Computes the case-insensitive hash index for an object name. + * + * @param Name + * Supplies a pointer to the unicode string containing the object name. + * + * @return This routine returns the computed hash index. + * + * @since XT 1.0 + */ +XTFASTCALL +ULONG +OB::Directory::ComputeObjectNameHash(IN PCUNICODE_STRING Name) +{ + ULONG CharacterLength, HashIndex; + WCHAR Character; + PWCH Buffer; + + /* Initialize the buffer pointer, character count, and starting hash value */ + Buffer = Name->Buffer; + CharacterLength = Name->Length / sizeof(WCHAR); + HashIndex = 0; + + /* Iterate through each wide character */ + while(CharacterLength--) + { + /* Fetch the current character and advance the buffer pointer */ + Character = *Buffer++; + + /* Apply the NT string hashing polynomial */ + HashIndex += (HashIndex << 1) + (HashIndex >> 1); + + /* Check if the character is uppercase, numeric, or a symbol */ + if(Character < L'a') + { + /* Add the unmodified character */ + HashIndex += Character; + } + else if(Character > L'z') + { + /* Convert extended Unicode characters to uppercase */ + HashIndex += RTL::Nls::ToUpperUnicodeCharacter(Character); + } + else + { + /* Perform ASCII conversion from lowercase to uppercase */ + HashIndex += (Character - (L'a' - L'A')); + } + } + + /* Return the final hash value */ + return HashIndex % OBJECT_NUMBER_HASH_BUCKETS; +} + +/** + * Removes an object directory entry from its hash bucket and frees its memory. + * + * @param LookupContext + * Supplies a pointer to the lookup context containing the directory and hash index. + * + * @return This routine returns TRUE if the entry was successfully unlinked and freed, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::Directory::DeleteDirectoryEntry(IN POBJECT_LOOKUP_CONTEXT LookupContext) +{ + POBJECT_DIRECTORY_ENTRY DirectoryEntry, *HashBucket; + POBJECT_DIRECTORY Directory; + + /* Extract the directory from the lookup context */ + Directory = LookupContext->Directory; + + /* Verify that the directory pointer is valid */ + if(Directory) + { + /* Resolve the head of the collision chain */ + HashBucket = (POBJECT_DIRECTORY_ENTRY*)&Directory->HashBuckets[LookupContext->HashIndex]; + + /* Retrieve the entry at the head of the chain */ + DirectoryEntry = *HashBucket; + + /* Ensure there isan entry to delete */ + if(DirectoryEntry) + { + /* Unlink the entry from the hash bucket chain */ + *HashBucket = DirectoryEntry->ChainLink; + DirectoryEntry->ChainLink = NULLPTR; + + /* Free the memory */ + MM::Allocator::FreePool(DirectoryEntry); + + /* Return TRUE */ + return TRUE; + } + } + + /* No entry found, return FALSE */ + return FALSE; +} + +/** + * Initializes the Object Manager lookup context. + * + * @param LookupContext + * Supplies a pointer to the caller-allocated lookup context to initialize. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Directory::InitializeLookupContext(OUT POBJECT_LOOKUP_CONTEXT LookupContext) +{ + /* Initialize the lookup context */ + LookupContext->Directory = NULLPTR; + LookupContext->DirectoryLocked = FALSE; + LookupContext->LockStateSignature = OBJECT_LOCK_STATE_INITIALIZED; + LookupContext->Object = NULLPTR; +} + +/** + * Inserts a newly created object into an object directory. + * + * @param Directory + * Pointer to the object directory where the object will be inserted. + * + * @param LookupContext + * Pointer to the lookup context containing the precomputed hash index. + * + * @param ObjectHeader + * Pointer to the object header of the object being inserted. + * + * @return TRUE if the insertion was successful, FALSE if pool allocation failed. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::Directory::InsertDirectoryEntry(IN OUT POBJECT_DIRECTORY Directory, + IN POBJECT_LOOKUP_CONTEXT LookupContext, + IN OUT POBJECT_HEADER ObjectHeader) +{ + POBJECT_DIRECTORY_ENTRY *HashBucket, NewEntry; + POBJECT_HEADER_NAME_INFO NameInfo; + XTSTATUS Status; + + /* Extract the name information header */ + NameInfo = OB::LifeCycle::GetObjectNameInformation(ObjectHeader); + + /* Allocate the directory entry */ + Status = MM::Allocator::AllocatePool(PagedPool, sizeof(OBJECT_DIRECTORY_ENTRY), + (PVOID *)&NewEntry, TAG_OB_DIRECTORY); + if(Status != STATUS_SUCCESS || !NewEntry) + { + /* Allocation failed, return FALSE */ + return FALSE; + } + + /* Resolve the hash bucket head */ + HashBucket = (POBJECT_DIRECTORY_ENTRY*)&Directory->HashBuckets[LookupContext->HashIndex]; + + /* Insert the entry at the head of the collision chain */ + NewEntry->ChainLink = *HashBucket; + *HashBucket = NewEntry; + + /* Link the entry to the object body and establish the parent directory */ + NewEntry->Object = &ObjectHeader->Body; + NameInfo->Directory = Directory; + + /* Return TRUE */ + return TRUE; +} + +/** + * Acquires an exclusive lock on the specified object directory. + * + * @param Directory + * Supplies a pointer to the object directory to lock. + * + * @param LookupContext + * Supplies a pointer to the active lookup context used to track the lock state. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Directory::LockLookupContext(IN POBJECT_DIRECTORY Directory, + IN POBJECT_LOOKUP_CONTEXT LookupContext) +{ + /* Acquire exclusive access to the directory */ + AcquireExclusiveDirectoryLock(Directory, LookupContext); + + /* Cache the directory pointer and lock ownership */ + LookupContext->Directory = Directory; + LookupContext->DirectoryLocked = TRUE; +} + +/** + * Looks up an object directory entry by name within the namespace. + * + * @param Directory + * Supplies a pointer to the primary object directory to search. + * + * @param Name + * Supplies a pointer to the name of the object to locate. + * + * @param Attributes + * Supplies the object attributes bitmask. + * + * @param SearchGlobalDirectory + * Specifies whether to fallback into the device map's global shadow directory if the object is not found + * in the primary directory. + * + * @param LookupContext + * Supplies a pointer to the tracking context. + * + * @return This routine returns a pointer to the referenced object body, or NULLPTR if resolution fails. + * + * @since XT 1.0 + */ +XTAPI +PVOID +OB::Directory::LookupDirectoryEntry(IN POBJECT_DIRECTORY Directory, + IN PUNICODE_STRING Name, + IN ULONG Attributes, + IN BOOLEAN SearchGlobalDirectory, + OUT POBJECT_LOOKUP_CONTEXT LookupContext) +{ + POBJECT_HEADER_NAME_INFO PreviousNameInfo; + POBJECT_DIRECTORY CurrentDirectory; + BOOLEAN CaseInsensitive; + PVOID FoundObject; + ULONG HashIndex; + + /* Initialize the default return value */ + FoundObject = NULLPTR; + + /* Check if global device map traversal is available */ + if(!OB::DeviceMap::GetUniqueDeviceMaps()) + { + /* Override caller's request to prevent shadow directory traversal */ + SearchGlobalDirectory = FALSE; + } + + /* Guard against invalid parameter combination */ + if(Directory != NULLPTR && Name != NULLPTR && Name->Length != 0 && Name->Buffer != NULLPTR) + { + /* Determine if the string comparison should ignore case */ + CaseInsensitive = (Attributes & OBJECT_CASE_INSENSITIVE) ? TRUE : FALSE; + + /* Precompute the hash index */ + HashIndex = ComputeObjectNameHash(Name); + + /* Initialize the traversal pointer */ + CurrentDirectory = Directory; + + /* Cache the computed hash index in the lookup context */ + LookupContext->HashIndex = (USHORT)HashIndex; + + /* Iterate through the directory and linked shadow boundaries */ + while(CurrentDirectory) + { + /* Check if the directory is locked */ + if(!LookupContext->DirectoryLocked) + { + /* Acquire the directory lock */ + AcquireSharedDirectoryLock(CurrentDirectory, LookupContext); + } + + /* Traverse the hash bucket chain to find a matching entry */ + FoundObject = SearchDirectory(CurrentDirectory, Name, CaseInsensitive, HashIndex, LookupContext); + if(FoundObject) + { + /* Match found, secure the object and its name info */ + OB::LifeCycle::ReferenceObjectNameInformation(CONTAIN_RECORD(FoundObject, OBJECT_HEADER, Body)); + OB::LifeCycle::ReferenceObject(FoundObject); + + /* Check if the directory is locked */ + if(!LookupContext->DirectoryLocked) + { + /* Drop the lock and restore standard kernel APC delivery */ + OB::Directory::ReleaseDirectoryLock(CurrentDirectory, LookupContext); + } + + /* Target resolved, break the loop */ + break; + } + + /* Check if the directory is locked */ + if(!LookupContext->DirectoryLocked) + { + /* Drop the lock and restore standard kernel APC delivery */ + OB::Directory::ReleaseDirectoryLock(CurrentDirectory, LookupContext); + } + + /* Check if fallback to the global shadow directory is possible */ + if(SearchGlobalDirectory && CurrentDirectory->DeviceMap != NULLPTR) + { + /* Resolve the shadow global devices directory in next iteration */ + CurrentDirectory = OB::DeviceMap::GetGlobalDevicesDirectory(CurrentDirectory); + } + else + { + /* Terminate the traversal loop */ + CurrentDirectory = NULLPTR; + } + } + } + + /* Check if the lookup context contains a previously resolved object */ + if(LookupContext->Object != NULLPTR) + { + /* Resolve the old object's name information header */ + PreviousNameInfo = OB::LifeCycle::GetObjectNameInformation(CONTAIN_RECORD(LookupContext->Object, + OBJECT_HEADER, + Body)); + + /* Release the references */ + OB::LifeCycle::DereferenceObjectNameInformation(PreviousNameInfo); + OB::LifeCycle::DereferenceObject(LookupContext->Object); + } + + /* Store the newly found object payload inside the caller's lookup context */ + LookupContext->Object = FoundObject; + + /* Return the object body */ + return FoundObject; +} + +/** + * Releases a previously acquired object directory lock. + * + * @param Directory + * Supplies a pointer to the object directory to unlock. + * + * @param LookupContext + * Supplies a pointer to the lookup context for state tracking. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Directory::ReleaseDirectoryLock(IN OUT POBJECT_DIRECTORY Directory, + IN OUT POBJECT_LOOKUP_CONTEXT LookupContext) +{ + /* Release the directory lock */ + KE::PushLock::ReleasePushLock(&Directory->Lock); + + /* Update the lock state */ + LookupContext->LockStateSignature = OBJECT_LOCK_STATE_RELEASED_SIGNATURE; + + /* Restore APC delivery */ + KE::KThread::LeaveCriticalRegion(); +} + +/** + * Releases all resources held within an Object Manager lookup context. + * + * @param LookupContext + * Supplies a pointer to the active lookup context to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Directory::ReleaseLookupContext(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext) +{ + /* Verify if a directory lock is held */ + if(LookupContext->DirectoryLocked) + { + /* Release the directory lock */ + ReleaseDirectoryLock(LookupContext->Directory, LookupContext); + + /* Update lookup context state */ + LookupContext->Directory = NULLPTR; + LookupContext->DirectoryLocked = FALSE; + } + + /* Release the object references held within a lookup context */ + ReleaseLookupContextObject(LookupContext); +} + +/** + * Releases the object reference held within a lookup context. + * + * @param LookupContext + * Supplies a pointer to the active lookup context containing the object to be released. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Directory::ReleaseLookupContextObject(IN OUT POBJECT_LOOKUP_CONTEXT LookupContext) +{ + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER ObjectHeader; + PVOID Object; + + /* Extract the cached object pointer from the lookup context */ + Object = LookupContext->Object; + if(Object) + { + /* Resolve the object header */ + ObjectHeader = CONTAIN_RECORD(Object, OBJECT_HEADER, Body); + + /* Retrieve the optional name information header */ + NameInfo = OB::LifeCycle::GetObjectNameInformation(ObjectHeader); + + /* Verify if the object has a registered name */ + if(NameInfo) + { + /* Drop the name query reference */ + OB::LifeCycle::DereferenceObjectNameInformation(NameInfo); + } + + /* Release the pointer reference */ + OB::LifeCycle::DereferenceObject(Object); + + /* Purge the pointer */ + LookupContext->Object = NULLPTR; + } +} + +/** + * Traverses an object directory hash bucket to find a matching entry. + * + * @param Directory + * Supplies a pointer to the object directory being searched. + * + * @param Name + * Supplies ap ointer to the target object name. + * + * @param CaseInsensitive + * Specifies whether the string comparison should ignore case. + * + * @param HashIndex + * Supplies the pre-computed hash bucket index used to locate the collision chain. + * + * @param LookupContext + * Supplies a pointer to the caller's lookup context. + * + * @return This routine returns a pointer to the resolved object body if found, or NULLPTR otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +PVOID +OB::Directory::SearchDirectory(IN POBJECT_DIRECTORY Directory, + IN PCUNICODE_STRING Name, + IN BOOLEAN CaseInsensitive, + IN ULONG HashIndex, + IN POBJECT_LOOKUP_CONTEXT LookupContext) +{ + POBJECT_DIRECTORY_ENTRY DirectoryEntry, *HeadDirectoryEntry, *LookupBucket; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_HEADER ObjectHeader; + + /* Resolve the head pointer of the target hash bucket chain */ + LookupBucket = (POBJECT_DIRECTORY_ENTRY*)&Directory->HashBuckets[HashIndex]; + + /* Iterate through the collision chain */ + HeadDirectoryEntry = LookupBucket; + while((DirectoryEntry = *HeadDirectoryEntry) != NULLPTR) + { + /* Resolve the underlying object header */ + ObjectHeader = CONTAIN_RECORD(DirectoryEntry->Object, OBJECT_HEADER, Body); + + /* Retrieve the optional name information header */ + NameInfo = OB::LifeCycle::GetObjectNameInformation(ObjectHeader); + + /* Check if the names match */ + if((Name->Length == NameInfo->Name.Length) && + RTL::Unicode::CompareString(Name, &NameInfo->Name, CaseInsensitive) == 0) + { + /* Check if it is already at the head of the bucket */ + if(HeadDirectoryEntry != LookupBucket) + { + /* Check if the directory is locked */ + if(LookupContext->DirectoryLocked || KE::PushLock::ConvertSharedPushLockToExclusive(&Directory->Lock)) + { + /* Relocate the entry to the front */ + *HeadDirectoryEntry = DirectoryEntry->ChainLink; + DirectoryEntry->ChainLink = *LookupBucket; + *LookupBucket = DirectoryEntry; + } + } + + /* Return the pointer to the object body */ + return DirectoryEntry->Object; + } + + /* Advance to the next node entry */ + HeadDirectoryEntry = &DirectoryEntry->ChainLink; + } + + /* Return NULL pointer*/ + return NULLPTR; +} diff --git a/xtoskrnl/ob/obmgr.cc b/xtoskrnl/ob/obmgr.cc new file mode 100644 index 0000000..9ff6720 --- /dev/null +++ b/xtoskrnl/ob/obmgr.cc @@ -0,0 +1,163 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/obmgr.cc + * DESCRIPTION: Object Manager + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Initializes an object attributes structure. + * + * @param ObjectAttributes + * Supplies a pointer to the object attributes structure to be initialized. + * + * @param ObjectName + * Supplies an optional pointer to a Unicode string representing the object name. + * + * @param Attributes + * Supplies a bitmask of flags controlling object behavior. + * + * @param Directory + * Supplies an optional handle to the root directory for relative path parsing. + * + * @param SecurityDescriptor + * Supplies an optional pointer to a security descriptor for the object. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +OB::Manager::InitializeObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING ObjectName, + IN ULONG Attributes, + IN HANDLE Directory, + IN PVOID SecurityDescriptor) +{ + /* Initialize the object attributes structure */ + ObjectAttributes->Attributes = Attributes; + ObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES); + ObjectAttributes->ObjectName = ObjectName; + ObjectAttributes->RootDirectory = Directory; + ObjectAttributes->SecurityDescriptor = SecurityDescriptor; + ObjectAttributes->SecurityQualityOfService = NULLPTR; +} + +/** + * Initializes the Object Manager subsystem. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::Manager::InitializeObjectManager(VOID) +{ + XTSTATUS Status; + + /* Zero out the static global lookaside structures */ + RTL::Memory::ZeroMemory(&CreateInfoList, sizeof(GENERAL_LOOKASIDE)); + RTL::Memory::ZeroMemory(&NameBufferList, sizeof(GENERAL_LOOKASIDE)); + + /* Initialize the system-wide global lookaside list for object create information structures */ + EX::LookasideList::InitializeLookasideList(&CreateInfoList, NonPagedPool, + sizeof(OBJECT_CREATE_INFORMATION), TAG_OB_CREATE_INFO, + 64, EX::LookasideList::GetSystemLookasideListHead()); + + /* Initialize the system-wide global lookaside list for object name buffers */ + EX::LookasideList::InitializeLookasideList(&NameBufferList, PagedPool, + OBJECT_NAME_BUFFER_SIZE, TAG_OB_NAME, + 32, EX::LookasideList::GetSystemLookasideListHead()); + + /* Initialize system lookaside list for BSP */ + InitializeSystemLookasideList(); + + /* Initialize handle table support */ + OB::HandleTable::InitializeHandleTable(); + + /* Initialize device map support */ + OB::DeviceMap::InitializeDeviceMap(); + + /* Initialize object life cycle support */ + OB::LifeCycle::InitializeObjectLifeCycle(); + + /* Initialize object type registry */ + Status = OB::TypeRegistry::InitializeObjectTypeRegistry(); + if(Status != STATUS_SUCCESS) + { + /* Initialization failed, return error code */ + return Status; + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Initializes the per-processor lookaside lists for the Object Manager. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::Manager::InitializeSystemLookasideList(VOID) +{ + PKPROCESSOR_CONTROL_BLOCK Prcb; + PGENERAL_LOOKASIDE LookasideList; + XTSTATUS Status; + + /* Retrieve the Processor Control Block */ + Prcb = KE::Processor::GetCurrentProcessorControlBlock(); + + /* Allocate a contiguous memory block for lookaside lists */ + Status = MM::Allocator::AllocatePool(NonPagedPool, sizeof(GENERAL_LOOKASIDE) * 2, + (PVOID*)&LookasideList, TAG_OB_CREATE_INFO); + + /* Wire the global pointer for create information structures */ + Prcb->LookasideList[LookasideCreateInfoList].Global = &CreateInfoList; + + /* Check if the contiguous allocation was successful */ + if(Status == STATUS_SUCCESS && LookasideList) + { + /* Map the pointer to the first half of the contiguous block */ + Prcb->LookasideList[LookasideCreateInfoList].Local = &LookasideList[0]; + + /* Initialize the local list */ + EX::LookasideList::InitializeLookasideList(&LookasideList[0], NonPagedPool, + sizeof(OBJECT_CREATE_INFORMATION), TAG_OB_CREATE_INFO, + 64, EX::LookasideList::GetSystemLookasideListHead()); + } + else + { + /* Allocation failed, use shared global list */ + Prcb->LookasideList[LookasideCreateInfoList].Local = &CreateInfoList; + } + + /* Wire the global pointer for object name buffers */ + Prcb->LookasideList[LookasideNameBufferList].Global = &NameBufferList; + + /* Check if the contiguous allocation was successful */ + if(Status == STATUS_SUCCESS && LookasideList) + { + /* Map the pointer to the second half of the contiguous block */ + Prcb->LookasideList[LookasideNameBufferList].Local = &LookasideList[1]; + + /* Initialize the local list */ + EX::LookasideList::InitializeLookasideList(&LookasideList[1], PagedPool, + OBJECT_NAME_BUFFER_SIZE, TAG_OB_NAME, + 32, EX::LookasideList::GetSystemLookasideListHead()); + } + else + { + /* Allocation failed, use shared global list */ + Prcb->LookasideList[LookasideNameBufferList].Local = &NameBufferList; + } +} diff --git a/xtoskrnl/ob/security.cc b/xtoskrnl/ob/security.cc new file mode 100644 index 0000000..8b13073 --- /dev/null +++ b/xtoskrnl/ob/security.cc @@ -0,0 +1,312 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/security.cc + * DESCRIPTION: Object Manager Security API + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Assigns a newly allocated security descriptor to an object. + * + * @param Object + * Supplies a pointer to the object being assigned a security descriptor. + * + * @param SecurityDescriptor + * Supplies a pointer to the security descriptor to be assigned. + * + * @param PoolType + * Supplies the type of pool memory used to allocate the security descriptor. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::Security::AssignObjectSecurityDescriptor(IN PVOID Object, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN MMPOOL_TYPE PoolType) +{ + UNIMPLEMENTED; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Audits object handles inherited by a new process. + * + * @param ObjectTableEntry + * Supplies a pointer to the specific handle table entry being enumerated. + * + * @param HandleId + * Supplies the runtime handle identifier associated with the entry. + * + * @param Context + * Supplies a pointer to the parent and child process contexts. + * + * @return This routine returns FALSE to ensure the enumeration continues across the entire handle table. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +OB::Security::AuditInheritedHandle(IN PHANDLE_TABLE_ENTRY ObjectTableEntry, + IN HANDLE HandleId, + IN PVOID Context) +{ + PSECURITY_PROCESS_AUDIT_INFO AuditInfo; + + /* Cast the enumeration parameter */ + AuditInfo = (PSECURITY_PROCESS_AUDIT_INFO)Context; + + /* Evaluate if the handle object is flagged for auditing */ + if(ObjectTableEntry->ObAttributes & OBJECT_AUDIT_OBJECT_CLOSE) + { + /* Handle duplication event */ + SE::Audit::AuditHandleDuplication(HandleId, + HandleId, + AuditInfo->ParentProcess, + AuditInfo->Process); + } + + /* Return FALSE to proceed to the next handle entry */ + return FALSE; +} + +/** + * Consumes the audit mask for a handle table entry and triggers a security audit alarm if the requested access + * rights match the audit requirements. + * + * @param Handle + * Supplies the handle being accessed. + * + * @param ObjectTableEntryInfo + * Supplies a pointer to the extended handle table entry information containing the volatile audit mask. + * + * @param ObjectTypeName + * Supplies a pointer to the Unicode string representing the object's type name. + * + * @param AccessMask + * Supplies the access mask requested by the caller to be evaluated against the audit mask. + * + * @return This routine does not return a value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::Security::AuditObjectAccess(IN HANDLE Handle, + IN PHANDLE_TABLE_ENTRY_INFO ObjectTableEntryInfo, + IN PUNICODE_STRING ObjectTypeName, + IN ACCESS_MASK AccessMask) +{ + ACCESS_MASK BitsToAudit, CurrentAuditMask, PreviousAuditMask, RemainingAuditMask; + + /* Enter a CAS loop */ + while(ObjectTableEntryInfo->AuditMask) + { + /* Capture the current state of the audit mask */ + CurrentAuditMask = ObjectTableEntryInfo->AuditMask; + + /* Mask out the access rights */ + RemainingAuditMask = CurrentAuditMask & ~AccessMask; + + /* Check if the requested access intersects with the audit mask */ + if(RemainingAuditMask == CurrentAuditMask) + { + /* No overlapping bits, return */ + return; + } + + /* Attempt to update the audit mask */ + PreviousAuditMask = (ACCESS_MASK)RTL::Atomic::CompareExchange32((VOLATILE PLONG)&ObjectTableEntryInfo->AuditMask, + (LONG)RemainingAuditMask, + (LONG)CurrentAuditMask); + + /* Verify if the update succeeded */ + if(PreviousAuditMask == CurrentAuditMask) + { + /* Extract the access bits */ + BitsToAudit = PreviousAuditMask & AccessMask; + + /* Check if there are active bits */ + if(BitsToAudit) + { + /* Dispatch the audit event */ + SE::Audit::OperationAuditAlarm(NULLPTR, Handle, ObjectTypeName, BitsToAudit, NULLPTR); + } + + /* Auditing completed, return */ + return; + } + } +} + +/** + * Deassigns and frees a security descriptor previously assigned to an object. + * + * @param SecurityDescriptor + * Supplies a pointer to a variable containing the security descriptor to be removed. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::Security::DeassignSecurity(IN OUT PSECURITY_DESCRIPTOR *SecurityDescriptor) +{ + UNIMPLEMENTED; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Provides the default security procedure for handling object security descriptors. + * + * @param Object + * Supplies a pointer to the object whose security descriptor is being processed. + * + * @param OperationCode + * Supplies the specific security operation to perform (e.g., Assign, Delete, Query, Set). + * + * @param SecurityInformation + * Supplies a bitmask indicating which specific components of the security descriptor are involved. + * + * @param SecurityDescriptor + * Supplies a pointer to a caller-allocated buffer. For a set/assign operation, this contains the new + * security data. For a query operation, it receives the requested data. + * + * @param Length + * Supplies a pointer to a variable that specifies the size of the SecurityDescriptor buffer. + * On return for a query operation, it receives the actual number of bytes required. + * + * @param OldSecurityDescriptor + * Supplies a pointer to a variable that holds the current security descriptor of the object. + * + * @param PoolType + * Supplies the type of memory pool to use if a new security descriptor must be allocated. + * + * @param GenericMapping + * Supplies a pointer to the generic access mapping associated with the object's type. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::Security::ProcessObjectSecurityDescriptor(IN PVOID Object, + IN SECURITY_OPERATION_CODE OperationCode, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG Length, + IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor, + IN MMPOOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping) +{ + /* Switch on the operation code */ + switch(OperationCode) + { + case AssignSecurityDescriptor: + AssignObjectSecurityDescriptor(Object, SecurityDescriptor, PoolType); + break; + case DeleteSecurityDescriptor: + return DeassignSecurity(OldSecurityDescriptor); + break; + case QuerySecurityDescriptor: + return QuerySecurityDescriptorInfo(Object, SecurityInformation, SecurityDescriptor, Length, OldSecurityDescriptor); + break; + case SetSecurityDescriptor: + return SetSecurityDescriptorInfo(Object, SecurityInformation, SecurityDescriptor, OldSecurityDescriptor, PoolType, GenericMapping); + break; + default: + KE::Crash::Panic(0x29, 0, STATUS_INVALID_PARAMETER, 0, 0); + break; + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Queries information from the security descriptor of an object. + * + * @param Object + * Supplies a pointer to the object whose security descriptor is being queried. + * + * @param SecurityInformation + * Supplies the type of security information being queried. + * + * @param SecurityDescriptor + * Supplies a pointer to the output buffer that receives the security descriptor. + * + * @param Length + * Supplies a pointer to a variable that specifies the length of the descriptor buffer. + * + * @param OldSecurityDescriptor + * Supplies a pointer to the original security descriptor of the object. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::Security::QuerySecurityDescriptorInfo(IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG Length, + IN PSECURITY_DESCRIPTOR *OldSecurityDescriptor) +{ + UNIMPLEMENTED; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Modifies the security descriptor information of an object. + * + * @param Object + * Supplies a pointer to the object whose security descriptor is being modified. + * + * @param SecurityInformation + * Supplies the type of security information to set. + * + * @param SecurityDescriptor + * Supplies a pointer to the new security descriptor information to apply. + * + * @param OldSecurityDescriptor + * Supplies a pointer to a variable that holds the current security descriptor of the object. + * + * @param PoolType + * Supplies the type of pool memory used for allocating the new security descriptor. + * + * @param GenericMapping + * Supplies a pointer to the generic mapping structure for the object type. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::Security::SetSecurityDescriptorInfo(IN PVOID Object, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor, + IN MMPOOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping) +{ + UNIMPLEMENTED; + + /* Return success */ + return STATUS_SUCCESS; +} diff --git a/xtoskrnl/ob/typereg.cc b/xtoskrnl/ob/typereg.cc new file mode 100644 index 0000000..ffe30d8 --- /dev/null +++ b/xtoskrnl/ob/typereg.cc @@ -0,0 +1,447 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ob/typereg.cc + * DESCRIPTION: Object Manager Type Registry + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Creates and initializes a new object type within the Object Manager namespace. + * + * @param TypeName + * Supplies the requested name of the new object type. + * + * @param Initializer + * Supplies the initialization parameters for the new object type. + * + * @param SecurityDescriptor + * Supplies an optional security descriptor. (Currently ignored). + * + * @param ObjectType + * Receives a pointer to the newly created object type. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::TypeRegistry::CreateObjectType(IN PUNICODE_STRING TypeName, + IN POBJECT_TYPE_INITIALIZER Initializer, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + OUT POBJECT_TYPE *ObjectType) +{ + POBJECT_HEADER_CREATOR_INFO CreatorInfo; + OBJECT_LOOKUP_CONTEXT LookupContext; + POBJECT_HEADER NewObjectTypeHeader; + POBJECT_TYPE NewObjectType; + UNICODE_STRING ObjectName; + XTSTATUS Status; + + /* Validate incoming parameters */ + Status = ValidateObjectTypeParameters(TypeName, Initializer); + if(Status != STATUS_SUCCESS) + { + /* Parameter validation failed, return error code */ + return Status; + } + + /* Initialize the lookup context */ + OB::Directory::InitializeLookupContext(&LookupContext); + + /* Check if the global type directory exists */ + if(ObjectTypeDirectory) + { + /* Acquire the directory lock and prepare for namespace lookup */ + OB::Directory::LockLookupContext(ObjectTypeDirectory, &LookupContext); + + /* Search the directory to check if an object type with this name already exists */ + if(OB::Directory::LookupDirectoryEntry(ObjectTypeDirectory, TypeName, OBJECT_CASE_INSENSITIVE, + FALSE, &LookupContext)) + { + /* A collision detected, release the directory lock and lookup context */ + OB::Directory::ReleaseLookupContext(&LookupContext); + + /* Reject the creation due to a naming conflict */ + return STATUS_OBJECT_NAME_COLLISION; + } + } + + /* Allocate paged memory for the persistent object type name */ + Status = MM::Allocator::AllocatePool(PagedPool, (ULONG)TypeName->MaximumLength, + (PVOID*)&ObjectName.Buffer, TAG_OB_NAME); + if(Status != STATUS_SUCCESS || ObjectName.Buffer == NULLPTR) + { + /* Pool allocation failed; release the lookup context and return error code */ + OB::Directory::ReleaseLookupContext(&LookupContext); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the requested type name */ + ObjectName.MaximumLength = TypeName->MaximumLength; + RTL::Unicode::CopyString(&ObjectName, TypeName); + + /* Allocate the physical memory block for the Object Type */ + Status = OB::LifeCycle::AllocateObject(NULLPTR, KernelMode, MasterObjectType, &ObjectName, + sizeof(OBJECT_TYPE), &NewObjectTypeHeader); + if(Status != STATUS_SUCCESS) + { + /* Object allocation failed; release the directory lock and free allocated name buffer */ + OB::Directory::ReleaseLookupContext(&LookupContext); + MM::Allocator::FreePool(ObjectName.Buffer); + + /* Return error code */ + return Status; + } + + /* Resolve the object body pointer and assign the captured name */ + NewObjectTypeHeader->Flags |= OBJECT_FLAG_KERNEL_MODE | OBJECT_FLAG_PERMANENT; + NewObjectType = (POBJECT_TYPE)&NewObjectTypeHeader->Body; + NewObjectType->Name = ObjectName; + + /* Zero out the statistics block */ + RTL::Memory::ZeroMemory(&NewObjectType->TotalNumberOfObjects, + FIELD_OFFSET(OBJECT_TYPE, TypeInfo) - FIELD_OFFSET(OBJECT_TYPE, TotalNumberOfObjects)); + + /* Check if master object type is already initialized */ + if(MasterObjectType == NULLPTR) + { + /* Set the global master type, link its header to itself, and set the default tag */ + MasterObjectType = NewObjectType; + NewObjectTypeHeader->Type = MasterObjectType; + NewObjectType->Key = TAG_OB_OBJECT_TYPE; + NewObjectType->TotalNumberOfObjects = 1; + } + else + { + /* Generate a clean tag from object name */ + NewObjectType->Key = GenerateObjectPoolTag(TypeName); + } + + /* Initialize default objects and pool charges */ + InitializeObjectType(NewObjectType, Initializer, &ObjectName); + + /* Suspend APCs and acquire exclusive access to the master type tracking list */ + KE::KThread::EnterCriticalRegion(); + KE::PushLock::AcquireExclusivePushLock(&MasterObjectType->TypeLock); + + /* Retrieve the creator information header */ + CreatorInfo = OB::LifeCycle::GetObjectCreatorInformation(NewObjectTypeHeader); + if(CreatorInfo != NULLPTR) + { + /* Link the new object type */ + RTL::LinkedList::InsertTailList(&MasterObjectType->TypeList, &CreatorInfo->TypeList); + + /* Prevent double-insertion during handle creation */ + NewObjectTypeHeader->Flags &= ~OBJECT_FLAG_CREATOR_INFO; + } + + /* Assign a type index */ + NewObjectType->Index = MasterObjectType->TotalNumberOfObjects; + if(NewObjectType->Index < OBJECT_MAX_DEFINED_OBJECT_TYPES) + { + /* Register the new type in the global table */ + ObjectTypesTable[NewObjectType->Index - 1] = NewObjectType; + } + + /* Release the master type lock and restore APC delivery */ + KE::PushLock::ReleaseExclusivePushLock(&MasterObjectType->TypeLock); + KE::KThread::LeaveCriticalRegion(); + + /* Publish into the namespace directory */ + if(ObjectTypeDirectory == NULLPTR || + OB::Directory::InsertDirectoryEntry(ObjectTypeDirectory, &LookupContext, NewObjectTypeHeader)) + { + /* Verify if the directory is present */ + if(ObjectTypeDirectory) + { + /* Increment the reference count */ + OB::LifeCycle::ReferenceObject(ObjectTypeDirectory); + } + + /* Release the directory lock and context */ + OB::Directory::ReleaseLookupContext(&LookupContext); + + /* Return the pointer to the object type */ + *ObjectType = NewObjectType; + return STATUS_SUCCESS; + } + else + { + /* Directory insertion failed, release lock and return error code */ + OB::Directory::ReleaseLookupContext(&LookupContext); + return STATUS_INSUFFICIENT_RESOURCES; + } +} + +/** + * Cleans up internal resources associated with an object type before its deletion. + * + * @param Object + * Supplies a pointer to the Object Type body being deleted. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::TypeRegistry::DeleteObjectType(IN PVOID Object) +{ + /* Nothing to do */ +} + +/** + * Generates a 4-byte pool tag based on the object type name. + * + * @param TypeName + * Supplies the name of the object type. + * + * @return This routine returns a 32-bit pool tag. + * + * @since XT 1.0 + */ +XTAPI +ULONG +OB::TypeRegistry::GenerateObjectPoolTag(IN PUNICODE_STRING TypeName) +{ + ULONG Index, Tag; + PUCHAR TagBytes; + + /* Default tag to four spaces */ + Tag = SIGNATURE32(' ', ' ', ' ', ' '); + TagBytes = (PUCHAR)&Tag; + + /* Extract up to the first 4 characters */ + for(Index = 0; Index < 4; Index++) + { + /* Verify if the current index falls within the valid bounds */ + if(Index < (TypeName->Length / sizeof(WCHAR))) + { + /* Strip the high unicode byte and store the resulting ASCII character */ + TagBytes[Index] = (UCHAR)(TypeName->Buffer[Index] & 0xFF); + } + } + + /* Return the tag */ + return Tag; +} + +/** + * Initializes the internal body and configuration of a newly allocated object type. + * + * @param ObjectType + * Supplies a pointer to the object type to initialize. + * + * @param Initializer + * Supplies the initialization parameters. + * + * @param TypeName + * Supplies the name of the object type. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +OB::TypeRegistry::InitializeObjectType(IN OUT POBJECT_TYPE ObjectType, + IN POBJECT_TYPE_INITIALIZER Initializer, + IN PUNICODE_STRING TypeName) +{ + ULONG HeaderCharge; + + /* Calculate standard header charges */ + HeaderCharge = sizeof(OBJECT_HEADER) + sizeof(OBJECT_HEADER_NAME_INFO); + + /* Verify if the object type requires handle count tracking */ + if(Initializer->MaintainHandleCount) + { + /* Include the size of the handle information header in the total charge */ + HeaderCharge += sizeof(OBJECT_HEADER_HANDLE_INFO); + } + + /* Copy initialization data */ + RTL::Memory::CopyMemory(&ObjectType->TypeInfo, Initializer, sizeof(OBJECT_TYPE_INITIALIZER)); + + /* Enforce global type list maintenance and configure the target pool type */ + ObjectType->TypeInfo.MaintainTypeList = TRUE; + ObjectType->TypeInfo.PoolType = Initializer->PoolType; + + /* Check pool type */ + if(Initializer->PoolType == NonPagedPool) + { + /* Apply the charge to the non-paged pool requirement */ + ObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderCharge; + } + else + { + /* Apply the charge to the paged pool requirement */ + ObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderCharge; + } + + /* Check if the caller supplied a custom procedure for security descriptor operations */ + if(Initializer->SecurityProcedure == NULLPTR) + { + /* No custom procedure provided, attach the generic system handler */ + ObjectType->TypeInfo.SecurityProcedure = OB::Security::ProcessObjectSecurityDescriptor; + } + + /* Initialize synchronization mechanisms */ + KE::PushLock::InitializePushLock(&ObjectType->TypeLock); + + /* Initialize the queue for registered callbacks and the tracking list */ + RTL::LinkedList::InitializeListHead(&ObjectType->CallbackList); + RTL::LinkedList::InitializeListHead(&ObjectType->TypeList); + + /* Check if the object type has a default object */ + if(ObjectType->TypeInfo.UseDefaultObject) + { + /* Map to the global default event and append the SYNCHRONIZE access right */ + ObjectType->DefaultObject = &DefaultEvent; + ObjectType->TypeInfo.ValidAccessMask |= SE_SYNCHRONIZE; + } + else if(TypeName->Length == 8 && !RTL::WideString::CompareWideString(TypeName->Buffer, L"File", 0)) + { + /* Point the synchronization offset directly to the internal Event field */ + ObjectType->DefaultObject = (PVOID)(ULONG_PTR)FIELD_OFFSET(FILE_OBJECT, Event); + } + else if(TypeName->Length == 24 && !RTL::WideString::CompareWideString(TypeName->Buffer, L"WaitablePort", 0)) + { + /* Point the synchronization offset directly to the WaitEvent field */ + ObjectType->DefaultObject = (PVOID)(ULONG_PTR)FIELD_OFFSET(LPCP_PORT_OBJECT, WaitEvent); + } + else + { + /* Disable synchronization for this object type */ + ObjectType->DefaultObject = NULLPTR; + } +} + +/** + * Initializes the global Object Type Registry and bootstraps the master type object. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::TypeRegistry::InitializeObjectTypeRegistry(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING TypeName; + XTSTATUS Status; + + /* Initialize the global directory pointer */ + ObjectTypeDirectory = NULLPTR; + + /* Clear the global object type lookup table and the default synchronization event block */ + RTL::Memory::ZeroMemory(ObjectTypesTable, sizeof(ObjectTypesTable)); + RTL::Memory::ZeroMemory(&DefaultEvent, sizeof(KEVENT)); + + /* Clear the initialization structure */ + RTL::Memory::ZeroMemory(&ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER)); + + /* Configure the attributes and pool charges for the master "Type" object */ + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE); + ObjectTypeInitializer.InvalidAttributes = OBJECT_OPENLINK; + ObjectTypeInitializer.Length = sizeof(OBJECT_TYPE_INITIALIZER); + ObjectTypeInitializer.MaintainTypeList = TRUE; + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.UseDefaultObject = TRUE; + ObjectTypeInitializer.ValidAccessMask = SE_OBJECT_TYPE_ALL_ACCESS; + + /* Register default destructor */ + ObjectTypeInitializer.DeleteProcedure = &DeleteObjectType; + + /* Initialize the descriptor for the "Type" name */ + RTL::Unicode::InitializeString(&TypeName, L"Type"); + + /* Create the master object type */ + Status = CreateObjectType(&TypeName, &ObjectTypeInitializer, NULLPTR, &MasterObjectType); + if(Status != STATUS_SUCCESS) + { + /* Object type creation failed, return error code */ + return STATUS_UNSUCCESSFUL; + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Validates the parameters supplied for creating a new object type. + * + * @param TypeName + * Supplies the requested name of the new object type. + * + * @param Initializer + * Supplies the initialization parameters for the new object type. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +OB::TypeRegistry::ValidateObjectTypeParameters(IN PUNICODE_STRING TypeName, + IN POBJECT_TYPE_INITIALIZER Initializer) +{ + ULONG Index; + PWCH Buffer; + + /* Check the basic string validity and alignment */ + if(TypeName == NULLPTR || TypeName->Length == 0 || (TypeName->Length % sizeof(WCHAR)) != 0) + { + /* Invalid type name, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Check initializer block integrity and allowed flags */ + if(Initializer == NULLPTR || + (Initializer->InvalidAttributes & ~OBJECT_VALID_ATTRIBUTES) != 0 || + Initializer->Length != sizeof(OBJECT_TYPE_INITIALIZER)) + { + /* Invalid initializer block, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Check the maintaining handle count and procedure presence */ + if(Initializer->MaintainHandleCount && + Initializer->OpenProcedure == NULLPTR && + Initializer->CloseProcedure == NULLPTR) + { + /* Invalid initializer block, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Validate memory pool type */ + if(!Initializer->UseDefaultObject && Initializer->PoolType != NonPagedPool) + { + /* Invalid pool type, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Extract the buffer pointer */ + Buffer = TypeName->Buffer; + Index = TypeName->Length / sizeof(WCHAR); + + /* Scan for illegal path separators in the type name */ + while(Index--) + { + /* Check for path separator */ + if(*Buffer++ == OBJECT_NAME_PATH_SEPARATOR) + { + /* Invalid type name, return error code */ + return STATUS_OBJECT_NAME_INVALID; + } + } + + /* Return success */ + return STATUS_SUCCESS; +} diff --git a/xtoskrnl/po/idle.cc b/xtoskrnl/po/idle.cc index 8f9aeba..a638640 100644 --- a/xtoskrnl/po/idle.cc +++ b/xtoskrnl/po/idle.cc @@ -28,7 +28,7 @@ PO::Idle::InitializeProcessorIdleState(IN OUT PKPROCESSOR_CONTROL_BLOCK Prcb) /* Initialize default power state */ Prcb->PowerState.Idle0TimeLimit = 0xFFFFFFFF; - Prcb->PowerState.CurrentThrottle = 100; + Prcb->PowerState.CurrentThrottle = POWER_PERFORMANCE_SCALE; Prcb->PowerState.CurrentThrottleIndex = 0; Prcb->PowerState.IdleFunction = Idle0Function; diff --git a/xtoskrnl/ps/data.cc b/xtoskrnl/ps/data.cc new file mode 100644 index 0000000..637f00b --- /dev/null +++ b/xtoskrnl/ps/data.cc @@ -0,0 +1,31 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/po/data.cc + * DESCRIPTION: Process global and static data + * DEVELOPERS: Aiken Harris + */ + +#include + + +/* Pointer to the IDLE process object */ +PEPROCESS PS::Process::IdleProcess; + +/* Pointer to the system process object */ +PEPROCESS PS::Process::SystemProcess; + +/* Global handle to the root system process */ +HANDLE PS::Process::SystemProcessHandle; + +/* Global object type descriptor for Process objects */ +POBJECT_TYPE PS::ProcessManager::ProcessType; + +/* Global object type descriptor for Thread objects */ +POBJECT_TYPE PS::ProcessManager::ThreadType; + +/* Default system-wide quota block assigned to processes */ +EPROCESS_QUOTA_BLOCK PS::Quota::DefaultQuotaBlock; + +/* Lock used for quota management */ +KSPIN_LOCK PS::Quota::QuotaLock; diff --git a/xtoskrnl/ps/process.cc b/xtoskrnl/ps/process.cc new file mode 100644 index 0000000..9084b4c --- /dev/null +++ b/xtoskrnl/ps/process.cc @@ -0,0 +1,261 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/po/process.cc + * DESCRIPTION: Process Management + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Creates the global IDLE process. + * + * @param Prcb + * Supplies a pointer to the Processor Control Block of the Bootstrap Processor. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +PS::Process::CreateIdleProcess(IN PKPROCESSOR_CONTROL_BLOCK Prcb) +{ + ULONG_PTR PageDirectory[2]; + PKPROCESS IdleProcess; + PKTHREAD IdleThread; + XTSTATUS Status; + + /* Get initial IDLE thread */ + IdleThread = Prcb->CurrentThread; + + /* Get initial IDLE process */ + IdleProcess = IdleThread->ApcState.Process; + + /* Setup placeholder for page directory entries */ + PageDirectory[0] = 0; + PageDirectory[1] = 0; + + /* Initialize IDLE process */ + Status = KE::KProcess::InitializeIdleProcess(IdleProcess, PageDirectory); + if(Status != STATUS_SUCCESS) + { + /* Failed to initialize IDLE process, return status code */ + return Status; + } + + /* Initialize IDLE thread */ + return KE::KThread::InitializeIdleThread(IdleProcess, IdleThread, Prcb, AR::ProcessorSupport::GetBootStack()); +} + +/** + * Creates and initializes the primary system process. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +PS::Process::CreateInitialSystemProcess(VOID) +{ + OBJECT_ATTRIBUTES Attributes; + XTSTATUS Status; + + /* Initialize process object attributes */ + OB::Manager::InitializeObjectAttributes(&Attributes, NULLPTR, 0, NULLPTR, NULLPTR); + + /* Spawn the root system process */ + Status = CreateKernelProcess(&SystemProcessHandle, SE_PROCESS_ALL_ACCESS, &Attributes, + NULLPTR, 0, NULLPTR, NULLPTR, NULLPTR, FALSE); + if(Status != STATUS_SUCCESS) + { + /* Process creation failed, return error code */ + return Status; + } + + /* Reference the process handle for a persistent kernel object pointer */ + Status = OB::LifeCycle::ReferenceObject(SystemProcessHandle, 0L, PS::ProcessManager::GetProcessType(), + KernelMode, (PVOID *)&SystemProcess, NULLPTR); + if(Status != STATUS_SUCCESS) + { + /* Handle reference failed, return error code */ + return Status; + } + + /* Set the diagnostic image file name */ + RTL::String::CopyString(&SystemProcess->ImageFileName[0], "System", 6); + + /* Allocate memory for the process creation audit information */ + Status = MM::Allocator::AllocatePool(PagedPool, sizeof(OBJECT_NAME_INFORMATION), + (PVOID *)&SystemProcess->AuditProcessCreationInfo.ImageFileName, + TAG_SE_PRIVILEGE_ARRAY); + if(Status != STATUS_SUCCESS || !SystemProcess->AuditProcessCreationInfo.ImageFileName) + { + /* Memory allocation failed, return error code */ + return Status; + } + + /* Zero the allocated audit information */ + RtlZeroMemory(SystemProcess->AuditProcessCreationInfo.ImageFileName, sizeof(OBJECT_NAME_INFORMATION)); + + /* Return success */ + return STATUS_SUCCESS; +} + + +/** + * Creates, configures, and publishes a new kernel process object. + * + * @param ProcessHandle + * Receives the handle to the newly created process. + * + * @param AccessMask + * Supplies the desired access rights to be granted. + * + * @param Attributes + * Supplies an optional pointer to the object attributes for process namespace insertion. + * + * @param ParentProcess + * Supplies an optional handle to the parent process. + * + * @param Flags + * Supplies process creation behavioral flags. + * + * @param SectionHandle + * Supplies an optional handle to the backed file mapping section. + * + * @param DebugPort + * Supplies an optional handle to the debugging registration port. + * + * @param ExceptionPort + * Supplies an optional handle to the IPC exception port. + * + * @param JobMember + * Specifies if the process is part of a job hierarchy. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +PS::Process::CreateKernelProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK AccessMask, + IN POBJECT_ATTRIBUTES Attributes, + IN HANDLE ParentProcess, + IN ULONG Flags, + IN HANDLE SectionHandle, + IN HANDLE DebugPort, + IN HANDLE ExceptionPort, + IN BOOLEAN JobMember) +{ + UNIMPLEMENTED; + + /* Not implemented */ + return STATUS_NOT_IMPLEMENTED; +} + +/** + * Creates a new process as a child of the main system process. + * + * @param ProcessHandle + * Receives the handle to the newly created process. + * + * @param AccessMask + * Supplies the desired access rights to be granted. + * + * @param Attributes + * Supplies an optional pointer to the object attributes for process namespace insertion. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +PS::Process::CreateSystemProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK AccessMask, + IN POBJECT_ATTRIBUTES Attributes) +{ + /* Create new process */ + return CreateKernelProcess(ProcessHandle, AccessMask, Attributes, SystemProcessHandle, + 0, NULLPTR, NULLPTR, NULLPTR, FALSE); +} + +/** + * Deletes a Process object when the final reference is released. + * + * @param ProcessObject + * Supplies a pointer to the terminating process object. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +PS::Process::DeleteProcess(IN PVOID ProcessObject) +{ + UNIMPLEMENTED; +} + +/** + * Returns a pointer to the process object associated with the currently executing thread. + * + * @return This routine returns a pointer to the current process object. + * + * @since XT 1.0 + */ +XTFASTCALL +PEPROCESS +PS::Process::GetCurrentProcess(VOID) +{ + /* Return the current process */ + return (PEPROCESS)KE::Processor::GetCurrentThread()->ApcState.Process; +} + +/** + * Returns a pointer to the primary system process object. + * + * @return This routine returns a pointer to the system process object. + * + * @since XT 1.0 + */ +XTFASTCALL +PEPROCESS +PS::Process::GetSystemProcess(VOID) +{ + /* Return the system process */ + return SystemProcess; +} + +/** + * Initializes the system idle process. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +PS::Process::InitializeIdleProcess(VOID) +{ + /* Bind the currently executing bootstrap process as the system idle process */ + IdleProcess = GetCurrentProcess(); + + /* Initialize the process lock and rundown protection */ + KE::PushLock::InitializePushLock(&IdleProcess->ProcessLock); + EX::Rundown::InitializeProtection(&IdleProcess->RundownProtect); + + /* Prepare the process thread tracking list */ + RTL::LinkedList::InitializeListHead(&IdleProcess->ThreadListHead); + + /* Set the diagnostic image file name */ + RTL::String::CopyString(&IdleProcess->ImageFileName[0], "Idle", 4); + + /* Reset the accounting metric */ + IdleProcess->ProcessControlBlock.KernelTime = 0; +} diff --git a/xtoskrnl/ps/psmgr.cc b/xtoskrnl/ps/psmgr.cc new file mode 100644 index 0000000..587dfda --- /dev/null +++ b/xtoskrnl/ps/psmgr.cc @@ -0,0 +1,89 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ps/psmgr.cc + * DESCRIPTION: Process Manager + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Retrieves the global object type descriptor for Process objects. + * + * @return This routine returns a pointer to the process object type structure. + * + * @since XT 1.0 + */ +XTFASTCALL +POBJECT_TYPE +PS::ProcessManager::GetProcessType(VOID) +{ + /* Return the process object type descriptor */ + return ProcessType; +} + +/** + * Retrieves the global object type descriptor for Thread objects. + * + * @return This routine returns a pointer to the thread object type structure. + * + * @since XT 1.0 + */ +XTFASTCALL +POBJECT_TYPE +PS::ProcessManager::GetThreadType(VOID) +{ + /* Return the thread object type descriptor */ + return ThreadType; +} + +/** + * Initializes the Process Manager subsystem. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +PS::ProcessManager::InitializeProcessManager(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING ObjectTypeName; + + /* Clear the object type initializer */ + RTL::Memory::ZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); + + /* Initialize common attributes */ + ObjectTypeInitializer.InvalidAttributes = OBJECT_EXCLUSIVE | OBJECT_OPENIF | OBJECT_PERMANENT; + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.SecurityRequired = TRUE; + + /* Initialize the Process object type */ + RTL::Unicode::InitializeString(&ObjectTypeName, L"Process"); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EPROCESS); + ObjectTypeInitializer.DeleteProcedure = PS::Process::DeleteProcess; + ObjectTypeInitializer.GenericMapping = PS_PROCESS_GENERIC_MAPPING; + ObjectTypeInitializer.ValidAccessMask = SE_PROCESS_ALL_ACCESS; + OB::TypeRegistry::CreateObjectType(&ObjectTypeName, &ObjectTypeInitializer, NULLPTR, &ProcessType); + + /* Initialize the Thread object type */ + RTL::Unicode::InitializeString(&ObjectTypeName, L"Thread"); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ETHREAD); + ObjectTypeInitializer.DeleteProcedure = PS::Thread::DeleteThread; + ObjectTypeInitializer.GenericMapping = PS_THREAD_GENERIC_MAPPING; + ObjectTypeInitializer.ValidAccessMask = SE_THREAD_ALL_ACCESS; + OB::TypeRegistry::CreateObjectType(&ObjectTypeName, &ObjectTypeInitializer, NULLPTR, &ThreadType); + + /* Initialize system quota */ + PS::Quota::InitializeQuota(); + + /* Create system process */ + PS::Process::CreateInitialSystemProcess(); + + /* Initialize IDLE process */ + PS::Process::InitializeIdleProcess(); +} diff --git a/xtoskrnl/ps/quota.cc b/xtoskrnl/ps/quota.cc new file mode 100644 index 0000000..c250b7d --- /dev/null +++ b/xtoskrnl/ps/quota.cc @@ -0,0 +1,486 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/po/quota.cc + * DESCRIPTION: Process Quota Management + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Charges a specified amount of quota against a given process quota block. + * + * @param QuotaBlock + * Supplies a pointer to the quota block from which the charge is being requested. + * + * @param Process + * Supplies an optional pointer to the process object associated with the charge. + * + * @param QuotaType + * Supplies the specific type of quota being charged. + * + * @param Amount + * Supplies the exact size, in bytes, of the quota charge. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +PS::Quota::ChargeProcessQuota(IN PEPROCESS_QUOTA_BLOCK QuotaBlock, + IN PEPROCESS Process, + IN PS_QUOTA_TYPE QuotaType, + IN SIZE_T Amount) +{ + SIZE_T CurrentLimit, CurrentUsage, NewUsage, ObservedUsage, RecoveredQuota; + PEPROCESS_QUOTA_ENTRY QuotaEntry; + + /* Check if the system process is being charged */ + if(Process == PS::Process::GetSystemProcess()) + { + /* Bypass quota enforcement for the initial system process, return success */ + return STATUS_SUCCESS; + } + + /* Resolve the quota entry */ + QuotaEntry = &QuotaBlock->QuotaEntry[QuotaType]; + CurrentUsage = QuotaEntry->Usage; + + /* Memory barrier */ + AR::CpuFunctions::MemoryBarrier(); + + /* Snapshot the current limit */ + CurrentLimit = QuotaEntry->Limit; + + /* Enter the lock-free contention loop */ + while(TRUE) + { + /* Calculate the projected usage */ + NewUsage = CurrentUsage + Amount; + + /* Check if an integer overflow occurs */ + if(NewUsage < CurrentUsage) + { + /* Reject the charge, return error code */ + return STATUS_QUOTA_EXCEEDED; + } + + /* Check if the projected usage is within the known limit */ + if(NewUsage <= CurrentLimit) + { + /* Attempt to commit the new usage value */ + ObservedUsage = RTL::Atomic::CompareExchange64((PLONG_PTR)&QuotaEntry->Usage, NewUsage, CurrentUsage); + if(ObservedUsage == CurrentUsage) + { + /* Successfully acquired quota, update the peak usage */ + UpdatePeakUsage(&QuotaEntry->Peak, NewUsage); + + /* Check if a process context was provided */ + if(Process) + { + /* Add the amount to the process's usage tracker */ + NewUsage = RTL::Atomic::Add64((PLONG_PTR)&Process->QuotaUsage[QuotaType], Amount); + + /* Update the per-process peak usage */ + UpdatePeakUsage(&Process->QuotaPeak[QuotaType], NewUsage); + } + + /* Quota charge completed, return success */ + return STATUS_SUCCESS; + } + + /* Refresh the snapshot */ + CurrentUsage = ObservedUsage; + + /* Memory barrier */ + AR::CpuFunctions::MemoryBarrier(); + + /* Refresh the limit snapshot */ + CurrentLimit = QuotaEntry->Limit; + continue; + } + + /* Check if this is a pagefile quota */ + if(QuotaType == PsPageFile) + { + /* Pagefile quota cannot be expanded, return error code */ + return STATUS_PAGEFILE_QUOTA_EXCEEDED; + } + + /* Attempt to reclaim quota that was returned but not yet merged */ + RecoveredQuota = RTL::Atomic::Exchange64((PLONG_PTR)&QuotaEntry->Return, 0); + if(RecoveredQuota > 0) + { + /* Reclaim successful, add the recovered amount and retry */ + CurrentLimit = RTL::Atomic::Add64((PLONG_PTR)&QuotaEntry->Limit, RecoveredQuota); + continue; + } + + /* Reclaim failed, attempt to expand the quota limit */ + if(MM::Quota::RaisePoolQuota((MMPOOL_TYPE)QuotaType, CurrentLimit, &CurrentLimit)) + { + /* Expansion successful, update the limit and retry */ + RTL::Atomic::Exchange64((PLONG_PTR)&QuotaEntry->Limit, CurrentLimit); + continue; + } + + /* Quota charge failed, return error code */ + return STATUS_QUOTA_EXCEEDED; + } +} + +/** + * Charges specified amounts of paged and non-paged pool quotas against a given process quota block. + * + * @param Process + * Supplies a pointer to the target process whose quota block will be charged. + * + * @param PagedAmount + * Supplies the amount of paged pool quota to charge, in bytes. + * + * @param NonPagedAmount + * Supplies the amount of non-paged pool quota to charge, in bytes. + * + * @return This routine returns a pointer to the charged quota block, or NULLPTR if either of the pool limits is exceeded. + * + * @since XT 1.0 + */ +XTAPI +PEPROCESS_QUOTA_BLOCK +PS::Quota::ChargeSharedPoolQuota(IN PEPROCESS Process, + IN SIZE_T PagedAmount, + IN SIZE_T NonPagedAmount) +{ + XTSTATUS Status; + + /* Check if the system process is being charged */ + if(Process == PS::Process::GetSystemProcess()) + { + /* Return the pseudo-marker allowing allocations without tracking */ + return PS_QUOTA_BYPASS_MARKER; + } + + /* Check if a non-paged pool charge is required */ + if(NonPagedAmount) + { + /* Attempt to charge the requested non-paged pool amount */ + Status = ChargeProcessQuota(Process->QuotaBlock, NULLPTR, PsNonPagedPool, NonPagedAmount); + if(Status != STATUS_SUCCESS) + { + /* Non-paged pool charge failed, return NULL pointer */ + return NULLPTR; + } + } + + /* Check if a paged pool charge is required */ + if(PagedAmount) + { + /* Attempt to charge the requested paged pool amount */ + Status = ChargeProcessQuota(Process->QuotaBlock, NULLPTR, PsPagedPool, PagedAmount); + if(Status != STATUS_SUCCESS) + { + /* Paged pool charge failed, rollback the non-paged pool quota and return NULL pointer */ + PS::Quota::ReturnProcessQuota(Process->QuotaBlock, NULLPTR, PsNonPagedPool, NonPagedAmount); + return NULLPTR; + } + } + + /* Increment the reference count of the quota block */ + RTL::Atomic::Increment32((VOLATILE PLONG)&Process->QuotaBlock->ReferenceCount); + + /* Return the charged quota block */ + return Process->QuotaBlock; +} + +/** + * Decrements the reference count of a quota block and destroys it if it reaches zero. + * + * @param QuotaBlock + * Supplies a pointer to the process quota block to dereference. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +PS::Quota::DereferenceQuotaBlock(IN PEPROCESS_QUOTA_BLOCK QuotaBlock) +{ + SIZE_T ReturnAmount; + ULONG Index; + + /* Guard against null pointer and the bypass marker */ + if(QuotaBlock == NULLPTR || QuotaBlock == PS_QUOTA_BYPASS_MARKER) + { + /* No cleanup is required, return */ + return; + } + + /* Decrement the reference count */ + if(RTL::Atomic::Decrement32((VOLATILE PLONG)&QuotaBlock->ReferenceCount) == 0) + { + /* Start a guarded code block */ + { + /* Raise runlevel to DISPATCH level */ + KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL); + + /* Iterate through all available pool quota types */ + for(Index = PsNonPagedPool; Index <= PsPagedPool; Index++) + { + /* Calculate the total residual quota */ + ReturnAmount = QuotaBlock->QuotaEntry[Index].Return + QuotaBlock->QuotaEntry[Index].Limit; + + /* Check if there is any residual quota left */ + if(ReturnAmount > 0) + { + /* Return the residual quota */ + MM::Quota::ReturnPoolQuota((MMPOOL_TYPE)Index, ReturnAmount); + } + } + + /* Acquire a quota lock */ + KE::SpinLockGuard SpinLock(&QuotaLock); + + /* Unlink the quota block from the global tracking list */ + RTL::LinkedList::RemoveEntryList(&QuotaBlock->QuotaList); + } + + /* Free the physical memory */ + MM::Allocator::FreePool(QuotaBlock, TAG_PS_QUOTA_BLOCK); + } +} + +/** + * Initializes the system-wide process quota subsystem. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +VOID +XTAPI +PS::Quota::InitializeQuota(VOID) +{ + /* Initialize the quota lock */ + KE::SpinLock::InitializeSpinLock(&QuotaLock); + + /* Clear the default quota block */ + RtlZeroMemory(&DefaultQuotaBlock, sizeof(DefaultQuotaBlock)); + + /* Set up the counters */ + DefaultQuotaBlock.ProcessCount = 1; + DefaultQuotaBlock.ReferenceCount = 1; + + /* Set up the limits */ + DefaultQuotaBlock.QuotaEntry[PsNonPagedPool].Limit = (SIZE_T)-1; + DefaultQuotaBlock.QuotaEntry[PsPagedPool].Limit = (SIZE_T)-1; + DefaultQuotaBlock.QuotaEntry[PsPageFile].Limit = (SIZE_T)-1; + + /* Assign the default quota block to the current process */ + PS::Process::GetCurrentProcess()->QuotaBlock = &DefaultQuotaBlock; +} + +/** + * Returns a specified amount of quota to a quota block and updates process usage. + * + * @param QuotaBlock + * Supplies the quota block receiving the returned quota. + * + * @param Process + * Supplies an optional pointer to the process whose usage is being reduced. + * + * @param QuotaType + * Supplies the type of quota being returned. + * + * @param Amount + * Supplies the amount of quota to return. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +PS::Quota::ReturnProcessQuota(IN PEPROCESS_QUOTA_BLOCK QuotaBlock, + IN PEPROCESS Process, + IN PS_QUOTA_TYPE QuotaType, + IN SIZE_T Amount) +{ + SIZE_T AccumulatedGiveBack, ExtractedReturnAmount, GiveBackAmount, GiveBackLimit, MinGiveBackThreshold; + SIZE_T CurrentLimit, CurrentUsage, ExpectedLimit, NewLimit; + PEPROCESS_QUOTA_ENTRY QuotaEntry; + + /* Initialize local pointers and fetch the current usage for the specified quota type */ + QuotaEntry = &QuotaBlock->QuotaEntry[QuotaType]; + CurrentUsage = QuotaEntry->Usage; + + /* Check if process provided */ + if(Process != NULLPTR) + { + /* Check if this is the system process */ + if(Process == PS::Process::GetSystemProcess()) + { + /* Do not do anything for system processes, return */ + return; + } + else if(Process->QuotaUsage[QuotaType] < Amount || CurrentUsage < Amount) + { + /* Quota underflow detected, raise kernel panic */ + KE::Crash::Panic(0x21, + (ULONG_PTR)Process, + (ULONG_PTR)QuotaType, + Process ? (ULONG_PTR)Process->QuotaUsage[QuotaType] : (ULONG_PTR)CurrentUsage, + (ULONG_PTR)Amount); + } + } + + /* Determine the thresholds for returning excess quota limit */ + CurrentLimit = QuotaEntry->Limit; + MinGiveBackThreshold = (MMPAGED_QUOTA_INCREASE > MMNONPAGED_QUOTA_INCREASE) ? MMNONPAGED_QUOTA_INCREASE + : MMPAGED_QUOTA_INCREASE; + + /* Check if the current limit exceeds usage by at least the minimum giveback threshold */ + if((CurrentLimit > CurrentUsage) && ((CurrentLimit - CurrentUsage) > MinGiveBackThreshold)) + { + /* Only proceed if this is a pool quota */ + if(QuotaType != PsPageFile && QuotaBlock != &DefaultQuotaBlock) + { + /* Calculate the exact amount of limit to trim based on pool type block size */ + GiveBackLimit = (QuotaType == PsPagedPool) ? MMPAGED_QUOTA_INCREASE : MMNONPAGED_QUOTA_INCREASE; + GiveBackAmount = (GiveBackLimit > Amount) ? Amount : GiveBackLimit; + + /* Attempt a lock-free update to shrink the quota limit */ + NewLimit = CurrentLimit - GiveBackAmount; + ExpectedLimit = (SIZE_T)RTL::Atomic::CompareExchange64((PLONG_PTR)&QuotaEntry->Limit, (LONG_PTR)NewLimit, + (LONG_PTR)CurrentLimit); + + /* Check if the atomic limit update succeeded */ + if(ExpectedLimit == CurrentLimit) + { + /* Add to the return counter */ + AccumulatedGiveBack = RTL::Atomic::Add64((PLONG_PTR)&QuotaEntry->Return, GiveBackAmount); + + /* Check if the accumulated returns exceed the threshold */ + if(AccumulatedGiveBack > GiveBackLimit) + { + /* Extract the accumulated return amount and reset the counter to zero */ + ExtractedReturnAmount = (SIZE_T)RTL::Atomic::Exchange64((PLONG_PTR)&QuotaEntry->Return, (LONG_PTR)0); + + /* Check if there is anything to return */ + if(ExtractedReturnAmount > 0) + { + /* Return the extracted quota back to the system pool */ + MM::Quota::ReturnPoolQuota((MMPOOL_TYPE)QuotaType, ExtractedReturnAmount); + } + } + } + } + } + + /* Decrease the block's overall usage count */ + RTL::Atomic::Add64((PLONG_PTR)&QuotaEntry->Usage, (SIZE_T)(-(SSIZE_T)Amount)); + + /* Check if a specific process was provided */ + if(Process) + { + /* Decrease the process's specific usage count */ + RTL::Atomic::Add64((PLONG_PTR)&Process->QuotaUsage[QuotaType], (SIZE_T)(-(SSIZE_T)Amount)); + } +} + +/** + * Returns previously charged pool amounts back to a shared quota block. + * + * @param QuotaBlock + * Supplies a pointer to the process quota block. + * + * @param PagedAmount + * Supplies the amount of paged pool quota to return, in bytes. + * + * @param NonPagedAmount + * Supplies the amount of non-paged pool quota to return, in bytes. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +PS::Quota::ReturnSharedPoolQuota(IN PEPROCESS_QUOTA_BLOCK QuotaBlock, + IN SIZE_T PagedAmount, + IN SIZE_T NonPagedAmount) +{ + /* Check for NULL pointers and bypass markers */ + if(!QuotaBlock || QuotaBlock == PS_QUOTA_BYPASS_MARKER) + { + /* No quota tracking is required for the system process or empty blocks, return */ + return; + } + + /* Check for paged pool quota */ + if(PagedAmount > 0) + { + /* Process the return of paged pool memory */ + ReturnProcessQuota(QuotaBlock, NULLPTR, PsPagedPool, PagedAmount); + } + + /* Check for non-paged pool quota */ + if(NonPagedAmount > 0) + { + /* Process the return of non-paged pool memory */ + ReturnProcessQuota(QuotaBlock, NULLPTR, PsNonPagedPool, NonPagedAmount); + } + + /* Drop the reference count on the quota block */ + DereferenceQuotaBlock(QuotaBlock); +} + +/** + * Updates a quota size tracker to a new peak maximum. + * + * @param TargetQuota + * Supplies a pointer to the variable tracking the peak usage. + * + * @param NewQuota + * Supplies the newly calculated usage to be evaluated against the peak. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTINLINE +VOID +PS::Quota::UpdatePeakUsage(IN PSIZE_T TargetQuota, + IN SIZE_T NewQuota) +{ + SIZE_T CurrentQuota; + SIZE_T ObservedQuota; + + /* Snapshot the initial memory value */ + CurrentQuota = *TargetQuota; + + /* Enter the CAS loop */ + while(TRUE) + { + /* Check if the proposed quota does not exceed the current peak */ + if(NewQuota <= CurrentQuota) + { + /* Nothing to update, break the loop */ + break; + } + + /* Attempt to overwrite the peak usage */ + ObservedQuota = RTL::Atomic::CompareExchange64((PLONG_PTR)TargetQuota, NewQuota, CurrentQuota); + if(ObservedQuota == CurrentQuota) + { + /* The peak successfully updated, break the loop */ + break; + } + + /* Update the snapshot and retry */ + CurrentQuota = ObservedQuota; + } +} diff --git a/xtoskrnl/ps/thread.cc b/xtoskrnl/ps/thread.cc new file mode 100644 index 0000000..2d93b52 --- /dev/null +++ b/xtoskrnl/ps/thread.cc @@ -0,0 +1,95 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/po/thread.cc + * DESCRIPTION: Thread Management + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Allocates and initializes a per-processor IDLE thread for an Application Processor (AP). + * + * @param Prcb + * Supplies a pointer to the Processor Control Block of the target processor. + * + * @param Stack + * Supplies a pointer to the pre-allocated kernel stack for the new idle thread. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +PS::Thread::CreateIdleThread(IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PVOID Stack) +{ + PKPROCESS IdleProcess; + PETHREAD IdleThread; + XTSTATUS Status; + + /* Retrieve the global IDLE process container */ + IdleProcess = KE::KProcess::GetIdleProcess(); + + /* Allocate the Executive Thread object */ + Status = MM::Allocator::AllocatePool(NonPagedPool, sizeof(ETHREAD), (PVOID*)&IdleThread); + if(Status != STATUS_SUCCESS) + { + /* Memory allocation failed, return the status code */ + return Status; + } + + /* Zero the allocated memory to prevent uninitialized data */ + RTL::Memory::ZeroMemory(IdleThread, sizeof(ETHREAD)); + + /* Register the new thread within the Processor Control Block */ + Prcb->CurrentThread = &IdleThread->ThreadControlBlock; + Prcb->IdleThread = &IdleThread->ThreadControlBlock; + + /* Initialize the IDLE thread */ + Status = KE::KThread::InitializeIdleThread(IdleProcess, &IdleThread->ThreadControlBlock, Prcb, Stack); + if(Status != STATUS_SUCCESS) + { + /* Failed to initialize the IDLE thread state, free the ETHREAD object and return the status code */ + MM::Allocator::FreePool((PVOID)IdleThread); + return Status; + } + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Deletes a Thread object when the final reference is released. + * + * @param ThreadObject + * Supplies a pointer to the terminating thread object. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +PS::Thread::DeleteThread(IN PVOID ThreadObject) +{ + UNIMPLEMENTED; +} + +/** + * Retrieves a pointer to the currently executing executive thread object. + * + * @return This routine returns the address of the current executive thread object. + * + * @since XT 1.0 + */ +XTAPI +PETHREAD +PS::Thread::GetCurrentThread(VOID) +{ + /* Retrieve the active kernel thread and cast it to the executive thread */ + return (PETHREAD)KE::Processor::GetCurrentThread(); +} diff --git a/xtoskrnl/rtl/amd64/atomic.cc b/xtoskrnl/rtl/amd64/atomic.cc new file mode 100644 index 0000000..9fc6fa5 --- /dev/null +++ b/xtoskrnl/rtl/amd64/atomic.cc @@ -0,0 +1,190 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/amd64/atomic.cc + * DESCRIPTION: Atomic operations support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Removes all entries from single linked list. + * + * @param Header + * Supplies a pointer to the header of linked list. + * + * @return This routine returns a pointer to the original list, or NULLPTR if the list was already empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::Atomic::FlushSingleList(IN PSINGLE_LIST_HEADER ListHead) +{ + ULONGLONG ExpectedValue, NewValue, ResultValue; + PSINGLE_LIST_ENTRY FirstEntry; + + /* Load the initial state of the header */ + ExpectedValue = *(VOLATILE PULONGLONG)&ListHead->Alignment; + + /* Enter the CAS loop */ + while(TRUE) + { + /* Extract the entry address */ + FirstEntry = (PSINGLE_LIST_ENTRY)((LONGLONG)ExpectedValue >> 21 ); + + /* Check if list is empty */ + if(FirstEntry == NULLPTR) + { + /* Return NULLPTR */ + return NULLPTR; + } + + /* Zero out both the compressed pointer and the Depth */ + NewValue = ExpectedValue & 0x01FF0000ULL; + + /* Perform the compare and swap operation */ + ResultValue = CompareExchange64((VOLATILE PLONG_PTR)&ListHead->Alignment, + (LONG_PTR)ExpectedValue, + (LONG_PTR)NewValue); + + /* Evaluate the CAS result */ + if(ResultValue == ExpectedValue) + { + /* Swap succeeded, return the original first entry */ + return FirstEntry; + } + + /* Collision detected, retry */ + ExpectedValue = ResultValue; + } +} + +/** + * Removes and returns the first entry from single linked list. + * + * @param Header + * Supplies a pointer to the header of a single linked list. + * + * @return This routine returns a pointer to the removed element, or NULLPTR if the list was empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::Atomic::PopEntrySingleList(IN PSINGLE_LIST_HEADER ListHead) +{ + ULONGLONG AdjustedValue, ExpectedValue, NewValue, ResultValue, Successor; + PSINGLE_LIST_ENTRY FirstEntry; + + /* Load the initial state of the header */ + ExpectedValue = *(VOLATILE PULONGLONG)&ListHead->Alignment; + + /* Enter the CAS loop */ + while(TRUE) + { + /* Extract the entry address */ + FirstEntry = (PSINGLE_LIST_ENTRY)((LONGLONG)ExpectedValue >> 21 ); + + /* Check if list is empty */ + if(FirstEntry == NULLPTR) + { + /* Return NULLPTR */ + return NULLPTR; + } + + /* Shift the successor address */ + Successor = (ULONGLONG)FirstEntry->Next << 21; + + /* Adjust depth and merge sequence */ + AdjustedValue = (ExpectedValue & ~0xFFFFULL) | ((ExpectedValue - 1) & 0xFFFFULL); + + /* Mask to the exact 25 bits */ + AdjustedValue &= 0x01FFFFFFULL; + + /* Merge the packed address with the updated depth and sequence */ + NewValue = Successor | AdjustedValue; + + /* Perform the compare and swap operation */ + ResultValue = CompareExchange64((VOLATILE PLONG_PTR)&ListHead->Alignment, + (LONG_PTR)ExpectedValue, + (LONG_PTR)NewValue); + + /* Evaluate the CAS result */ + if(ResultValue == ExpectedValue) + { + /* Swap succeeded, return the original first entry */ + return FirstEntry; + } + + /* Collision detected, retry */ + ExpectedValue = ResultValue; + } +} + +/** + * Inserts new entry at the beginning of single linked list. + * + * @param Header + * Supplies a pointer to the header of linked list. + * + * @param Entry + * Supplies a pointer to entry, that will be inserted into linked list. + * + * @return This routine returns a pointer to original heading, or NULLPTR if the list was originally empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::Atomic::PushEntrySingleList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + ULONGLONG AdjustedValue, ExpectedValue, NewValue, PackedEntry, ResultValue; + PSINGLE_LIST_ENTRY FirstEntry; + + /* Shift the 64-bit pointer into the top 43 bits */ + PackedEntry = (ULONGLONG)Entry << 21; + + /* Load the initial state of the header */ + ExpectedValue = *(VOLATILE PULONGLONG)&ListHead->Alignment; + + /* Enter the CAS loop */ + while(TRUE) + { + /* Extract the entry address */ + FirstEntry = (PSINGLE_LIST_ENTRY)((LONGLONG)ExpectedValue >> 21 ); + + /* Set next entry to the previous first */ + Entry->Next = FirstEntry; + + /* Adjust depth and merge sequence */ + AdjustedValue = (ExpectedValue & ~0xFFFFULL) | ((ExpectedValue + 1) & 0xFFFFULL); + + /* Increment the sequence field */ + AdjustedValue += 0x10000ULL; + + /* Mask to the exact 25 bits */ + AdjustedValue &= 0x01FFFFFFULL; + + /* Merge the packed address with the updated depth and sequence */ + NewValue = PackedEntry | AdjustedValue; + + /* Perform the compare and swap operation */ + ResultValue = CompareExchange64((VOLATILE PLONG_PTR)&ListHead->Alignment, + (LONG_PTR)ExpectedValue, + (LONG_PTR)NewValue); + + /* Evaluate the CAS result */ + if(ResultValue == ExpectedValue) + { + /* Swap succeeded, return the original first entry */ + return FirstEntry; + } + + /* Collision detected, retry */ + ExpectedValue = ResultValue; + } +} diff --git a/xtoskrnl/rtl/amd64/slist.cc b/xtoskrnl/rtl/amd64/slist.cc new file mode 100644 index 0000000..97fd408 --- /dev/null +++ b/xtoskrnl/rtl/amd64/slist.cc @@ -0,0 +1,536 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/amd64/slist.cc + * DESCRIPTION: Singly linked list manipulation routines for AMD64 architecture + * DEVELOPERS: Rafal Kupiec + * Aiken Harris + */ + +#include + + +/** + * Retrieves the first entry from a singly linked list without removing it from the list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine returns a pointer to the first entry in the list, or NULLPTR if the list is empty. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::GetFirstEntry(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Empty list, return NULLPTR */ + return NULLPTR; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Extract pointer from Region */ + return (PSINGLE_LIST_ENTRY)(ListHead->Region & ~0xFLL); + } + else + { + /* Decompress and return the pointer */ + return (PSINGLE_LIST_ENTRY)(((ULONG64)ListHead & 0xFFFFF8000000000FULL) | + ((ULONG64)ListHead->Header8.NextEntry << 4)); + } +} + +/** + * Initializes a structure representing the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InitializeListHead(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Initialize the singly linked list head */ + ListHead->Alignment = 0; + ListHead->Region = 0; + ListHead->Header16.HeaderType = 1; +} + +/** + * Inserts an entry at the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine returns a pointer to the original first entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::InsertHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY OriginalEntry; + + /* Store the original first entry */ + OriginalEntry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Insert entry at the head of the list */ + Entry->Next = OriginalEntry; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Update pointer and increment depth and sequence */ + ListHead->Region = ((ULONG64)Entry & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth++; + ListHead->Header16.Sequence++; + } + else + { + /* Update pointer and increment depth and sequence */ + ListHead->Header8.NextEntry = ((ULONG64)Entry >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth++; + ListHead->Header8.Sequence++; + } + + /* Return original first entry */ + return OriginalEntry; +} + +/** + * Inserts an entry at the tail of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine returns a pointer to the original last entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY CurrentEntry, OriginalEntry; + + /* Set Next pointer of the new entry to NULLPTR */ + Entry->Next = NULLPTR; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Store the original last entry */ + OriginalEntry = NULLPTR; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Insert entry at the head */ + ListHead->Region = ((ULONG64)Entry & ~0xFLL) | (ListHead->Region & 0xFLL); + } + else + { + /* Insert entry at the head */ + ListHead->Header8.NextEntry = ((ULONG64)Entry >> 4) & 0x7FFFFFFFFFULL; + } + } + else + { + /* Traverse the list to find the last entry */ + CurrentEntry = RTL::SinglyList::GetFirstEntry(ListHead); + while(CurrentEntry->Next != NULLPTR) + { + /* Move to the next entry */ + CurrentEntry = CurrentEntry->Next; + } + + /* Store the original last entry */ + OriginalEntry = CurrentEntry; + + /* Insert entry at the tail */ + CurrentEntry->Next = Entry; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Increment list depth and sequence */ + ListHead->Header16.Depth++; + ListHead->Header16.Sequence++; + } + else + { + /* Increment list depth and sequence */ + ListHead->Header8.Depth++; + ListHead->Header8.Sequence++; + } + + /* Return original last entry */ + return OriginalEntry; +} + +/** + * Indicates whether a singly linked list structure is empty, or not initialized at all. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @return This routine returns TRUE if there are currently no entries in the list or FALSE otherwise. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +RTL::SinglyList::ListEmpty(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is uninitialized */ + if(ListHead == NULLPTR) + { + /* Empty list, return TRUE */ + return TRUE; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Check if the list is empty */ + return ((ListHead->Region & ~0xFLL) == 0); + } + else + { + /* Check if the list is empty */ + return (ListHead->Header8.NextEntry == 0); + } +} + +/** + * Queries the current depth (number of entries) of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the singly linked list. + * + * @return This routine returns the number of entries currently in the list, or zero if the list head is NULLPTR. + * + * @since XT 1.0 + */ +XTAPI +USHORT +RTL::SinglyList::QueryListDepth(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list head is initialized and valid */ + if(ListHead == NULLPTR) + { + /* Return zero */ + return 0; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Return the list depth */ + return (USHORT)ListHead->Header16.Depth; + } + else + { + /* Return the list depth */ + return (USHORT)ListHead->Header8.Depth; + } +} + +/** + * Removes an entry from a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be removed from the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::RemoveEntryList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY FirstEntry, PreviousEntry; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* List is empty, nothing to remove, return */ + return; + } + + /* Retrieve the first entry dynamically */ + FirstEntry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Check if the entry is the first one */ + if(FirstEntry == Entry) + { + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Remove the first entry and decrement depth */ + ListHead->Region = ((ULONG64)Entry->Next & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth--; + } + else + { + /* Remove the first entry and decrement depth */ + ListHead->Header8.NextEntry = ((ULONG64)Entry->Next >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth--; + } + + /* Nothing else to do, return */ + return; + } + + /* Find the previous entry */ + PreviousEntry = FirstEntry; + while(PreviousEntry->Next != Entry) + { + /* Move to the next entry */ + PreviousEntry = PreviousEntry->Next; + + /* Check if we reached the end of the list */ + if(PreviousEntry == NULLPTR) + { + /* Entry not found, return */ + return; + } + } + + /* Remove the entry */ + PreviousEntry->Next = Entry->Next; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Decrement depth */ + ListHead->Header16.Depth--; + } + else + { + /* Decrement depth */ + ListHead->Header8.Depth--; + } +} + +/** + * Splices a singly linked list at the head of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @param SpliceList + * Supplies a pointer to a structure that represents the head of the list that will be spliced. + * + * @return This routine returns a pointer to the original first entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry, OriginalEntry, SpliceFirstEntry; + + /* Store the original first entry */ + OriginalEntry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Check if the list to splice is empty */ + if(ListEmpty(SpliceList)) + { + /* Nothing to splice, return original first entry */ + return OriginalEntry; + } + + /* Find the last entry of the list to splice */ + SpliceFirstEntry = RTL::SinglyList::GetFirstEntry(SpliceList); + LastEntry = SpliceFirstEntry; + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Splice the list at the head of destination */ + LastEntry->Next = OriginalEntry; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Update destination list header pointers and values */ + ListHead->Region = ((ULONG64)SpliceFirstEntry & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header16.Sequence++; + + /* Reinitialize the source list and preserve format flags */ + SpliceList->Region &= 0xFLL; + SpliceList->Header16.Depth = 0; + } + else + { + /* Update destination list header pointers and values */ + ListHead->Header8.NextEntry = ((ULONG64)SpliceFirstEntry >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header8.Sequence++; + + /* Reinitialize the source list and preserve format flags */ + SpliceList->Header8.NextEntry = 0; + SpliceList->Header8.Depth = 0; + } + + /* Return the original first entry */ + return OriginalEntry; +} + +/** + * Splices a singly linked list at the tail of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to the head of the destination list. + * + * @param SpliceList + * Supplies a pointer to the head of the list that will be spliced. + * + * @return This routine returns a pointer to the original last entry in the list. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::SpliceTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry, OriginalEntry, SpliceFirstEntry; + + /* Get the first entry of the list to splice */ + SpliceFirstEntry = RTL::SinglyList::GetFirstEntry(SpliceList); + + /* Check if the destination list is empty */ + if(ListEmpty(ListHead)) + { + /* Destination is empty, original last entry is NULLPTR */ + OriginalEntry = NULLPTR; + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Move the splice list to the destination head */ + ListHead->Region = ((ULONG64)SpliceFirstEntry & ~0xFLL) | (ListHead->Region & 0xFLL); + } + else + { + /* Move the splice list to the destination head */ + ListHead->Header8.NextEntry = ((ULONG64)SpliceFirstEntry >> 4) & 0x7FFFFFFFFFULL; + } + } + else + { + /* Find the last entry of the destination list */ + LastEntry = RTL::SinglyList::GetFirstEntry(ListHead); + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Store the original last entry */ + OriginalEntry = LastEntry; + + /* Splice the list at the tail of destination */ + LastEntry->Next = SpliceFirstEntry; + } + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Update depth and sequence of the destination list */ + ListHead->Header16.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header16.Sequence++; + + /* Reinitialize the source list to empty while preserving format flags */ + SpliceList->Region &= 0xFLL; + SpliceList->Header16.Depth = 0; + } + else + { + /* Update depth and sequence of the destination list */ + ListHead->Header8.Depth += RTL::SinglyList::QueryListDepth(SpliceList); + ListHead->Header8.Sequence++; + + /* Reinitialize the source list to empty while preserving format flags */ + SpliceList->Header8.NextEntry = 0; + SpliceList->Header8.Depth = 0; + } + + /* Return the original last entry */ + return OriginalEntry; +} + +/** + * Retrieves the first entry from a singly linked list and removes it from the list. + * + * @param ListHead + * Pointer to a structure that serves as the list header. + * + * @return This routine returns a pointer to the first entry in the list, or NULLPTR if the list is empty. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::TakeFirstEntry(IN PSINGLE_LIST_HEADER ListHead) +{ + PSINGLE_LIST_ENTRY Entry; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* List is empty, return NULLPTR */ + return NULLPTR; + } + + /* Get the first entry dynamically */ + Entry = RTL::SinglyList::GetFirstEntry(ListHead); + + /* Check if the header is initialized as a modern 16-byte header */ + if(ListHead->Header16.HeaderType) + { + /* Remove entry from the list and decrement depth */ + ListHead->Region = ((ULONG64)Entry->Next & ~0xFLL) | (ListHead->Region & 0xFLL); + ListHead->Header16.Depth--; + } + else + { + /* Remove entry from the list and decrement depth */ + ListHead->Header8.NextEntry = ((ULONG64)Entry->Next >> 4) & 0x7FFFFFFFFFULL; + ListHead->Header8.Depth--; + } + + /* Return the first entry */ + return Entry; +} diff --git a/xtoskrnl/rtl/atomic.cc b/xtoskrnl/rtl/atomic.cc index 86b16d8..a115ef1 100644 --- a/xtoskrnl/rtl/atomic.cc +++ b/xtoskrnl/rtl/atomic.cc @@ -4,11 +4,117 @@ * FILE: xtoskrnl/rtl/atomic.cc * DESCRIPTION: Atomic operations support * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #include +/** + * Performs an atomic addition on the 8-bit value. + * + * @param Address + * Supplies the address of the value on which the addition is to be performed. + * + * @param Value + * Supplies the value to be added. + * + * @return This routine returns the initial value at the given address. + * + * @since XT 1.0 + */ +XTFASTCALL +CHAR +RTL::Atomic::Add8(IN PCHAR Address, + IN CHAR Value) +{ + return __sync_fetch_and_add(Address, Value); +} + +/** + * Performs an atomic addition on the 16-bit value. + * + * @param Address + * Supplies the address of the value on which the addition is to be performed. + * + * @param Value + * Supplies the value to be added. + * + * @return This routine returns the initial value at the given address. + * + * @since XT 1.0 + */ +XTFASTCALL +SHORT +RTL::Atomic::Add16(IN PSHORT Address, + IN SHORT Value) +{ + return __sync_fetch_and_add(Address, Value); +} + +/** + * Performs an atomic addition on the 32-bit value. + * + * @param Address + * Supplies the address of the value on which the addition is to be performed. + * + * @param Value + * Supplies the value to be added. + * + * @return This routine returns the initial value at the given address. + * + * @since XT 1.0 + */ +XTFASTCALL +LONG +RTL::Atomic::Add32(IN PLONG Address, + IN LONG Value) +{ + return __sync_fetch_and_add(Address, Value); +} + +/** + * Performs an atomic addition on the 64-bit value. + * + * @param Address + * Supplies the address of the value on which the addition is to be performed. + * + * @param Value + * Supplies the value to be added. + * + * @return This routine returns the initial value at the given address. + * + * @since XT 1.0 + */ +XTFASTCALL +LONG_PTR +RTL::Atomic::Add64(IN PLONG_PTR Address, + IN LONG_PTR Value) +{ + return __sync_fetch_and_add(Address, Value); +} + +/** + * Performs an atomic addition on the pointer value. + * + * @param Address + * Supplies the address of the pointer on which the addition is to be performed. + * + * @param Value + * Supplies the value (in bytes) to be added to the pointer. + * + * @return This routine returns the initial pointer value at the given address. + * + * @since XT 1.0 + */ +XTFASTCALL +PVOID +RTL::Atomic::AddPointer(IN PVOID *Address, + IN PVOID Value) +{ + return (PVOID)__sync_fetch_and_add(Address, Value); +} + /** * Performs an atomic bitwise AND operation on the 8-bit value. * @@ -93,6 +199,48 @@ RTL::Atomic::And64(IN PLONG_PTR Address, return __sync_fetch_and_and(Address, Mask); } +/** + * Performs an atomic test of the specified bit of the specified long value and resets it to 0. + * + * @param Base + * Supplies a pointer to the variable. + * + * @param Offset + * Specifies the bit position to be tested. + * + * @return This routine returns the original value of the specified bit. + * + * @since XT 1.0 + */ +XTFASTCALL +UCHAR +RTL::Atomic::BitTestAndReset(IN PLONG Base, + IN LONG Offset) +{ + return (__atomic_fetch_and(Base, ~(1l << Offset), __ATOMIC_SEQ_CST) >> Offset) & 1; +} + +/** + * Performs an atomic test of the specified bit of the specified 64-bit long value and resets it to 0. + * + * @param Base + * Supplies a pointer to the variable. + * + * @param Offset + * Specifies the bit position to be tested. + * + * @return This routine returns the original value of the specified bit. + * + * @since XT 1.0 + */ +XTFASTCALL +UCHAR +RTL::Atomic::BitTestAndReset64(IN PLONGLONG Base, + IN LONGLONG Offset) +{ + return (__atomic_fetch_and(Base, ~(1ll << Offset), __ATOMIC_SEQ_CST) >> Offset) & 1; +} + /** * Performs an atomic test of the specified bit of the specified long value and sets it to 1. * @@ -102,7 +250,7 @@ RTL::Atomic::And64(IN PLONG_PTR Address, * @param Offset * Specifies the bit position to be tested. * - * @return Returns a value of the specified bit. + * @return This routine returns a value of the specified bit. * * @since XT 1.0 */ @@ -123,7 +271,7 @@ RTL::Atomic::BitTestAndSet(IN PLONG Base, * @param Offset * Specifies the bit position to be tested. * - * @return Returns a value of the specified bit. + * @return This routine returns a value of the specified bit. * * @since XT 1.0 */ @@ -518,23 +666,6 @@ RTL::Atomic::ExchangePointer(IN PVOID *Address, return (PVOID)__sync_lock_test_and_set(Address, Exchange); } -/** - * Removes all entries from single linked list. - * - * @param Header - * Supplies a pointer to the header of linked list. - * - * @return This routine returns a pointer to the original list, or NULLPTR if the list was already empty. - * - * @since XT 1.0 - */ -XTFASTCALL -PSINGLE_LIST_ENTRY -RTL::Atomic::FlushSingleList(IN PSINGLE_LIST_HEADER Header) -{ - return (PSINGLE_LIST_ENTRY)Exchange64((PLONG_PTR)&Header->Alignment, (LONGLONG)NULLPTR); -} - /** * Performs atomically increment of the 8-bit value. * @@ -687,89 +818,6 @@ RTL::Atomic::Or64(IN PLONG_PTR Address, return __sync_fetch_and_or(Address, Mask); } -/** - * Removes and returns the first entry from single linked list. - * - * @param Header - * Supplies a pointer to the header of a single linked list. - * - * @return This routine returns a pointer to the removed element, or NULLPTR if the list was empty. - * - * @since XT 1.0 - */ -XTFASTCALL -PSINGLE_LIST_ENTRY -RTL::Atomic::PopEntrySingleList(IN PSINGLE_LIST_HEADER Header) -{ - PSINGLE_LIST_ENTRY ListHead, FirstEntry, NextEntry; - - /* Save header and first entry */ - ListHead = (PSINGLE_LIST_ENTRY)Header; - FirstEntry = ListHead->Next; - do - { - /* Check if list is not empty */ - if(!FirstEntry) - { - /* Empty list */ - return NULLPTR; - } - - /* Update link */ - NextEntry = FirstEntry; - - /* Compare and exchange */ - FirstEntry = (PSINGLE_LIST_ENTRY)CompareExchange64((PLONG_PTR)ListHead, - (LONG_PTR)FirstEntry->Next, - (LONG_PTR)FirstEntry); - } while(FirstEntry != NextEntry); - - /* Return removed element */ - return FirstEntry; -} - -/** - * Inserts new entry at the beginning of single linked list. - * - * @param Header - * Supplies a pointer to the header of linked list. - * - * @param Entry - * Supplies a pointer to entry, that will be inserted into linked list. - * - * @return This routine returns a pointer to original heading, or NULLPTR if the list was originally empty. - * - * @since XT 1.0 - */ -XTFASTCALL -PSINGLE_LIST_ENTRY -RTL::Atomic::PushEntrySingleList(IN PSINGLE_LIST_HEADER Header, - IN PSINGLE_LIST_ENTRY Entry) -{ - PSINGLE_LIST_ENTRY ListHead, ListEntry, FirstEntry, NextEntry; - - /* Save header and new entry */ - ListHead = (PSINGLE_LIST_ENTRY)Header; - ListEntry = Entry; - - /* Save next link in new first element */ - FirstEntry = ListHead->Next; - do - { - /* Update links */ - ListEntry->Next = FirstEntry; - NextEntry = FirstEntry; - - /* Compare and exchange */ - FirstEntry = (PSINGLE_LIST_ENTRY)CompareExchange64((PLONG_PTR)ListHead, - (LONG_PTR)ListEntry, - (LONG_PTR)FirstEntry); - } while(FirstEntry != NextEntry); - - /* Return original first element */ - return FirstEntry; -} - /** * Performs an atomic bitwise XOR operation on the 8-bit value. * diff --git a/xtoskrnl/rtl/exports.cc b/xtoskrnl/rtl/exports.cc index b2f8bee..ec7c0da 100644 --- a/xtoskrnl/rtl/exports.cc +++ b/xtoskrnl/rtl/exports.cc @@ -392,6 +392,29 @@ RtlCopyString(IN PCHAR Destination, RTL::String::CopyString(Destination, Source, Length); } +/** + * Copies a source Unicode string to a destination Unicode string. + * + * @param Destination + * Supplies a pointer to the destination string. + * + * @param Source + * Supplies an optional pointer to the source string. If this parameter is not provided, + * the destination string is effectively emptied. + * + * @return This routine does not return any value. + * + * @since NT 3.5 + */ +XTCLINK +XTAPI +VOID +RtlCopyUnicodeString(IN OUT PUNICODE_STRING Destination, + IN PCUNICODE_STRING Source) +{ + RTL::Unicode::CopyString(Destination, Source); +} + /** * Copies a wide string from a buffer into another buffer, ensuring that the destination string is NULL-terminated. * @@ -628,6 +651,50 @@ RtlInitializeListHead(IN PLIST_ENTRY ListHead) RTL::LinkedList::InitializeListHead(ListHead); } +/** + * Initializes a Unicode string. + * + * @param Destination + * Supplies a pointer to the UNICODE_STRING structure to be initialized. + * + * @param Source + * Supplies an optional pointer to a NULL-terminated wide character string. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCLINK +XTAPI +VOID +RtlInitializeUnicodeString(OUT PUNICODE_STRING Destination, + IN PCWSTR Source) +{ + RTL::Unicode::InitializeString(Destination, Source, TRUE); +} + +/** + * Initializes a Unicode string. + * + * @param Destination + * Supplies a pointer to the UNICODE_STRING structure to be initialized. + * + * @param Source + * Supplies an optional pointer to a NULL-terminated wide character string. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTCLINK +XTAPI +XTSTATUS +RtlInitializeUnicodeStringEx(OUT PUNICODE_STRING Destination, + IN PCWSTR Source) +{ + return RTL::Unicode::InitializeString(Destination, Source); +} + /** * This routine inserts an entry at the head of a doubly linked list. * diff --git a/xtoskrnl/rtl/exsup.cc b/xtoskrnl/rtl/exsup.cc new file mode 100644 index 0000000..5486c77 --- /dev/null +++ b/xtoskrnl/rtl/exsup.cc @@ -0,0 +1,89 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/exsup.cc + * DESCRIPTION: Exception handling + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Raises a structured exception using an exception record. + * + * @param ExceptionRecord + * Supplies a pointer to the exception record containing details. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::Exception::RaiseException(IN PEXCEPTION_RECORD ExceptionRecord) +{ + /* Not implemented */ + UNIMPLEMENTED; + + /* Disable interrupts */ + AR::CpuFunctions::ClearInterruptFlag(); + + /* Halt the system */ + KE::Crash::Panic(ExceptionRecord->ExceptionCode); +} + +/** + * Raises a structured exception based on the provided status code. + * + * @param Status + * Supplies the status code to be raised as an exception. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::Exception::RaiseStatus(IN XTSTATUS Status) +{ + EXCEPTION_RECORD ExceptionRecord; + + /* Not implemented */ + UNIMPLEMENTED; + + /* Create a basic exception record */ + ExceptionRecord.ExceptionAddress = _ReturnAddress(); + ExceptionRecord.ExceptionCode = Status; + ExceptionRecord.ExceptionRecord = NULLPTR; + ExceptionRecord.NumberParameters = 0; + ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + + /* Dispatch the exception */ + RaiseException(&ExceptionRecord); +} + +/** + * Determines whether a SEH exception should be handled or lead to a kernel panic based on the processor mode. + * + * @return This routine returns EXCEPTION_EXECUTE_HANDLER if the CPU was in UserMode, + * or EXCEPTION_CONTINUE_SEARCH if the CPU was in KernelMode. + * + * @since XT 1.0 + */ +XTAPI +LONG +RTL::Exception::SystemFilter(VOID) +{ + /* Check if the exception originated from kernel-mode execution */ + if(KE::Processor::GetCurrentThread()->PreviousMode == KernelMode) + { + /* Kernel-mode fault, force a kernel panic */ + return EXCEPTION_CONTINUE_SEARCH; + } + else + { + /* User-mode fault, catch it and return the error status gracefully */ + return EXCEPTION_EXECUTE_HANDLER; + } +} diff --git a/xtoskrnl/rtl/i686/atomic.cc b/xtoskrnl/rtl/i686/atomic.cc new file mode 100644 index 0000000..45e60dc --- /dev/null +++ b/xtoskrnl/rtl/i686/atomic.cc @@ -0,0 +1,178 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/i686/atomic.cc + * DESCRIPTION: Atomic operations support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Removes all entries from single linked list. + * + * @param Header + * Supplies a pointer to the header of linked list. + * + * @return This routine returns a pointer to the original list, or NULLPTR if the list was already empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::Atomic::FlushSingleList(IN PSINGLE_LIST_HEADER ListHead) +{ + SINGLE_LIST_HEADER ExpectedHeader, NewHeader; + PSINGLE_LIST_ENTRY FirstEntry; + ULONG64 ResultValue; + + /* Load the initial state of the header */ + ExpectedHeader.Alignment = *(VOLATILE PULONGLONG)&ListHead->Alignment; + + /* Enter the CAS loop */ + while(TRUE) + { + /* Extract the entry address */ + FirstEntry = ExpectedHeader.Next.Next; + + /* Check if list is empty */ + if(FirstEntry == NULLPTR) + { + /* Return NULLPTR */ + return NULLPTR; + } + + /* Prepare the new header state */ + NewHeader.Next.Next = NULLPTR; + NewHeader.Depth = 0; + NewHeader.Sequence = ExpectedHeader.Sequence; + + /* Perform the compare and swap operation */ + ResultValue = CompareExchange64((VOLATILE PLONG_PTR)&ListHead->Alignment, + (LONG_PTR)ExpectedHeader.Alignment, + (LONG_PTR)NewHeader.Alignment); + + /* Evaluate the CAS result */ + if(ResultValue == ExpectedHeader.Alignment) + { + /* Swap succeeded, return the original first entry */ + return FirstEntry; + } + + /* Collision detected, retry */ + ExpectedHeader.Alignment = ResultValue; + } +} + +/** + * Removes and returns the first entry from single linked list. + * + * @param Header + * Supplies a pointer to the header of a single linked list. + * + * @return This routine returns a pointer to the removed element, or NULLPTR if the list was empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::Atomic::PopEntrySingleList(IN PSINGLE_LIST_HEADER ListHead) +{ + SINGLE_LIST_HEADER ExpectedHeader, NewHeader; + PSINGLE_LIST_ENTRY FirstEntry; + ULONGLONG ResultValue; + + /* Load the initial state of the header */ + ExpectedHeader.Alignment = *(VOLATILE PULONGLONG)&ListHead->Alignment; + + /* Enter the CAS loop */ + while(TRUE) + { + /* Extract the entry address */ + FirstEntry = ExpectedHeader.Next.Next; + + /* Check if list is empty */ + if(FirstEntry == NULLPTR) + { + /* Return NULLPTR */ + return NULLPTR; + } + + /* Prepare the new header state */ + NewHeader.Next.Next = FirstEntry->Next; + NewHeader.Depth = ExpectedHeader.Depth - 1; + NewHeader.Sequence = ExpectedHeader.Sequence; + + /* Perform the compare and swap operation */ + ResultValue = CompareExchange64((VOLATILE PLONG_PTR)&ListHead->Alignment, + (LONG_PTR)ExpectedHeader.Alignment, + (LONG_PTR)NewHeader.Alignment); + + /* Evaluate the CAS result */ + if(ResultValue == ExpectedHeader.Alignment) + { + /* Swap succeeded, return the original first entry */ + return FirstEntry; + } + + /* Collision detected, retry */ + ExpectedHeader.Alignment = ResultValue; + } +} + +/** + * Inserts new entry at the beginning of single linked list. + * + * @param Header + * Supplies a pointer to the header of linked list. + * + * @param Entry + * Supplies a pointer to entry, that will be inserted into linked list. + * + * @return This routine returns a pointer to original heading, or NULLPTR if the list was originally empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::Atomic::PushEntrySingleList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + SINGLE_LIST_HEADER ExpectedHeader, NewHeader; + PSINGLE_LIST_ENTRY FirstEntry; + ULONGLONG ResultValue; + + /* Load the initial state of the header */ + ExpectedHeader.Alignment = *(VOLATILE PULONGLONG)&ListHead->Alignment; + + /* Enter the CAS loop */ + while(TRUE) + { + /* Extract the entry address */ + FirstEntry = ExpectedHeader.Next.Next; + + /* Set next entry to the previous first */ + Entry->Next = FirstEntry; + + /* Prepare the new header state */ + NewHeader.Next.Next = Entry; + NewHeader.Depth = ExpectedHeader.Depth + 1; + NewHeader.Sequence = ExpectedHeader.Sequence + 1; + + /* Perform the compare and swap operation */ + ResultValue = CompareExchange64((VOLATILE PLONG_PTR)&ListHead->Alignment, + (LONG_PTR)ExpectedHeader.Alignment, + (LONG_PTR)NewHeader.Alignment); + + /* Evaluate the CAS result */ + if(ResultValue == ExpectedHeader.Alignment) + { + /* Swap succeeded, return the original first entry */ + return FirstEntry; + } + + /* Collision detected, retry */ + ExpectedHeader.Alignment = ResultValue; + } +} diff --git a/xtoskrnl/rtl/slist.cc b/xtoskrnl/rtl/i686/slist.cc similarity index 98% rename from xtoskrnl/rtl/slist.cc rename to xtoskrnl/rtl/i686/slist.cc index 5677744..1cc2cd4 100644 --- a/xtoskrnl/rtl/slist.cc +++ b/xtoskrnl/rtl/i686/slist.cc @@ -1,8 +1,8 @@ /** * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory - * FILE: xtoskrnl/rtl/slist.cc - * DESCRIPTION: Singly linked list manipulation routines + * FILE: xtoskrnl/rtl/i686/slist.cc + * DESCRIPTION: Singly linked list manipulation routines for i686 architecture * DEVELOPERS: Rafal Kupiec */ @@ -112,7 +112,7 @@ RTL::SinglyList::InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, if(ListEmpty(ListHead)) { /* Store the original last entry */ - OriginalEntry = ListHead->Next.Next; + OriginalEntry = NULLPTR; /* Insert entry at the head */ ListHead->Next.Next = Entry; @@ -263,7 +263,7 @@ RTL::SinglyList::SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, { PSINGLE_LIST_ENTRY LastEntry, OriginalEntry; - /* Store the original last entry */ + /* Store the original first entry */ OriginalEntry = ListHead->Next.Next; /* Check if the list to splice is empty */ diff --git a/xtoskrnl/rtl/lifo.cc b/xtoskrnl/rtl/lifo.cc new file mode 100644 index 0000000..7742a3c --- /dev/null +++ b/xtoskrnl/rtl/lifo.cc @@ -0,0 +1,140 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/lifo.cc + * DESCRIPTION: Last In First Out (LIFO) queue implementation + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Evaluates whether the LIFO queue is completely empty. + * + * @param ListHead + * Supplies a pointer to the head of the LIFO queue. + * + * @return This routine returns TRUE if the queue is empty, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +RTL::LifoQueue::EmptyList(IN PSINGLE_LIST_ENTRY ListHead) +{ + /* Return the queue status */ + return (ListHead->Next == NULLPTR); +} + +/** + * Retrieves the first entry from the LIFO queue without removing it. + * + * @param ListHead + * Supplies a pointer to the head of the LIFO queue. + * + * @return This routine returns a pointer to the first entry, or NULLPTR if empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::LifoQueue::PeekEntryList(IN PSINGLE_LIST_ENTRY ListHead) +{ + /* Return the entry at the top of the queue */ + return ListHead->Next; +} + +/** + * Removes and returns the entry at the top of the LIFO queue. + * + * @param ListHead + * Supplies a pointer to the head of the LIFO queue. + * + * @return This routine returns a pointer to the removed entry, or NULLPTR if empty. + * + * @since XT 1.0 + */ +XTFASTCALL +PSINGLE_LIST_ENTRY +RTL::LifoQueue::PopEntryList(IN OUT PSINGLE_LIST_ENTRY ListHead) +{ + PSINGLE_LIST_ENTRY Entry; + + /* Capture the entry currently at the top of the queue */ + Entry = ListHead->Next; + + /* Check if the queue is not empty */ + if(Entry) + { + /* Unlink the first entry */ + ListHead->Next = Entry->Next; + } + + /* Return the captured entry */ + return Entry; +} + +/** + * Pushes an entry onto the top of the LIFO queue. + * + * @param ListHead + * Supplies a pointer to the head of the LIFO queue. + * + * @param Entry + * Supplies a pointer to the entry to be pushed onto the queue. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +RTL::LifoQueue::PushEntryList(IN OUT PSINGLE_LIST_ENTRY ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + /* Link the new entry and update queue head */ + Entry->Next = ListHead->Next; + ListHead->Next = Entry; +} + +/** + * Searches the LIFO queue to determine if a specific entry is present. + * + * @param ListHead + * Supplies a pointer to the head of the LIFO queue. + * + * @param Entry + * Supplies a pointer to the entry being searched for. + * + * @return This routine returns TRUE if the entry is found, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +RTL::LifoQueue::SearchEntryList(IN PSINGLE_LIST_ENTRY ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY CurrentEntry; + + /* Start traversing from the first entry in the queue */ + CurrentEntry = ListHead->Next; + + /* Iterate through the linked list until the end is reached */ + while(CurrentEntry != NULLPTR) + { + /* Check if the current node matches the target entry */ + if(CurrentEntry == Entry) + { + /* Entry found within the queue, return TRUE */ + return TRUE; + } + + /* Move to the next entry in the chain */ + CurrentEntry = CurrentEntry->Next; + } + + /* Target entry not found, return FALSE */ + return FALSE; +} diff --git a/xtoskrnl/rtl/nls.cc b/xtoskrnl/rtl/nls.cc new file mode 100644 index 0000000..2c5658b --- /dev/null +++ b/xtoskrnl/rtl/nls.cc @@ -0,0 +1,130 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/nls.cc + * DESCRIPTION: National Language Support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Retrieves the default ANSI and OEM code page identifiers for the system. + * + * @param AnsiCodePage + * Receives the default ANSI code page identifier. + * + * @param OemCodePage + * Receives the default OEM code page identifier. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::Nls::GetDefaultCodePage(OUT PUSHORT AnsiCodePage, + OUT PUSHORT OemCodePage) +{ + /* No NLS support */ + UNIMPLEMENTED; + + /* Set fallback values to zero */ + *AnsiCodePage = 0; + *OemCodePage = 0; +} + +/** + * Initializes a code page table information structure from a raw table base pointer. + * + * @param TableBase + * Supplies a pointer to the raw code page data. + * + * @param CodePageTable + * Receives the initialized code page table information structure. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::Nls::InitializeCodePageTable(IN PUSHORT TableBase, + OUT PCPTABLE_INFO CodePageTable) +{ + /* No NLS support */ + UNIMPLEMENTED; +} + +/** + * Initializes the global NLS table information structure using raw table bases. + * + * @param AnsiTableBase + * Supplies a pointer to the raw ANSI translation table data. + * + * @param OemTableBase + * Supplies a pointer to the raw OEM translation table data. + * + * @param CaseTableBase + * Supplies a pointer to the raw Unicode uppercase/lowercase mapping table data. + * + * @param NlsTable + * Receives the fully initialized NLS table structure. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::Nls::InitializeNlsTables(IN PUSHORT AnsiTableBase, + IN PUSHORT OemTableBase, + IN PUSHORT CaseTableBase, + OUT PNLSTABLE_INFO NlsTable) +{ + /* No NLS support */ + UNIMPLEMENTED; +} + +/** + * Converts a wide character to its lowercase equivalent using Unicode rules. + * + * @param WideCharacter + * Supplies the Unicode wide character to convert. + * + * @return This routine returns the lowercase equivalent of the provided wide character. + * + * @since XT 1.0 + */ +XTAPI +WCHAR +RTL::Nls::ToLowerUnicodeCharacter(IN WCHAR WideCharacter) +{ + /* This is temporary wrapper with no NLS support */ + UNIMPLEMENTED; + + /* Fall back to the internal wide string character transformation engine */ + return RTL::WideString::ToLowerWideCharacter(WideCharacter); +} + +/** + * Converts a wide character to its uppercase equivalent using Unicode rules. + * + * @param WideCharacter + * Supplies the Unicode wide character to convert. + * + * @return This routine returns the uppercase equivalent of the provided wide character. + * + * @since XT 1.0 + */ +XTAPI +WCHAR +RTL::Nls::ToUpperUnicodeCharacter(IN WCHAR WideCharacter) +{ + /* This is temporary wrapper with no NLS support */ + UNIMPLEMENTED; + + /* Fallback to the internal wide string character transformation engine */ + return RTL::WideString::ToUpperWideCharacter(WideCharacter); +} diff --git a/xtoskrnl/rtl/unicode.cc b/xtoskrnl/rtl/unicode.cc new file mode 100644 index 0000000..05ce174 --- /dev/null +++ b/xtoskrnl/rtl/unicode.cc @@ -0,0 +1,181 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/unicode.cc + * DESCRIPTION: Unicode support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Compares two Unicode strings. + * + * @param String1 + * Supplies a pointer to the first UNICODE_STRING. + * + * @param String2 + * Supplies a pointer to the second UNICODE_STRING. + * + * @param CaseInsensitive + * Specifies whether the comparison should be case-insensitive (TRUE) or case-sensitive (FALSE). + * + * @return This routine returns an integral value indicating the relationship between the wide strings. + */ +XTAPI +LONG +RTL::Unicode::CompareString(IN PCUNICODE_STRING String1, + IN PCUNICODE_STRING String2, + IN BOOLEAN CaseInsensitive) +{ + SIZE_T WideCharsToCompare; + PWCHAR Buffer1, Buffer2; + LONG Difference; + + /* Isolate the bounded safe region determined by the shortest string */ + WideCharsToCompare = (String1->Length < String2->Length ? String1->Length : String2->Length) >> 1; + + /* Cache the string buffer pointers */ + Buffer1 = String1->Buffer; + Buffer2 = String2->Buffer; + + /* Determine the comparison mode */ + if(CaseInsensitive) + { + /* Perform a case-insensitive comparison */ + while(WideCharsToCompare--) + { + /* Convert both wide characters to uppercase and compute their lexicographical difference */ + Difference = (LONG)RTL::Nls::ToUpperUnicodeCharacter(*Buffer1++) - + (LONG)RTL::Nls::ToUpperUnicodeCharacter(*Buffer2++); + if(Difference != 0) + { + /* A character mismatch found, return the computed difference */ + return Difference; + } + } + } + else + { + /* Perform a case-sensitive comparison */ + while(WideCharsToCompare--) + { + /* Compute the lexicographical difference between the wide characters */ + Difference = (LONG)(*Buffer1++) - (LONG)(*Buffer2++); + if(Difference != 0) + { + /* A character mismatch found, return the computed difference */ + return Difference; + } + } + } + + /* All characters match, return the relationship determined by the difference in length */ + return (LONG)String1->Length - (LONG)String2->Length; +} + +/** + * Copies a source Unicode string to a destination Unicode string. + * + * @param Destination + * Supplies a pointer to the destination string. + * + * @param Source + * Supplies an optional pointer to the source string. If this parameter is not provided, + * the destination string is effectively emptied. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +RTL::Unicode::CopyString(IN OUT PUNICODE_STRING Destination, + IN PCUNICODE_STRING Source) +{ + ULONG Length; + + /* Check if the source string pointer is valid */ + if(!Source) + { + /* Source is missing, clear the destination string and return */ + Destination->Length = 0; + return; + } + + /* Calculate the length to copy */ + Length = MIN(Source->Length, Destination->MaximumLength); + Destination->Length = Length; + + /* Copy the source string data into the destination buffer */ + RTL::Memory::CopyMemory(Destination->Buffer, Source->Buffer, Length); + + /* Check if there is enough space left in the buffer to NULL-terminate */ + if(Destination->Length < Destination->MaximumLength) + { + /* Append a NULL terminator */ + Destination->Buffer[Length / sizeof(WCHAR)] = (WCHAR)0; + } +} + +/** + * Initializes a Unicode string. + * + * @param Destination + * Supplies a pointer to the UNICODE_STRING structure to be initialized. + * + * @param Source + * Supplies an optional pointer to a NULL-terminated wide character string. + * + * @param Truncate + * Specifies whether to truncate the source string to the maximum allowed length. + * + * @return This routine returns a status code indicating the success or failure of the operation. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +RTL::Unicode::InitializeString(OUT PUNICODE_STRING Destination, + IN PCWSTR Source, + IN BOOLEAN Truncate) +{ + ULONG Size; + + /* Check if the source string pointer is valid */ + if(!Source) + { + /* Source is missing, initialize the destination as empty string */ + Destination->Length = 0; + Destination->MaximumLength = 0; + + /* Return success */ + return STATUS_SUCCESS; + } + + /* Calculate the size of the string in bytes */ + Size = RTL::WideString::WideStringLength(Source, 0) * sizeof(WCHAR); + + /* Check if the size exceeds the maximum allowed */ + if(Size > ((MAXUSHORT & ~1) - sizeof(WCHAR))) + { + /* Check if truncation is not explicitly forced */ + if(!Truncate) + { + /* Return error code */ + return STATUS_NAME_TOO_LONG; + } + + /* Force truncation to the maximum safe length */ + Size = (MAXUSHORT & ~1) - sizeof(WCHAR); + } + + /* Initialize the destination string fields */ + Destination->Buffer = (PWCHAR)Source; + Destination->Length = (USHORT)Size; + Destination->MaximumLength = (USHORT)Size + sizeof(WCHAR); + + /* Return success */ + return STATUS_SUCCESS; +} diff --git a/xtoskrnl/se/access.cc b/xtoskrnl/se/access.cc new file mode 100644 index 0000000..db1a606 --- /dev/null +++ b/xtoskrnl/se/access.cc @@ -0,0 +1,104 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/se/access.cc + * DESCRIPTION: Security access state check routines + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Computes the access rights that are requested but not granted. + * + * @param GrantedAccessMask + * Supplies the mask of access rights currently granted to the subject. + * + * @param DesiredAccessMask + * Supplies the mask of access rights requested by the subject. + * + * @return This routine returns an access mask with the bits in DesiredAccess that are not present in GrantedAccess. + * + * @since XT 1.0 + */ +XTFASTCALL +ACCESS_MASK +SE::Access::ComputeDeniedAccesses(IN ACCESS_MASK GrantedAccessMask, + IN ACCESS_MASK DesiredAccessMask) +{ + /* Return the desired denied accesses */ + return ~GrantedAccessMask & DesiredAccessMask; +} + +/** + * Computes the access rights that are both requested and granted. + * + * @param GrantedAccessMask + * Supplies the mask of access rights currently granted to the subject. + * + * @param DesiredAccessMask + * Supplies the mask of access rights requested by the subject. + * + * @return This routine returns an access mask containing the intersection of DesiredAccess and GrantedAccess bits. + * + * @since XT 1.0 + */ +XTFASTCALL +ACCESS_MASK +SE::Access::ComputeGrantedAccesses(IN ACCESS_MASK GrantedAccessMask, + IN ACCESS_MASK DesiredAccessMask) +{ + /* Return the desired granted accesses */ + return GrantedAccessMask & DesiredAccessMask; +} + +/** + * Maps all generic accesses in the provided access mask to specific and standard accesses. + * + * @param AccessMask + * Supplies a pointer to the access mask to be mapped. + * + * @param Mapping + * Supplies the mapping of generic to specific and standard access types. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +SE::Access::MapGenericMask(IN OUT PACCESS_MASK AccessMask, + IN PGENERIC_MAPPING Mapping) +{ + /* Check if the read right is present in the access mask */ + if(*AccessMask & SE_GENERIC_READ) + { + /* Map the read flag to its specific access rights */ + *AccessMask |= Mapping->GenericRead; + } + + /* Check if the write right is present in the access mask */ + if(*AccessMask & SE_GENERIC_WRITE) + { + /* Map the write flag to its specific access rights */ + *AccessMask |= Mapping->GenericWrite; + } + + /* Check if the execute right is present in the access mask */ + if(*AccessMask & SE_GENERIC_EXECUTE) + { + /* Map the execute flag to its specific access rights */ + *AccessMask |= Mapping->GenericExecute; + } + + /* Check if the all right is present in the access mask */ + if(*AccessMask & SE_GENERIC_ALL) + { + /* Map the all flag to its specific access rights */ + *AccessMask |= Mapping->GenericAll; + } + + /* Clear the generic flags from the final access mask */ + *AccessMask &= ~(SE_GENERIC_READ | SE_GENERIC_WRITE | SE_GENERIC_EXECUTE | SE_GENERIC_ALL); +} diff --git a/xtoskrnl/se/audit.cc b/xtoskrnl/se/audit.cc new file mode 100644 index 0000000..0e512be --- /dev/null +++ b/xtoskrnl/se/audit.cc @@ -0,0 +1,92 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/se/audit.cc + * DESCRIPTION: Security Auditing + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Generates a security audit event for an object handle duplication. + * + * @param SourceHandle + * Supplies the original handle identifier as it exists in the source process. + * + * @param TargetHandle + * Supplies the newly created handle identifier as it exists in the target process. + * + * @param SourceProcess + * Supplies a pointer to the executive process originating the duplication. + * + * @param TargetProcess + * Supplies a pointer to the executive process receiving the duplicated handle. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +SE::Audit::AuditHandleDuplication(PVOID SourceHandle, + PVOID TargetHandle, + PEPROCESS SourceProcess, + PEPROCESS TargetProcess) +{ + UNIMPLEMENTED; +} + +/** + * Determines whether detailed security auditing is enabled for a specific token. + * + * @param AccessToken + * Supplies an optional pointer to the access token to be evaluated. + * + * @return This routine returns TRUE if auditing is required, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +SE::Audit::AuditWithToken(IN PACCESS_TOKEN AccessToken) +{ + UNIMPLEMENTED; + + /* Bypass audit generation */ + return FALSE; +} + +/** + * Generates a security audit alarm for an object access operation. + * + * @param SubsystemName + * Supplies the name of the subsystem triggering the audit alarm. + * + * @param HandleId + * Supplies the handle or identifier of the object being accessed. + * + * @param ObjectTypeName + * Supplies the name of the object type being accessed. + * + * @param AccessMask + * Supplies the access mask containing the specific rights that triggered the audit. + * + * @param UserSid + * Optionally supplies the SID of the user initiating the operation. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +SE::Audit::OperationAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN ACCESS_MASK AccessMask, + IN PSID UserSid) +{ + UNIMPLEMENTED; +} diff --git a/xtoskrnl/se/descript.cc b/xtoskrnl/se/descript.cc new file mode 100644 index 0000000..ae91b14 --- /dev/null +++ b/xtoskrnl/se/descript.cc @@ -0,0 +1,127 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/se/descript.cc + * DESCRIPTION: Security Descriptors + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** +* Creates a safe kernel-space copy of a security descriptor to prevent TOC/TOU vulnerabilities. +* +* @param InputDescriptor +* Supplies a pointer to the original security descriptor to be captured. +* +* @param ProcessorMode +* Supplies the processor mode from which the request originated. +* +* @param PoolType +* Supplies the type of memory pool to allocate the captured copy from. +* +* @param ForceCapture +* Supplies a boolean value indicating whether to force the capture in kernel mode. +* +* @param OutputDescriptor +* Supplies a pointer to a variable that receives the safely captured security descriptor. +* +* @return This routine returns a status code indicating the success or failure of the operation. +* +* @since XT 1.0 +*/ +XTAPI +XTSTATUS +SE::Descriptor::CaptureSecurityDescriptor(IN PSECURITY_DESCRIPTOR InputDescriptor, + IN KPROCESSOR_MODE ProcessorMode, + IN MMPOOL_TYPE PoolType, + IN BOOLEAN ForceCapture, + OUT PSECURITY_DESCRIPTOR *OutputDescriptor) +{ + UNIMPLEMENTED; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Computes the memory quota required for a security descriptor. + * + * @param Size + * Supplies the base size of the security information in bytes. + * + * @return This routine returns the computed security quota in bytes. + * + * @since XT 1.0 + */ +XTFASTCALL +ULONG +SE::Descriptor::ComputeSecurityQuota(IN ULONG Size) +{ + ULONG ComputedSize; + + /* Calculate double the base size */ + ComputedSize = Size * 2; + + /* Ensure the allocated quota meets the minimum default system threshold */ + return (ComputedSize > SE_DEFAULT_SECURITY_QUOTA) ? ComputedSize : SE_DEFAULT_SECURITY_QUOTA; +} + +/** +* Calculates the exact memory footprint of a security descriptor for quota accounting. +* +* @param SecurityDescriptor +* Supplies a pointer to a valid, captured security descriptor. +* +* @param QuotaSize +* Supplies a pointer to a variable that receives the calculated quota size in bytes. +* +* @return This routine returns a status code indicating the success or failure of the operation. +* +* @since XT 1.0 +*/ +XTAPI +XTSTATUS +SE::Descriptor::ComputeQuotaInformationSize(IN PSECURITY_DESCRIPTOR SecurityDescriptor, + OUT PULONG QuotaSize) +{ + UNIMPLEMENTED; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** +* Frees the memory of a captured security descriptor. +* +* @param Descriptor +* Supplies a pointer to the captured security descriptor to be released. +* +* @param ProcessorMode +* Supplies the processor mode that was originally used to capture the descriptor. +* +* @param Force +* Supplies a boolean value indicating whether to force the deallocation. +* +* @return This routine does not return any value. +* +* @since XT 1.0 +*/ +XTAPI +VOID +SE::Descriptor::ReleaseSecurityDescriptor(IN PSECURITY_DESCRIPTOR Descriptor, + IN KPROCESSOR_MODE ProcessorMode, + IN BOOLEAN Force) +{ + /* Check if the descriptor should be released */ + if(((ProcessorMode == KernelMode) && (Force == TRUE)) || (ProcessorMode == UserMode)) + { + /* Ensure the descriptor is valid */ + if(Descriptor) + { + /* Free the descriptor */ + MM::Allocator::FreePool(Descriptor, TAG_SE_DESCRIPTOR); + } + } +} diff --git a/xtoskrnl/se/privileg.cc b/xtoskrnl/se/privileg.cc new file mode 100644 index 0000000..1ed8113 --- /dev/null +++ b/xtoskrnl/se/privileg.cc @@ -0,0 +1,109 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/se/privileg.cc + * DESCRIPTION: Privileges Management + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Performs a privilege check against a specific access token. + * + * @param Token + * Supplies a pointer to the access token being queried. + * + * @param Privileges + * Supplies a pointer to an array of privileges and their attributes. + * + * @param PrivilegeCount + * Supplies the number of privileges in the array. + * + * @param PrivilegeSet + * Supplies the control flags specifying how the privileges are evaluated. + * + * @param ProcessorMode + * Supplies the processor mode from which the request originated. + * + * @return This routine returns TRUE if the required privileges are held, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +SE::Privileges::CheckPrivilege(IN PTOKEN Token, + IN OUT PLUID_AND_ATTRIBUTES Privileges, + IN ULONG PrivilegeCount, + IN ULONG PrivilegeSet, + IN KPROCESSOR_MODE ProcessorMode) +{ + UNIMPLEMENTED; + + /* Return TRUE */ + return TRUE; +} + +/** + * Checks whether the specified privileges are held by the security context. + * + * @param RequiredPrivileges + * Supplies a pointer to the privilege set that specifies the privileges to check. + * + * @param SecurityContext + * Supplies a pointer to the security subject context representing the caller. + * + * @param ProcessorMode + * Supplies the processor mode of the caller. + * + * @return This routine returns TRUE if the required privileges are held, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTAPI +BOOLEAN +SE::Privileges::CheckPrivilege(IN OUT PPRIVILEGE_SET RequiredPrivileges, + IN PSECURITY_SUBJECT_CONTEXT SecurityContext, + IN KPROCESSOR_MODE ProcessorMode) +{ + PACCESS_TOKEN Token; + + /* Verify that an existing client token has a sufficient impersonation level */ + if((SecurityContext->ClientToken != NULLPTR) && (SecurityContext->ImpersonationLevel < SecurityImpersonation)) + { + /* The impersonation level is too low to perform privilege checks, return FALSE */ + return FALSE; + } + + /* Select the effective access token based on the presence of a client impersonation token */ + Token = SecurityContext->ClientToken ? SecurityContext->ClientToken : SecurityContext->PrimaryToken; + + /* Dispatch the privilege check and return the result */ + return CheckPrivilege((PTOKEN)Token, RequiredPrivileges->Privilege, RequiredPrivileges->PrivilegeCount, + RequiredPrivileges->Control, ProcessorMode); +} + +/** +* Checks if the current thread's access token holds a specific privilege. +* +* @param PrivilegeValue +* Supplies the locally unique identifier (LUID) of the privilege to check. +* +* @param ProcessorMode +* Supplies the processor mode from which the request originated. +* +* @return This routine returns TRUE if the privilege is held, or FALSE otherwise. +* +* @since XT 1.0 +*/ +XTAPI +BOOLEAN +SE::Privileges::CheckSinglePrivilege(LUID PrivilegeValue, + KPROCESSOR_MODE ProcessorMode) +{ + UNIMPLEMENTED; + + /* Return TRUE */ + return TRUE; +} diff --git a/xtoskrnl/xtoskrnl.spec b/xtoskrnl/xtoskrnl.spec index f5d47ff..6120265 100644 --- a/xtoskrnl/xtoskrnl.spec +++ b/xtoskrnl/xtoskrnl.spec @@ -65,6 +65,7 @@ @ stdcall RtlConvertToLargeIntegerUnsigned32(long) @ stdcall RtlCopyMemory(ptr ptr long) @ stdcall RtlCopyString(ptr ptr long) +@ stdcall RtlCopyUnicodeString(ptr ptr) @ stdcall RtlCopyWideString(ptr ptr long) @ stdcall RtlDivideLargeInteger(long long long ptr) @ stdcall RtlFindClearBits(ptr long long) @@ -75,6 +76,8 @@ @ stdcall RtlFindWideStringInsensitive(wstr wstr) @ stdcall RtlInitializeBitMap(ptr ptr long) @ stdcall RtlInitializeListHead(ptr) +@ stdcall RtlInitializeUnicodeString(ptr wstr) +@ stdcall RtlInitializeUnicodeStringEx(ptr wstr) @ stdcall RtlInsertHeadList(ptr ptr) @ stdcall RtlInsertTailList(ptr ptr) @ stdcall RtlListEmpty(ptr)