Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
f79c9023d8
|
|||
|
97703c7932
|
|||
|
2f5902119d
|
|||
|
7a10135731
|
|||
|
b0074637f8
|
|||
|
1a062ca05f
|
|||
|
c702152cca
|
|||
|
81c799e590
|
|||
|
cf0d7f0a40
|
|||
|
b0d2868f82
|
|||
|
32f0b747a1
|
|||
|
c57aa98923
|
|||
|
429e4ef6f1
|
|||
|
39928f2ef4
|
|||
|
51ec7e3bab
|
|||
|
f3ae70573c
|
|||
|
830f84ab26
|
|||
|
5a9df7ca86
|
|||
|
4bcdcda3a0
|
|||
|
7a27912dac
|
|||
|
cf4b91ac83
|
|||
|
36c3d92399
|
|||
|
6a2a35c008
|
|||
|
a9202f5b57
|
|||
|
4cbefe3a22
|
|||
|
3841ceaf5b
|
|||
|
e2eb784eef
|
|||
|
6078a5ba29
|
|||
|
663f5cd048
|
|||
|
5999906bf0
|
|||
|
1e0c1490fb
|
|||
|
5b0eebdb43
|
|||
|
9e64939de4
|
|||
|
b911670121
|
|||
|
d175a817a5
|
|||
|
b285bc7312
|
|||
|
c8cd198c4e
|
|||
|
95d45f5a0a
|
|||
|
766e4d9603
|
|||
|
a601fd0afa
|
|||
|
cc23e459e0
|
|||
|
d36b678ba1
|
|||
|
43265bcddb
|
|||
|
47d4069d6f
|
|||
|
904df63198
|
|||
|
1df971a71e
|
|||
|
2a413d5717
|
|||
|
9c2357dfe6
|
|||
|
f82562f450
|
|||
|
a33b63842a
|
|||
|
4256a312ae
|
|||
|
678a0f4f48
|
|||
|
7344c5ed4a
|
|||
|
537fbc8af4
|
|||
|
cf25af23d1
|
|||
|
f680830b53
|
|||
|
53a239958f
|
|||
|
f13326ffaf
|
|||
|
75e7760d04
|
|||
|
02d0f3f538
|
|||
|
e2a78389f2
|
|||
|
81fdf1f77a
|
|||
|
631f58bf72
|
|||
|
1d2d66fc83
|
|||
|
34aba8c7c7
|
|||
|
5e764a0d17
|
|||
|
65e86db731
|
|||
|
615d253bb4
|
|||
|
2fcbc7bee8
|
|||
|
2c14da997d
|
|||
|
a7c2182d4a
|
|||
|
0aabc206a1
|
|||
|
7d8b33390a
|
|||
|
5a5604c35d
|
|||
|
addf9addab
|
|||
|
f562aa0874
|
|||
|
19a9dfe7c6
|
|||
|
46594f1fc3
|
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -132,6 +132,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 +244,7 @@ typedef struct _CONTEXT
|
||||
USHORT SegFs;
|
||||
USHORT SegGs;
|
||||
USHORT SegSs;
|
||||
ULONG EFlags;
|
||||
ULONG Flags;
|
||||
ULONG64 Dr0;
|
||||
ULONG64 Dr1;
|
||||
ULONG64 Dr2;
|
||||
@@ -560,13 +572,27 @@ typedef struct _KPROCESSOR_CONTROL_BLOCK
|
||||
ULONG_PTR SetMember;
|
||||
CPU_IDENTIFICATION CpuId;
|
||||
KPROCESSOR_STATE ProcessorState;
|
||||
KSPIN_LOCK PrcbLock;
|
||||
KSPIN_LOCK_QUEUE LockQueue[MaximumLock];
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -154,6 +154,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 +304,7 @@ typedef struct _CONTEXT
|
||||
ULONG Ebp;
|
||||
ULONG Eip;
|
||||
ULONG SegCs;
|
||||
ULONG EFlags;
|
||||
ULONG Flags;
|
||||
ULONG Esp;
|
||||
ULONG SegSs;
|
||||
UCHAR ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
|
||||
@@ -519,13 +532,27 @@ typedef struct _KPROCESSOR_CONTROL_BLOCK
|
||||
ULONG_PTR SetMember;
|
||||
CPU_IDENTIFICATION CpuId;
|
||||
KPROCESSOR_STATE ProcessorState;
|
||||
KSPIN_LOCK PrcbLock;
|
||||
KSPIN_LOCK_QUEUE LockQueue[MaximumLock];
|
||||
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;
|
||||
|
||||
@@ -24,14 +24,30 @@
|
||||
/* 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
|
||||
|
||||
/* APC pending state length */
|
||||
#define KAPC_STATE_LENGTH (FIELD_OFFSET(KAPC_STATE, UserApcPending) + sizeof(BOOLEAN))
|
||||
|
||||
/* 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
|
||||
@@ -79,6 +95,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
|
||||
{
|
||||
@@ -212,6 +237,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
|
||||
{
|
||||
@@ -263,6 +337,15 @@ typedef struct _EXCEPTION_RECORD
|
||||
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
||||
} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
|
||||
|
||||
/* Extended affinity structure definition */
|
||||
typedef struct _KAFFINITY_MAP
|
||||
{
|
||||
USHORT Count;
|
||||
USHORT Size;
|
||||
ULONG Reserved;
|
||||
KAFFINITY Bitmap[];
|
||||
} KAFFINITY_MAP, *PKAFFINITY_MAP;
|
||||
|
||||
/* Asynchronous Procedure Call (APC) object structure definition */
|
||||
typedef struct _KAPC
|
||||
{
|
||||
@@ -419,7 +502,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 +511,6 @@ typedef struct _KPROCESS
|
||||
PVOID VdmTrapHandler;
|
||||
LIST_ENTRY ThreadListHead;
|
||||
KSPIN_LOCK ProcessLock;
|
||||
KAFFINITY Affinity;
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -482,7 +565,6 @@ typedef struct _KTHREAD
|
||||
PVOID StackBase;
|
||||
PVOID StackLimit;
|
||||
KSPIN_LOCK ThreadLock;
|
||||
|
||||
ULONG ContextSwitches;
|
||||
VOLATILE UCHAR State;
|
||||
UCHAR NpxState;
|
||||
@@ -507,7 +589,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 +627,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,7 +645,7 @@ typedef struct _KTHREAD
|
||||
LIST_ENTRY ThreadListEntry;
|
||||
UCHAR LargeStack;
|
||||
UCHAR PowerState;
|
||||
UCHAR NpxIrql;
|
||||
UCHAR NpxRunLevel;
|
||||
UCHAR Spare5;
|
||||
BOOLEAN AutoAlignment;
|
||||
UCHAR Iopl;
|
||||
|
||||
@@ -99,14 +99,20 @@ typedef struct _M128
|
||||
/* Dispatcher object header structure definition */
|
||||
typedef struct _DISPATCHER_HEADER
|
||||
{
|
||||
UCHAR Type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
UCHAR Type;
|
||||
UCHAR Absolute;
|
||||
UCHAR NpxIrql;
|
||||
};
|
||||
UCHAR Size;
|
||||
union {
|
||||
UCHAR Inserted;
|
||||
BOOLEAN DebugActive;
|
||||
};
|
||||
};
|
||||
VOLATILE LONG Lock;
|
||||
};
|
||||
LONG SignalState;
|
||||
LIST_ENTRY WaitListHead;
|
||||
} DISPATCHER_HEADER, *PDISPATCHER_HEADER;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
/* XT status code definitions */
|
||||
#define STATUS_SUCCESS ((XTSTATUS) 0x00000000L)
|
||||
#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,6 +60,7 @@
|
||||
#define STATUS_INVALID_PARAMETER ((XTSTATUS) 0xC000000DL)
|
||||
#define STATUS_END_OF_FILE ((XTSTATUS) 0xC0000011L)
|
||||
#define STATUS_NO_MEMORY ((XTSTATUS) 0xC0000017L)
|
||||
#define STATUS_BUFFER_TOO_SMALL ((XTSTATUS) 0xC0000023L)
|
||||
#define STATUS_PORT_DISCONNECTED ((XTSTATUS) 0xC0000037L)
|
||||
#define STATUS_CRC_ERROR ((XTSTATUS) 0xC000003FL)
|
||||
#define STATUS_FLOAT_OVERFLOW ((XTSTATUS) 0xC0000091L)
|
||||
|
||||
@@ -43,6 +43,7 @@ typedef enum _EFI_UART_STOP_BITS_TYPE EFI_UART_STOP_BITS_TYPE, *PEFI_UART_STOP_B
|
||||
typedef enum _EFI_UNIVERSA_GRAPHICS_BLT_OPERATION EFI_UNIVERSA_GRAPHICS_BLT_OPERATION, *PEFI_UNIVERSA_GRAPHICS_BLT_OPERATION;
|
||||
typedef enum _HAL_APIC_MODE HAL_APIC_MODE, *PHAL_APIC_MODE;
|
||||
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,6 +52,7 @@ 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;
|
||||
@@ -250,6 +252,7 @@ typedef struct _GENERIC_ADDRESS GENERIC_ADDRESS, *PGENERIC_ADDRESS;
|
||||
typedef struct _GUID GUID, *PGUID;
|
||||
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 _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;
|
||||
|
||||
@@ -31,13 +31,16 @@ 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
|
||||
@@ -46,6 +49,7 @@ list(APPEND XTOSKRNL_SOURCE
|
||||
${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
|
||||
@@ -55,6 +59,7 @@ list(APPEND XTOSKRNL_SOURCE
|
||||
${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
|
||||
@@ -76,6 +81,8 @@ list(APPEND XTOSKRNL_SOURCE
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/pool.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/pte.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/po/idle.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ps/process.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/ps/thread.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/dispatch.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/exsup.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/rtl/${ARCH}/intrin.cc
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -24,7 +24,6 @@ VOID
|
||||
HL::Cpu::InitializeProcessor(VOID)
|
||||
{
|
||||
PKPROCESSOR_BLOCK ProcessorBlock;
|
||||
KAFFINITY Affinity;
|
||||
|
||||
/* Get current processor block */
|
||||
ProcessorBlock = KE::Processor::GetCurrentProcessorBlock();
|
||||
@@ -33,17 +32,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 +85,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 +136,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 +190,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 +249,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -18,10 +18,11 @@ namespace HL
|
||||
class Cpu
|
||||
{
|
||||
private:
|
||||
STATIC KAFFINITY ActiveProcessors;
|
||||
STATIC PKAFFINITY_MAP ActiveProcessors;
|
||||
|
||||
public:
|
||||
STATIC XTAPI VOID InitializeProcessor(VOID);
|
||||
STATIC XTAPI XTSTATUS InitializeProcessorAffinity(VOID);
|
||||
STATIC XTAPI XTSTATUS StartAllProcessors(VOID);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
|
||||
#include <kd/dbg.hh>
|
||||
#include <kd/dbgio.hh>
|
||||
#include <kd/debug.hh>
|
||||
|
||||
#endif /* __XTOSKRNL_KD_HH */
|
||||
|
||||
38
xtoskrnl/includes/kd/debug.hh
Normal file
38
xtoskrnl/includes/kd/debug.hh
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_KD_DEBUG_HH
|
||||
#define __XTOSKRNL_KD_DEBUG_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* 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 */
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
#include <ke/affinity.hh>
|
||||
#include <ke/apc.hh>
|
||||
#include <ke/bootinfo.hh>
|
||||
#include <ke/crash.hh>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <ke/dpc.hh>
|
||||
#include <ke/event.hh>
|
||||
#include <ke/guard.hh>
|
||||
#include <ke/ipi.hh>
|
||||
#include <ke/kprocess.hh>
|
||||
#include <ke/krnlinit.hh>
|
||||
#include <ke/kthread.hh>
|
||||
@@ -28,6 +30,7 @@
|
||||
#include <ke/shdata.hh>
|
||||
#include <ke/spinlock.hh>
|
||||
#include <ke/sysres.hh>
|
||||
#include <ke/sysserv.hh>
|
||||
#include <ke/systime.hh>
|
||||
#include <ke/timer.hh>
|
||||
|
||||
|
||||
49
xtoskrnl/includes/ke/affinity.hh
Normal file
49
xtoskrnl/includes/ke/affinity.hh
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_KE_AFFINITY_HH
|
||||
#define __XTOSKRNL_KE_AFFINITY_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* 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 */
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ 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 VOID UpdateRunTime(IN PKTRAP_FRAME TrapFrame,
|
||||
|
||||
@@ -19,18 +19,27 @@ namespace KE
|
||||
{
|
||||
private:
|
||||
KSPIN_LOCK_QUEUE_LEVEL QueuedLockLevel;
|
||||
BOOLEAN Owned;
|
||||
|
||||
public:
|
||||
QueuedSpinLockGuard(IN OUT KSPIN_LOCK_QUEUE_LEVEL LockLevel)
|
||||
QueuedSpinLockGuard(IN OUT KSPIN_LOCK_QUEUE_LEVEL LockLevel,
|
||||
IN BOOLEAN Acquire = TRUE)
|
||||
{
|
||||
QueuedLockLevel = LockLevel;
|
||||
Owned = Acquire;
|
||||
if(Owned)
|
||||
{
|
||||
KE::SpinLock::AcquireQueuedSpinLock(QueuedLockLevel);
|
||||
}
|
||||
}
|
||||
|
||||
~QueuedSpinLockGuard()
|
||||
{
|
||||
if(Owned)
|
||||
{
|
||||
KE::SpinLock::ReleaseQueuedSpinLock(QueuedLockLevel);
|
||||
}
|
||||
}
|
||||
|
||||
QueuedSpinLockGuard(const QueuedSpinLockGuard&) = delete;
|
||||
QueuedSpinLockGuard& operator=(const QueuedSpinLockGuard&) = delete;
|
||||
@@ -40,18 +49,27 @@ 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;
|
||||
Owned = Acquire;
|
||||
if(Owned)
|
||||
{
|
||||
KE::SpinLock::AcquireSpinLock(Lock);
|
||||
}
|
||||
}
|
||||
|
||||
~SpinLockGuard()
|
||||
{
|
||||
if(Owned)
|
||||
{
|
||||
KE::SpinLock::ReleaseSpinLock(Lock);
|
||||
}
|
||||
}
|
||||
|
||||
SpinLockGuard(const SpinLockGuard&) = delete;
|
||||
SpinLockGuard& operator=(const SpinLockGuard&) = delete;
|
||||
|
||||
31
xtoskrnl/includes/ke/ipi.hh
Normal file
31
xtoskrnl/includes/ke/ipi.hh
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_KE_IPI_HH
|
||||
#define __XTOSKRNL_KE_IPI_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* 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 */
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace KE
|
||||
|
||||
private:
|
||||
STATIC XTAPI VOID BootstrapKernel(VOID);
|
||||
STATIC XTAPI VOID InitializeInterruptHandlers(VOID);
|
||||
STATIC XTAPI VOID InitializeKernel(VOID);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ namespace KE
|
||||
|
||||
public:
|
||||
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,
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -27,18 +27,27 @@ namespace KE
|
||||
{
|
||||
private:
|
||||
KRUNLEVEL PreviousRunLevel;
|
||||
BOOLEAN Switched;
|
||||
|
||||
public:
|
||||
LowerRunLevel(KRUNLEVEL RunLevel)
|
||||
LowerRunLevel(IN KRUNLEVEL RunLevel,
|
||||
IN BOOLEAN ChangeLevel = TRUE)
|
||||
{
|
||||
PreviousRunLevel = KE::RunLevel::GetCurrentRunLevel();
|
||||
Switched = ChangeLevel;
|
||||
if(Switched)
|
||||
{
|
||||
KE::RunLevel::LowerRunLevel(RunLevel);
|
||||
}
|
||||
}
|
||||
|
||||
~LowerRunLevel()
|
||||
{
|
||||
if(Switched)
|
||||
{
|
||||
KE::RunLevel::RaiseRunLevel(PreviousRunLevel);
|
||||
}
|
||||
}
|
||||
|
||||
LowerRunLevel(const LowerRunLevel&) = delete;
|
||||
LowerRunLevel& operator=(const LowerRunLevel&) = delete;
|
||||
@@ -48,18 +57,27 @@ namespace KE
|
||||
{
|
||||
private:
|
||||
KRUNLEVEL PreviousRunLevel;
|
||||
BOOLEAN Switched;
|
||||
|
||||
public:
|
||||
RaiseRunLevel(KRUNLEVEL RunLevel)
|
||||
RaiseRunLevel(IN KRUNLEVEL RunLevel,
|
||||
IN BOOLEAN ChangeLevel = TRUE)
|
||||
{
|
||||
PreviousRunLevel = KE::RunLevel::GetCurrentRunLevel();
|
||||
Switched = ChangeLevel;
|
||||
if(Switched)
|
||||
{
|
||||
KE::RunLevel::RaiseRunLevel(RunLevel);
|
||||
}
|
||||
}
|
||||
|
||||
~RaiseRunLevel()
|
||||
{
|
||||
if(Switched)
|
||||
{
|
||||
KE::RunLevel::LowerRunLevel(PreviousRunLevel);
|
||||
}
|
||||
}
|
||||
|
||||
RaiseRunLevel(const RaiseRunLevel&) = delete;
|
||||
RaiseRunLevel& operator=(const RaiseRunLevel&) = delete;
|
||||
|
||||
25
xtoskrnl/includes/ke/sysserv.hh
Normal file
25
xtoskrnl/includes/ke/sysserv.hh
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_KE_SYSSERV_HH
|
||||
#define __XTOSKRNL_KE_SYSSERV_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* Kernel Library */
|
||||
namespace KE
|
||||
{
|
||||
class SystemServices
|
||||
{
|
||||
public:
|
||||
STATIC XTAPI PKSERVICE_DESCRIPTOR_TABLE GetSystemServicesDescriptorTable(VOID);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __XTOSKRNL_KE_SYSSERV_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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* Runtime Library */
|
||||
/* Power Management */
|
||||
namespace PO
|
||||
{
|
||||
class Idle
|
||||
|
||||
18
xtoskrnl/includes/ps.hh
Normal file
18
xtoskrnl/includes/ps.hh
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/includes/ps.hh
|
||||
* DESCRIPTION: Process and thread management
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_PS_HH
|
||||
#define __XTOSKRNL_PS_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
#include <ps/process.hh>
|
||||
#include <ps/thread.hh>
|
||||
|
||||
|
||||
#endif /* __XTOSKRNL_PS_HH */
|
||||
25
xtoskrnl/includes/ps/process.hh
Normal file
25
xtoskrnl/includes/ps/process.hh
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/includes/ps/process.hh
|
||||
* DESCRIPTION: Process Management
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_PS_PROCESS_HH
|
||||
#define __XTOSKRNL_PS_PROCESS_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* Process and thread management */
|
||||
namespace PS
|
||||
{
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
STATIC XTAPI XTSTATUS CreateIdleProcess(IN PKPROCESSOR_CONTROL_BLOCK Prcb);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __XTOSKRNL_PS_PROCESS_HH */
|
||||
26
xtoskrnl/includes/ps/thread.hh
Normal file
26
xtoskrnl/includes/ps/thread.hh
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/includes/ps/thread.hh
|
||||
* DESCRIPTION: Thread Management
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __XTOSKRNL_PS_THREAD_HH
|
||||
#define __XTOSKRNL_PS_THREAD_HH
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* Process and thread management */
|
||||
namespace PS
|
||||
{
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
STATIC XTAPI XTSTATUS CreateIdleThread(IN PKPROCESSOR_CONTROL_BLOCK Prcb,
|
||||
IN PVOID Stack);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __XTOSKRNL_PS_THREAD_HH */
|
||||
@@ -24,4 +24,5 @@
|
||||
#include <ke.hh>
|
||||
#include <mm.hh>
|
||||
#include <po.hh>
|
||||
#include <ps.hh>
|
||||
#include <rtl.hh>
|
||||
|
||||
36
xtoskrnl/kd/amd64/debug.cc
Normal file
36
xtoskrnl/kd/amd64/debug.cc
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@@ -9,6 +9,9 @@
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* Debugger active flag */
|
||||
BOOLEAN KD::Debugger::Active;
|
||||
|
||||
/* Debug I/O spinlock */
|
||||
KSPIN_LOCK KD::DebugIo::DebugIoLock;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
74
xtoskrnl/kd/debug.cc
Normal file
74
xtoskrnl/kd/debug.cc
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
36
xtoskrnl/kd/i686/debug.cc
Normal file
36
xtoskrnl/kd/i686/debug.cc
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
562
xtoskrnl/ke/affinity.cc
Normal file
562
xtoskrnl/ke/affinity.cc
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,65 @@ 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_DPC, KE::Dispatcher::HandleDispatchInterrupt);
|
||||
HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_IPI, KE::Ipi::HandleIpiInterrupt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +221,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),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,234 @@
|
||||
* FILE: xtoskrnl/ke/panic.cc
|
||||
* DESCRIPTION: System shutdown and kernel panic mechanism
|
||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
* Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -4,11 +4,82 @@
|
||||
* FILE: xtoskrnl/ke/dispatch.cc
|
||||
* DESCRIPTION: Kernel Thread Dispatcher
|
||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
* Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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 +100,25 @@ 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)
|
||||
{
|
||||
/* End the interrupt */
|
||||
HL::Pic::SendEoi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the runtime quantum of the currently executing thread and handles preemption.
|
||||
*
|
||||
@@ -47,4 +137,101 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,10 +110,9 @@ 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)),
|
||||
[SwExceptionList] "i" (FIELD_OFFSET(KSWITCH_FRAME, ExceptionList)),
|
||||
@@ -128,7 +121,4 @@ KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread,
|
||||
[ThrdStack] "i" (FIELD_OFFSET(KTHREAD, KernelStack)),
|
||||
[ThrdSwapBusy] "i" (FIELD_OFFSET(KTHREAD, SwapBusy))
|
||||
: "cc", "memory");
|
||||
|
||||
/* Return the APC status */
|
||||
return PendingApc;
|
||||
}
|
||||
|
||||
@@ -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,65 @@ 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_DPC, KE::Dispatcher::HandleDispatchInterrupt);
|
||||
HL::Irq::RegisterSystemInterruptHandler(APIC_VECTOR_IPI, KE::Ipi::HandleIpiInterrupt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,7 +66,7 @@ KE::KThread::InitializeThreadContext(IN PKTHREAD Thread,
|
||||
|
||||
/* 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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
247
xtoskrnl/ke/ipi.cc
Normal file
247
xtoskrnl/ke/ipi.cc
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,21 @@
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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 = MAXSHORT;
|
||||
Process->Quantum = THREAD_QUANTUM;
|
||||
|
||||
/* Set IOPM offset */
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/* 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)
|
||||
|
||||
@@ -23,6 +23,76 @@ KE::KThread::GetInitialThread(VOID)
|
||||
return &InitialThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -75,8 +145,10 @@ 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);
|
||||
@@ -99,15 +171,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 +207,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 +226,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);
|
||||
@@ -200,7 +277,7 @@ KE::KThread::InitializeThread(IN PKPROCESS Process,
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
KE::KThread::StartThread(IN PKTHREAD Thread)
|
||||
KE::KThread::StartThread(IN OUT PKTHREAD Thread)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
25
xtoskrnl/ke/sysserv.cc
Normal file
25
xtoskrnl/ke/sysserv.cc
Normal file
@@ -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 <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -152,6 +152,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 +163,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 +177,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 +187,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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* FILE: xtoskrnl/ke/timer.cc
|
||||
* DESCRIPTION: Kernel timer object support
|
||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
* Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
51
xtoskrnl/ps/process.cc
Normal file
51
xtoskrnl/ps/process.cc
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/po/process.cc
|
||||
* DESCRIPTION: Process Management
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
63
xtoskrnl/ps/thread.cc
Normal file
63
xtoskrnl/ps/thread.cc
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/po/thread.cc
|
||||
* DESCRIPTION: Thread Management
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user