Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
29368a0dd8
|
|||
|
8ee97ac0ae
|
|||
|
6bbeb657ea
|
|||
|
c824e15cdb
|
|||
|
38b2e7a1ed
|
|||
|
efff262fb5
|
|||
|
14cbd63b01
|
|||
|
63d18aad1e
|
|||
|
ed52d421ea
|
|||
|
6df6a012d2
|
|||
|
ac675b037e
|
|||
|
ca4f3acc0e
|
|||
|
5b7761fe7d
|
|||
|
7a2a27b1b9
|
|||
|
1cff58c106
|
|||
|
9185ceade6
|
|||
|
908bc87b06
|
|||
|
6b852556a5
|
|||
|
ae18468bad
|
|||
|
42bbdc9b26
|
|||
|
b1ecdc3439
|
|||
|
fd7e18989d
|
|||
|
757eac08c6
|
|||
|
760e58f993
|
|||
|
c8868ead47
|
|||
|
58981e0087
|
|||
|
06635ed014
|
|||
|
5a92173586
|
@@ -80,4 +80,12 @@ GenerateAssemblyDefinitions(VOID)
|
|||||||
/* Generate KTRAP_FRAME size and REGISTERS_SIZE */
|
/* Generate KTRAP_FRAME size and REGISTERS_SIZE */
|
||||||
ADK_SIZE(KTRAP_FRAME);
|
ADK_SIZE(KTRAP_FRAME);
|
||||||
ADK_SIZE_FROM(REGISTERS_SIZE, KTRAP_FRAME, Rax);
|
ADK_SIZE_FROM(REGISTERS_SIZE, KTRAP_FRAME, Rax);
|
||||||
|
|
||||||
|
/* Generate PROCESSOR_START_BLOCK offsets */
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Cr3);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Cr4);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, EntryPoint);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, ProcessorStructures);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Stack);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Started);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,4 +54,12 @@ GenerateAssemblyDefinitions(VOID)
|
|||||||
/* Generate KTRAP_FRAME size and REGISTERS_SIZE */
|
/* Generate KTRAP_FRAME size and REGISTERS_SIZE */
|
||||||
ADK_SIZE(KTRAP_FRAME);
|
ADK_SIZE(KTRAP_FRAME);
|
||||||
ADK_SIZE_FROM(REGISTERS_SIZE, KTRAP_FRAME, Eax);
|
ADK_SIZE_FROM(REGISTERS_SIZE, KTRAP_FRAME, Eax);
|
||||||
|
|
||||||
|
/* Generate PROCESSOR_START_BLOCK offsets */
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Cr3);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Cr4);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, EntryPoint);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, ProcessorStructures);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Stack);
|
||||||
|
ADK_OFFSET(PROCESSOR_START_BLOCK, Started);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -430,7 +430,9 @@ typedef VOID (*PINTERRUPT_HANDLER)(PKTRAP_FRAME TrapFrame);
|
|||||||
/* Processor identification information */
|
/* Processor identification information */
|
||||||
typedef struct _CPU_IDENTIFICATION
|
typedef struct _CPU_IDENTIFICATION
|
||||||
{
|
{
|
||||||
|
ULONGLONG ExtendedFeatureBits;
|
||||||
USHORT Family;
|
USHORT Family;
|
||||||
|
ULONGLONG FeatureBits;
|
||||||
USHORT Model;
|
USHORT Model;
|
||||||
USHORT Stepping;
|
USHORT Stepping;
|
||||||
CPU_VENDOR Vendor;
|
CPU_VENDOR Vendor;
|
||||||
|
|||||||
@@ -69,6 +69,62 @@
|
|||||||
#define AMD64_INTERRUPT_GATE 0xE
|
#define AMD64_INTERRUPT_GATE 0xE
|
||||||
#define AMD64_TRAP_GATE 0xF
|
#define AMD64_TRAP_GATE 0xF
|
||||||
|
|
||||||
|
/* Kernel CPU Standard Features */
|
||||||
|
#define KCF_VME (1ULL << 0) /* Virtual 8086 Mode Enhancements */
|
||||||
|
#define KCF_LARGE_PAGE (1ULL << 1) /* Page Size Extensions */
|
||||||
|
#define KCF_RDTSC (1ULL << 2) /* Time Stamp Counter */
|
||||||
|
#define KCF_PAE (1ULL << 3) /* Physical Address Extension */
|
||||||
|
#define KCF_MCE (1ULL << 4) /* Machine Check Exception */
|
||||||
|
#define KCF_CMPXCHG8B (1ULL << 5) /* CMPXCHG8B Instruction */
|
||||||
|
#define KCF_APIC (1ULL << 6) /* APIC On-Chip */
|
||||||
|
#define KCF_FAST_SYSCALL (1ULL << 7) /* SYSENTER/SYSEXIT Instructions */
|
||||||
|
#define KCF_MTRR (1ULL << 8) /* Memory Type Range Registers */
|
||||||
|
#define KCF_GLOBAL_PAGE (1ULL << 9) /* Page Global Enable */
|
||||||
|
#define KCF_MCA (1ULL << 10) /* Machine Check Architecture */
|
||||||
|
#define KCF_CMOV (1ULL << 11) /* Conditional Move Instructions */
|
||||||
|
#define KCF_PAT (1ULL << 12) /* Page Attribute Table */
|
||||||
|
#define KCF_PSE36 (1ULL << 13) /* 36-bit Page Size Extension */
|
||||||
|
#define KCF_CLFLUSH (1ULL << 14) /* CLFLUSH Instruction */
|
||||||
|
#define KCF_FXSR (1ULL << 15) /* FXSAVE/FXRSTOR Instructions */
|
||||||
|
#define KCF_ACPI (1ULL << 16) /* Thermal Monitor and Software Controlled Clock */
|
||||||
|
#define KCF_MMX (1ULL << 17) /* MMX Technology */
|
||||||
|
#define KCF_SSE (1ULL << 18) /* Streaming SIMD Extensions */
|
||||||
|
#define KCF_SSE2 (1ULL << 19) /* Streaming SIMD Extensions 2 */
|
||||||
|
#define KCF_SMT (1ULL << 20) /* Hyper-Threading Technology */
|
||||||
|
#define KCF_SSE3 (1ULL << 21) /* Streaming SIMD Extensions 3 */
|
||||||
|
#define KCF_VMX (1ULL << 22) /* Intel Virtual Machine Extensions */
|
||||||
|
#define KCF_SSSE3 (1ULL << 23) /* Supplemental SSE3 Instructions */
|
||||||
|
#define KCF_SSE41 (1ULL << 24) /* SSE4.1 Instructions */
|
||||||
|
#define KCF_SSE42 (1ULL << 25) /* SSE4.2 Instructions */
|
||||||
|
#define KCF_X2APIC (1ULL << 26) /* x2APIC Support */
|
||||||
|
#define KCF_POPCNT (1ULL << 27) /* POPCNT Instruction */
|
||||||
|
#define KCF_TSC_DEADLINE (1ULL << 28) /* TSC Deadline Timer */
|
||||||
|
#define KCF_AES (1ULL << 29) /* AES-NI Instruction Set */
|
||||||
|
#define KCF_XSAVE (1ULL << 30) /* XSAVE/XRSTOR Instructions */
|
||||||
|
#define KCF_AVX (1ULL << 31) /* Advanced Vector Extensions */
|
||||||
|
#define KCF_RDRAND (1ULL << 32) /* RDRAND Instruction */
|
||||||
|
#define KCF_FSGSBASE (1ULL << 33) /* RDFSBASE/WRFSBASE Instructions */
|
||||||
|
#define KCF_AVX2 (1ULL << 34) /* AVX2 Instructions */
|
||||||
|
#define KCF_SMEP (1ULL << 35) /* Supervisor Mode Execution Prevention */
|
||||||
|
#define KCF_RDSEED (1ULL << 36) /* RDSEED Instruction */
|
||||||
|
#define KCF_SMAP (1ULL << 37) /* Supervisor Mode Access Prevention */
|
||||||
|
#define KCF_SHA (1ULL << 38) /* SHA Extensions */
|
||||||
|
#define KCF_LA57 (1ULL << 39) /* 57-bit Linear Addresses */
|
||||||
|
#define KCF_ARAT (1ULL << 40) /* Always Running APIC Timer */
|
||||||
|
|
||||||
|
/* Kernel CPU Extended Features */
|
||||||
|
#define KCF_SVM (1ULL << 0) /* AMD Secure Virtual Machine */
|
||||||
|
#define KCF_SSE4A (1ULL << 1) /* SSE4A Instructions */
|
||||||
|
#define KCF_FMA4 (1ULL << 2) /* FMA4 Instructions */
|
||||||
|
#define KCF_TOPOEXT (1ULL << 3) /* AMD Topology Extensions */
|
||||||
|
#define KCF_SYSCALL (1ULL << 4) /* SYSCALL/SYSRET Instructions */
|
||||||
|
#define KCF_NX_BIT (1ULL << 5) /* No-Execute Page Protection */
|
||||||
|
#define KCF_RDTSCP (1ULL << 6) /* RDTSCP Instruction */
|
||||||
|
#define KCF_64BIT (1ULL << 7) /* Long Mode Support */
|
||||||
|
#define KCF_3DNOW_EXT (1ULL << 8) /* 3DNow! Extensions */
|
||||||
|
#define KCF_3DNOW (1ULL << 9) /* 3DNow! Instructions */
|
||||||
|
#define KCF_INVARIANT_TSC (1ULL << 10) /* Invariant Time Stamp Counter */
|
||||||
|
|
||||||
/* Context control flags */
|
/* Context control flags */
|
||||||
#define CONTEXT_ARCHITECTURE 0x00100000
|
#define CONTEXT_ARCHITECTURE 0x00100000
|
||||||
#define CONTEXT_CONTROL (CONTEXT_ARCHITECTURE | 0x01)
|
#define CONTEXT_CONTROL (CONTEXT_ARCHITECTURE | 0x01)
|
||||||
@@ -118,8 +174,8 @@
|
|||||||
#define KERNEL_STACK_GUARD_PAGES 1
|
#define KERNEL_STACK_GUARD_PAGES 1
|
||||||
|
|
||||||
/* Processor structures size */
|
/* Processor structures size */
|
||||||
#define KPROCESSOR_STRUCTURES_SIZE ((2 * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + sizeof(KTSS) + \
|
#define KPROCESSOR_STRUCTURES_SIZE ((KERNEL_STACKS * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + \
|
||||||
sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
|
sizeof(KTSS) + sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
|
||||||
|
|
||||||
/* Kernel frames */
|
/* Kernel frames */
|
||||||
#define KEXCEPTION_FRAME_SIZE sizeof(KEXCEPTION_FRAME)
|
#define KEXCEPTION_FRAME_SIZE sizeof(KEXCEPTION_FRAME)
|
||||||
@@ -470,11 +526,22 @@ typedef struct _KSPECIAL_REGISTERS
|
|||||||
ULONG64 MsrSyscallMask;
|
ULONG64 MsrSyscallMask;
|
||||||
} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS;
|
} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS;
|
||||||
|
|
||||||
|
/* Processor start block structure definition */
|
||||||
|
typedef struct _PROCESSOR_START_BLOCK
|
||||||
|
{
|
||||||
|
ULONG_PTR Cr3;
|
||||||
|
ULONG_PTR Cr4;
|
||||||
|
PVOID EntryPoint;
|
||||||
|
PVOID ProcessorStructures;
|
||||||
|
PVOID Stack;
|
||||||
|
BOOLEAN Started;
|
||||||
|
} PROCESSOR_START_BLOCK, *PPROCESSOR_START_BLOCK;
|
||||||
|
|
||||||
/* Processor state frame structure definition */
|
/* Processor state frame structure definition */
|
||||||
typedef struct _KPROCESSOR_STATE
|
typedef struct _KPROCESSOR_STATE
|
||||||
{
|
{
|
||||||
KSPECIAL_REGISTERS SpecialRegisters;
|
|
||||||
CONTEXT ContextFrame;
|
CONTEXT ContextFrame;
|
||||||
|
KSPECIAL_REGISTERS SpecialRegisters;
|
||||||
} KPROCESSOR_STATE, *PKPROCESSOR_STATE;
|
} KPROCESSOR_STATE, *PKPROCESSOR_STATE;
|
||||||
|
|
||||||
/* Processor Control Block (PRCB) structure definition */
|
/* Processor Control Block (PRCB) structure definition */
|
||||||
@@ -524,6 +591,8 @@ typedef struct _KPROCESSOR_BLOCK
|
|||||||
KAFFINITY SetMember;
|
KAFFINITY SetMember;
|
||||||
ULONG StallScaleFactor;
|
ULONG StallScaleFactor;
|
||||||
UCHAR CpuNumber;
|
UCHAR CpuNumber;
|
||||||
|
ULONG HardwareId;
|
||||||
|
VOLATILE BOOLEAN Started;
|
||||||
PINTERRUPT_HANDLER InterruptDispatchTable[256];
|
PINTERRUPT_HANDLER InterruptDispatchTable[256];
|
||||||
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;
|
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;
|
||||||
|
|
||||||
|
|||||||
@@ -395,7 +395,9 @@ typedef VOID (*PINTERRUPT_HANDLER)(PKTRAP_FRAME TrapFrame);
|
|||||||
/* Processor identification information */
|
/* Processor identification information */
|
||||||
typedef struct _CPU_IDENTIFICATION
|
typedef struct _CPU_IDENTIFICATION
|
||||||
{
|
{
|
||||||
|
ULONGLONG ExtendedFeatureBits;
|
||||||
USHORT Family;
|
USHORT Family;
|
||||||
|
ULONGLONG FeatureBits;
|
||||||
USHORT Model;
|
USHORT Model;
|
||||||
USHORT Stepping;
|
USHORT Stepping;
|
||||||
CPU_VENDOR Vendor;
|
CPU_VENDOR Vendor;
|
||||||
|
|||||||
@@ -90,6 +90,62 @@
|
|||||||
#define I686_INTERRUPT_GATE 0xE
|
#define I686_INTERRUPT_GATE 0xE
|
||||||
#define I686_TRAP_GATE 0xF
|
#define I686_TRAP_GATE 0xF
|
||||||
|
|
||||||
|
/* Kernel CPU Standard Features */
|
||||||
|
#define KCF_VME (1ULL << 0) /* Virtual 8086 Mode Enhancements */
|
||||||
|
#define KCF_LARGE_PAGE (1ULL << 1) /* Page Size Extensions */
|
||||||
|
#define KCF_RDTSC (1ULL << 2) /* Time Stamp Counter */
|
||||||
|
#define KCF_PAE (1ULL << 3) /* Physical Address Extension */
|
||||||
|
#define KCF_MCE (1ULL << 4) /* Machine Check Exception */
|
||||||
|
#define KCF_CMPXCHG8B (1ULL << 5) /* CMPXCHG8B Instruction */
|
||||||
|
#define KCF_APIC (1ULL << 6) /* APIC On-Chip */
|
||||||
|
#define KCF_FAST_SYSCALL (1ULL << 7) /* SYSENTER/SYSEXIT Instructions */
|
||||||
|
#define KCF_MTRR (1ULL << 8) /* Memory Type Range Registers */
|
||||||
|
#define KCF_GLOBAL_PAGE (1ULL << 9) /* Page Global Enable */
|
||||||
|
#define KCF_MCA (1ULL << 10) /* Machine Check Architecture */
|
||||||
|
#define KCF_CMOV (1ULL << 11) /* Conditional Move Instructions */
|
||||||
|
#define KCF_PAT (1ULL << 12) /* Page Attribute Table */
|
||||||
|
#define KCF_PSE36 (1ULL << 13) /* 36-bit Page Size Extension */
|
||||||
|
#define KCF_CLFLUSH (1ULL << 14) /* CLFLUSH Instruction */
|
||||||
|
#define KCF_FXSR (1ULL << 15) /* FXSAVE/FXRSTOR Instructions */
|
||||||
|
#define KCF_ACPI (1ULL << 16) /* Thermal Monitor and Software Controlled Clock */
|
||||||
|
#define KCF_MMX (1ULL << 17) /* MMX Technology */
|
||||||
|
#define KCF_SSE (1ULL << 18) /* Streaming SIMD Extensions */
|
||||||
|
#define KCF_SSE2 (1ULL << 19) /* Streaming SIMD Extensions 2 */
|
||||||
|
#define KCF_SMT (1ULL << 20) /* Hyper-Threading Technology */
|
||||||
|
#define KCF_SSE3 (1ULL << 21) /* Streaming SIMD Extensions 3 */
|
||||||
|
#define KCF_VMX (1ULL << 22) /* Intel Virtual Machine Extensions */
|
||||||
|
#define KCF_SSSE3 (1ULL << 23) /* Supplemental SSE3 Instructions */
|
||||||
|
#define KCF_SSE41 (1ULL << 24) /* SSE4.1 Instructions */
|
||||||
|
#define KCF_SSE42 (1ULL << 25) /* SSE4.2 Instructions */
|
||||||
|
#define KCF_X2APIC (1ULL << 26) /* x2APIC Support */
|
||||||
|
#define KCF_POPCNT (1ULL << 27) /* POPCNT Instruction */
|
||||||
|
#define KCF_TSC_DEADLINE (1ULL << 28) /* TSC Deadline Timer */
|
||||||
|
#define KCF_AES (1ULL << 29) /* AES-NI Instruction Set */
|
||||||
|
#define KCF_XSAVE (1ULL << 30) /* XSAVE/XRSTOR Instructions */
|
||||||
|
#define KCF_AVX (1ULL << 31) /* Advanced Vector Extensions */
|
||||||
|
#define KCF_RDRAND (1ULL << 32) /* RDRAND Instruction */
|
||||||
|
#define KCF_FSGSBASE (1ULL << 33) /* RDFSBASE/WRFSBASE Instructions */
|
||||||
|
#define KCF_AVX2 (1ULL << 34) /* AVX2 Instructions */
|
||||||
|
#define KCF_SMEP (1ULL << 35) /* Supervisor Mode Execution Prevention */
|
||||||
|
#define KCF_RDSEED (1ULL << 36) /* RDSEED Instruction */
|
||||||
|
#define KCF_SMAP (1ULL << 37) /* Supervisor Mode Access Prevention */
|
||||||
|
#define KCF_SHA (1ULL << 38) /* SHA Extensions */
|
||||||
|
#define KCF_LA57 (1ULL << 39) /* 57-bit Linear Addresses */
|
||||||
|
#define KCF_ARAT (1ULL << 40) /* Always Running APIC Timer */
|
||||||
|
|
||||||
|
/* Kernel CPU Extended Features */
|
||||||
|
#define KCF_SVM (1ULL << 0) /* AMD Secure Virtual Machine */
|
||||||
|
#define KCF_SSE4A (1ULL << 1) /* SSE4A Instructions */
|
||||||
|
#define KCF_FMA4 (1ULL << 2) /* FMA4 Instructions */
|
||||||
|
#define KCF_TOPOEXT (1ULL << 3) /* AMD Topology Extensions */
|
||||||
|
#define KCF_SYSCALL (1ULL << 4) /* SYSCALL/SYSRET Instructions */
|
||||||
|
#define KCF_NX_BIT (1ULL << 5) /* No-Execute Page Protection */
|
||||||
|
#define KCF_RDTSCP (1ULL << 6) /* RDTSCP Instruction */
|
||||||
|
#define KCF_64BIT (1ULL << 7) /* Long Mode Support */
|
||||||
|
#define KCF_3DNOW_EXT (1ULL << 8) /* 3DNow! Extensions */
|
||||||
|
#define KCF_3DNOW (1ULL << 9) /* 3DNow! Instructions */
|
||||||
|
#define KCF_INVARIANT_TSC (1ULL << 10) /* Invariant Time Stamp Counter */
|
||||||
|
|
||||||
/* Context control flags */
|
/* Context control flags */
|
||||||
#define CONTEXT_ARCHITECTURE 0x00010000
|
#define CONTEXT_ARCHITECTURE 0x00010000
|
||||||
#define CONTEXT_CONTROL (CONTEXT_ARCHITECTURE | 0x01)
|
#define CONTEXT_CONTROL (CONTEXT_ARCHITECTURE | 0x01)
|
||||||
@@ -137,8 +193,8 @@
|
|||||||
#define KERNEL_STACK_GUARD_PAGES 1
|
#define KERNEL_STACK_GUARD_PAGES 1
|
||||||
|
|
||||||
/* Processor structures size */
|
/* Processor structures size */
|
||||||
#define KPROCESSOR_STRUCTURES_SIZE ((2 * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + sizeof(KTSS) + \
|
#define KPROCESSOR_STRUCTURES_SIZE ((KERNEL_STACKS * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + \
|
||||||
sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
|
sizeof(KTSS) + sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
|
||||||
|
|
||||||
/* Kernel frames */
|
/* Kernel frames */
|
||||||
#define KTRAP_FRAME_ALIGN 0x08
|
#define KTRAP_FRAME_ALIGN 0x08
|
||||||
@@ -431,6 +487,17 @@ typedef struct _KSPECIAL_REGISTERS
|
|||||||
ULONG Reserved[6];
|
ULONG Reserved[6];
|
||||||
} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS;
|
} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS;
|
||||||
|
|
||||||
|
/* Processor start block structure definition */
|
||||||
|
typedef struct _PROCESSOR_START_BLOCK
|
||||||
|
{
|
||||||
|
ULONG_PTR Cr3;
|
||||||
|
ULONG_PTR Cr4;
|
||||||
|
PVOID EntryPoint;
|
||||||
|
PVOID ProcessorStructures;
|
||||||
|
PVOID Stack;
|
||||||
|
BOOLEAN Started;
|
||||||
|
} PROCESSOR_START_BLOCK, *PPROCESSOR_START_BLOCK;
|
||||||
|
|
||||||
/* Processor state frame structure definition */
|
/* Processor state frame structure definition */
|
||||||
typedef struct _KPROCESSOR_STATE
|
typedef struct _KPROCESSOR_STATE
|
||||||
{
|
{
|
||||||
@@ -483,6 +550,8 @@ typedef struct _KPROCESSOR_BLOCK
|
|||||||
KAFFINITY SetMember;
|
KAFFINITY SetMember;
|
||||||
ULONG StallScaleFactor;
|
ULONG StallScaleFactor;
|
||||||
UCHAR CpuNumber;
|
UCHAR CpuNumber;
|
||||||
|
ULONG HardwareId;
|
||||||
|
VOLATILE BOOLEAN Started;
|
||||||
PINTERRUPT_HANDLER InterruptDispatchTable[256];
|
PINTERRUPT_HANDLER InterruptDispatchTable[256];
|
||||||
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;
|
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,8 @@
|
|||||||
#define STATUS_NO_MEMORY ((XTSTATUS) 0xC0000017L)
|
#define STATUS_NO_MEMORY ((XTSTATUS) 0xC0000017L)
|
||||||
#define STATUS_PORT_DISCONNECTED ((XTSTATUS) 0xC0000037L)
|
#define STATUS_PORT_DISCONNECTED ((XTSTATUS) 0xC0000037L)
|
||||||
#define STATUS_CRC_ERROR ((XTSTATUS) 0xC000003FL)
|
#define STATUS_CRC_ERROR ((XTSTATUS) 0xC000003FL)
|
||||||
|
#define STATUS_FLOAT_OVERFLOW ((XTSTATUS) 0xC0000091L)
|
||||||
|
#define STATUS_INTEGER_OVERFLOW ((XTSTATUS) 0xC0000095L)
|
||||||
#define STATUS_INSUFFICIENT_RESOURCES ((XTSTATUS) 0xC000009AL)
|
#define STATUS_INSUFFICIENT_RESOURCES ((XTSTATUS) 0xC000009AL)
|
||||||
#define STATUS_DEVICE_NOT_READY ((XTSTATUS) 0xC00000A3L)
|
#define STATUS_DEVICE_NOT_READY ((XTSTATUS) 0xC00000A3L)
|
||||||
#define STATUS_NOT_SUPPORTED ((XTSTATUS) 0xC00000BBL)
|
#define STATUS_NOT_SUPPORTED ((XTSTATUS) 0xC00000BBL)
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ The following is a consolidated list of available kernel parameters:
|
|||||||
scheduler tick. Valid values include `LAPIC` (Local APIC Timer), `HPET` (High Precision Event Timer), and `PIT`
|
scheduler tick. Valid values include `LAPIC` (Local APIC Timer), `HPET` (High Precision Event Timer), and `PIT`
|
||||||
(Legacy Programmable Interval Timer). If this parameter is omitted, the kernel will autonomously probe the hardware
|
(Legacy Programmable Interval Timer). If this parameter is omitted, the kernel will autonomously probe the hardware
|
||||||
and select the most optimal clock source for the current CPU topology, (defaulting to the Local APIC on modern systems.
|
and select the most optimal clock source for the current CPU topology, (defaulting to the Local APIC on modern systems.
|
||||||
|
* **NOX2APIC**: Explicitly disables x2APIC support. When specified, the kernel bypasses hardware feature detection for
|
||||||
|
x2APIC and forces the use of the classic, memory-mapped (MMIO) xAPIC mode. This parameter is particularly useful for
|
||||||
|
troubleshooting interrupt routing issues or ensuring compatibility with specific hypervisors and legacy emulators.
|
||||||
* **NOXPA**: Disables PAE or LA57 support, depending on the CPU architecture. This parameter is handled by the
|
* **NOXPA**: Disables PAE or LA57 support, depending on the CPU architecture. This parameter is handled by the
|
||||||
bootloader, which configures paging and selects the appropriate Page Map Level (PML) before transferring control to
|
bootloader, which configures paging and selects the appropriate Page Map Level (PML) before transferring control to
|
||||||
the kernel.
|
the kernel.
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ ArHandleSpuriousInterrupt:
|
|||||||
iretq
|
iretq
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts an application processor (AP). This is just a stub.
|
* Starts an application processor (AP).
|
||||||
*
|
*
|
||||||
* @return This routine does not return any value.
|
* @return This routine does not return any value.
|
||||||
*
|
*
|
||||||
@@ -367,6 +367,123 @@ ArHandleSpuriousInterrupt:
|
|||||||
*/
|
*/
|
||||||
.global ArStartApplicationProcessor
|
.global ArStartApplicationProcessor
|
||||||
ArStartApplicationProcessor:
|
ArStartApplicationProcessor:
|
||||||
|
/* Enter 16-bit real mode */
|
||||||
|
.code16
|
||||||
|
|
||||||
|
/* Disable interrupts and clear direction flag */
|
||||||
|
cli
|
||||||
|
cld
|
||||||
|
|
||||||
|
/* Establish a flat addressing baseline */
|
||||||
|
movw %cs, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %ss
|
||||||
|
|
||||||
|
/* Calculate absolute physical base address */
|
||||||
|
xorl %ebx, %ebx
|
||||||
|
movw %cs, %bx
|
||||||
|
shll $4, %ebx
|
||||||
|
|
||||||
|
/* Set up a temporary stack for the AP initialization */
|
||||||
|
movl %ebx, %esp
|
||||||
|
addl $0x1000, %esp
|
||||||
|
|
||||||
|
/* Load the temporary Global Descriptor Table */
|
||||||
|
leal (ApTemporaryGdtDesc - ArStartApplicationProcessor)(%ebx), %eax
|
||||||
|
movl %eax, (ApTemporaryGdtBase - ArStartApplicationProcessor)
|
||||||
|
lgdtl (ApTemporaryGdtSize - ArStartApplicationProcessor)
|
||||||
|
|
||||||
|
/* Enable Protected Mode */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $0x01, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
/* Far return to enter 32-bit protected mode */
|
||||||
|
leal (ApEnterProtectedMode - ArStartApplicationProcessor)(%ebx), %eax
|
||||||
|
pushl $KGDT_R0_CMCODE
|
||||||
|
pushl %eax
|
||||||
|
lretl
|
||||||
|
|
||||||
|
ApEnterProtectedMode:
|
||||||
|
/* Enter 32-bit protected mode */
|
||||||
|
.code32
|
||||||
|
|
||||||
|
/* Setup all data segment registers */
|
||||||
|
movw $KGDT_R0_DATA, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %ss
|
||||||
|
xorw %ax, %ax
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
|
||||||
|
/* Locate PROCESSOR_START_BLOCK structure */
|
||||||
|
leal (ArStartApplicationProcessorEnd - ArStartApplicationProcessor)(%ebx), %edi
|
||||||
|
|
||||||
|
/* Load CR4 from BSP, but mask PCIDE and PGE */
|
||||||
|
movl PROCESSOR_START_BLOCK_Cr4(%edi), %eax
|
||||||
|
andl $~(CR4_PGE | CR4_PCIDE), %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
|
||||||
|
/* Load the Kernel Page Directory Base from BSP */
|
||||||
|
movl PROCESSOR_START_BLOCK_Cr3(%edi), %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
/* Enable Long Mode and No-Execute */
|
||||||
|
movl $X86_MSR_EFER, %ecx
|
||||||
|
rdmsr
|
||||||
|
orl $(X86_MSR_EFER_LME | X86_MSR_EFER_NXE), %eax
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
/* Enable Paging */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $CR0_PG, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
/* Far return to enter 64-bit long mode */
|
||||||
|
leal (ApEnterLongMode - ArStartApplicationProcessor)(%ebx), %eax
|
||||||
|
pushl $KGDT_R0_CODE
|
||||||
|
pushl %eax
|
||||||
|
lretl
|
||||||
|
|
||||||
|
ApEnterLongMode:
|
||||||
|
/* Enter 64-bit long mode */
|
||||||
|
.code64
|
||||||
|
|
||||||
|
/* Clear all segment registers */
|
||||||
|
xorw %ax, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %ss
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
|
||||||
|
/* Zero-extend EDI into RDI to ensure safe 64-bit pointer usage */
|
||||||
|
movl %edi, %edi
|
||||||
|
|
||||||
|
/* Load dedicated Stack for AP */
|
||||||
|
movq PROCESSOR_START_BLOCK_Stack(%rdi), %rsp
|
||||||
|
|
||||||
|
/* Save the pointer to PROCESSOR_START_BLOCK */
|
||||||
|
movq %rdi, %rcx
|
||||||
|
pushq %rdi
|
||||||
|
|
||||||
|
/* Call the EntryPoint routine */
|
||||||
|
movq PROCESSOR_START_BLOCK_EntryPoint(%rdi), %rax
|
||||||
|
call *%rax
|
||||||
|
|
||||||
|
/* Fire the breakpoint and halt if the entry point returns */
|
||||||
|
.ApNoReturnPoint:
|
||||||
|
int $0x03
|
||||||
|
hlt
|
||||||
|
jmp .ApNoReturnPoint
|
||||||
|
|
||||||
|
/* Data section for temporary GDT */
|
||||||
|
.align 8
|
||||||
|
ApTemporaryGdtSize: .short ArStartApplicationProcessorEnd - ApTemporaryGdtDesc - 1
|
||||||
|
ApTemporaryGdtBase: .quad 0x0000000000000000
|
||||||
|
ApTemporaryGdtDesc: .quad 0x0000000000000000, 0x00CF9A000000FFFF, 0x00AF9A000000FFFF, 0x00CF92000000FFFF
|
||||||
|
|
||||||
.global ArStartApplicationProcessorEnd
|
.global ArStartApplicationProcessorEnd
|
||||||
ArStartApplicationProcessorEnd:
|
ArStartApplicationProcessorEnd:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ XTAPI
|
|||||||
PVOID
|
PVOID
|
||||||
AR::ProcSup::GetBootStack(VOID)
|
AR::ProcSup::GetBootStack(VOID)
|
||||||
{
|
{
|
||||||
|
/* Return base address of kernel boot stack */
|
||||||
return (PVOID)((ULONG_PTR)BootStack + KERNEL_STACK_SIZE);
|
return (PVOID)((ULONG_PTR)BootStack + KERNEL_STACK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,19 +30,23 @@ AR::ProcSup::GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType,
|
|||||||
OUT PVOID *TrampolineCode,
|
OUT PVOID *TrampolineCode,
|
||||||
OUT PULONG_PTR TrampolineSize)
|
OUT PULONG_PTR TrampolineSize)
|
||||||
{
|
{
|
||||||
|
/* Get trampoline information */
|
||||||
switch(TrampolineType)
|
switch(TrampolineType)
|
||||||
{
|
{
|
||||||
case TrampolineApStartup:
|
case TrampolineApStartup:
|
||||||
|
/* Get AP startup trampoline information */
|
||||||
*TrampolineCode = (PVOID)ArStartApplicationProcessor;
|
*TrampolineCode = (PVOID)ArStartApplicationProcessor;
|
||||||
*TrampolineSize = (ULONG_PTR)ArStartApplicationProcessorEnd -
|
*TrampolineSize = (ULONG_PTR)ArStartApplicationProcessorEnd -
|
||||||
(ULONG_PTR)ArStartApplicationProcessor;
|
(ULONG_PTR)ArStartApplicationProcessor;
|
||||||
break;
|
break;
|
||||||
case TrampolineEnableXpa:
|
case TrampolineEnableXpa:
|
||||||
|
/* Get Enable XPA trampoline information */
|
||||||
*TrampolineCode = (PVOID)ArEnableExtendedPhysicalAddressing;
|
*TrampolineCode = (PVOID)ArEnableExtendedPhysicalAddressing;
|
||||||
*TrampolineSize = (ULONG_PTR)ArEnableExtendedPhysicalAddressingEnd -
|
*TrampolineSize = (ULONG_PTR)ArEnableExtendedPhysicalAddressingEnd -
|
||||||
(ULONG_PTR)ArEnableExtendedPhysicalAddressing;
|
(ULONG_PTR)ArEnableExtendedPhysicalAddressing;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
/* Unknown trampoline type */
|
||||||
*TrampolineCode = NULLPTR;
|
*TrampolineCode = NULLPTR;
|
||||||
*TrampolineSize = 0;
|
*TrampolineSize = 0;
|
||||||
break;
|
break;
|
||||||
@@ -64,9 +69,6 @@ AR::ProcSup::IdentifyProcessor(VOID)
|
|||||||
CPUID_REGISTERS CpuRegisters;
|
CPUID_REGISTERS CpuRegisters;
|
||||||
CPUID_SIGNATURE CpuSignature;
|
CPUID_SIGNATURE CpuSignature;
|
||||||
|
|
||||||
/* Not fully implemented yet */
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
|
|
||||||
/* Get current processor control block */
|
/* Get current processor control block */
|
||||||
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
||||||
|
|
||||||
@@ -122,11 +124,12 @@ AR::ProcSup::IdentifyProcessor(VOID)
|
|||||||
Prcb->CpuId.Vendor = CPU_VENDOR_UNKNOWN;
|
Prcb->CpuId.Vendor = CPU_VENDOR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Store a list of CPU features in processor control block */
|
/* Identify processor features */
|
||||||
|
IdentifyProcessorFeatures();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes AMD64 processor specific structures.
|
* Identifies processor features and stores them in Processor Control Block (PRCB).
|
||||||
*
|
*
|
||||||
* @return This routine does not return any value.
|
* @return This routine does not return any value.
|
||||||
*
|
*
|
||||||
@@ -134,71 +137,133 @@ AR::ProcSup::IdentifyProcessor(VOID)
|
|||||||
*/
|
*/
|
||||||
XTAPI
|
XTAPI
|
||||||
VOID
|
VOID
|
||||||
AR::ProcSup::InitializeProcessor(IN PVOID ProcessorStructures)
|
AR::ProcSup::IdentifyProcessorFeatures(VOID)
|
||||||
{
|
{
|
||||||
PVOID KernelBootStack, KernelFaultStack, KernelNmiStack;
|
ULONG MaxExtendedLeaf, MaxStandardLeaf;
|
||||||
KDESCRIPTOR GdtDescriptor, IdtDescriptor;
|
PKPROCESSOR_CONTROL_BLOCK Prcb;
|
||||||
PKPROCESSOR_BLOCK ProcessorBlock;
|
CPUID_REGISTERS CpuRegisters;
|
||||||
PKGDTENTRY Gdt;
|
|
||||||
PKIDTENTRY Idt;
|
|
||||||
PKTSS Tss;
|
|
||||||
|
|
||||||
/* Check if processor structures buffer provided */
|
/* Get current processor control block */
|
||||||
if(ProcessorStructures)
|
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
||||||
{
|
|
||||||
/* Assign CPU structures from provided buffer */
|
|
||||||
InitializeProcessorStructures(ProcessorStructures, &Gdt, &Tss, &ProcessorBlock,
|
|
||||||
&KernelBootStack, &KernelFaultStack, &KernelNmiStack);
|
|
||||||
|
|
||||||
/* Use global IDT */
|
/* Get maximum CPUID standard leaf */
|
||||||
Idt = InitialIdt;
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
}
|
CpuRegisters.Leaf = CPUID_GET_VENDOR_STRING;
|
||||||
else
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
MaxStandardLeaf = CpuRegisters.Eax;
|
||||||
|
|
||||||
|
/* Get maximum CPUID extended leaf */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_EXTENDED_MAX;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
MaxExtendedLeaf = CpuRegisters.Eax;
|
||||||
|
|
||||||
|
/* Check if CPU supports standard features leaf */
|
||||||
|
if(MaxStandardLeaf >= CPUID_GET_STANDARD1_FEATURES)
|
||||||
{
|
{
|
||||||
/* Use initial structures */
|
/* Get CPU standard features */
|
||||||
Gdt = InitialGdt;
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
Idt = InitialIdt;
|
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
|
||||||
Tss = &InitialTss;
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
KernelBootStack = (PVOID)((ULONG_PTR)&BootStack + KERNEL_STACK_SIZE);
|
|
||||||
KernelFaultStack = (PVOID)((ULONG_PTR)&FaultStack + KERNEL_STACK_SIZE);
|
/* Store CPU standard features in processor control block */
|
||||||
KernelNmiStack = (PVOID)((ULONG_PTR)&NmiStack + KERNEL_STACK_SIZE);
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE3) Prcb->CpuId.FeatureBits |= KCF_SSE3;
|
||||||
ProcessorBlock = &InitialProcessorBlock;
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_VMX) Prcb->CpuId.FeatureBits |= KCF_VMX;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSSE3) Prcb->CpuId.FeatureBits |= KCF_SSSE3;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE4_1) Prcb->CpuId.FeatureBits |= KCF_SSE41;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE4_2) Prcb->CpuId.FeatureBits |= KCF_SSE42;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_X2APIC) Prcb->CpuId.FeatureBits |= KCF_X2APIC;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_POPCNT) Prcb->CpuId.FeatureBits |= KCF_POPCNT;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_TSC_DEADLINE) Prcb->CpuId.FeatureBits |= KCF_TSC_DEADLINE;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_AES) Prcb->CpuId.FeatureBits |= KCF_AES;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_XSAVE) Prcb->CpuId.FeatureBits |= KCF_XSAVE;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_AVX) Prcb->CpuId.FeatureBits |= KCF_AVX;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_RDRAND) Prcb->CpuId.FeatureBits |= KCF_RDRAND;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_VME) Prcb->CpuId.FeatureBits |= KCF_VME;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PSE) Prcb->CpuId.FeatureBits |= KCF_LARGE_PAGE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_TSC) Prcb->CpuId.FeatureBits |= KCF_RDTSC;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PAE) Prcb->CpuId.FeatureBits |= KCF_PAE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MCE) Prcb->CpuId.FeatureBits |= KCF_MCE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_CX8) Prcb->CpuId.FeatureBits |= KCF_CMPXCHG8B;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_APIC) Prcb->CpuId.FeatureBits |= KCF_APIC;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SEP) Prcb->CpuId.FeatureBits |= KCF_FAST_SYSCALL;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MTRR) Prcb->CpuId.FeatureBits |= KCF_MTRR;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PGE) Prcb->CpuId.FeatureBits |= KCF_GLOBAL_PAGE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MCA) Prcb->CpuId.FeatureBits |= KCF_MCA;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_CMOV) Prcb->CpuId.FeatureBits |= KCF_CMOV;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PAT) Prcb->CpuId.FeatureBits |= KCF_PAT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PSE36) Prcb->CpuId.FeatureBits |= KCF_PSE36;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_CLFLUSH) Prcb->CpuId.FeatureBits |= KCF_CLFLUSH;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_FXSR) Prcb->CpuId.FeatureBits |= KCF_FXSR;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_ACPI) Prcb->CpuId.FeatureBits |= KCF_ACPI;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MMX) Prcb->CpuId.FeatureBits |= KCF_MMX;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SSE) Prcb->CpuId.FeatureBits |= KCF_SSE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SSE2) Prcb->CpuId.FeatureBits |= KCF_SSE2;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_HTT) Prcb->CpuId.FeatureBits |= KCF_SMT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize processor block */
|
/* Check if CPU supports standard7 features leaf */
|
||||||
InitializeProcessorBlock(ProcessorBlock, Gdt, Idt, Tss, KernelFaultStack);
|
if(MaxStandardLeaf >= CPUID_GET_STANDARD7_FEATURES)
|
||||||
|
{
|
||||||
|
/* Get CPU standard features */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_STANDARD7_FEATURES;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Initialize GDT, IDT and TSS */
|
/* Store CPU standard7 features in processor control block */
|
||||||
InitializeGdt(ProcessorBlock);
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_FSGSBASE) Prcb->CpuId.FeatureBits |= KCF_FSGSBASE;
|
||||||
InitializeIdt(ProcessorBlock);
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_AVX2) Prcb->CpuId.FeatureBits |= KCF_AVX2;
|
||||||
InitializeTss(ProcessorBlock, KernelBootStack, KernelFaultStack, KernelNmiStack);
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_SMEP) Prcb->CpuId.FeatureBits |= KCF_SMEP;
|
||||||
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_RDSEED) Prcb->CpuId.FeatureBits |= KCF_RDSEED;
|
||||||
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_SMAP) Prcb->CpuId.FeatureBits |= KCF_SMAP;
|
||||||
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_SHA) Prcb->CpuId.FeatureBits |= KCF_SHA;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_LA57) Prcb->CpuId.FeatureBits |= KCF_LA57;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set GDT and IDT descriptors */
|
/* Check if CPU supports power management leaf */
|
||||||
GdtDescriptor.Base = Gdt;
|
if(MaxStandardLeaf >= CPUID_GET_POWER_MANAGEMENT)
|
||||||
GdtDescriptor.Limit = (GDT_ENTRIES * sizeof(KGDTENTRY)) - 1;
|
{
|
||||||
IdtDescriptor.Base = Idt;
|
/* Get CPU power management features */
|
||||||
IdtDescriptor.Limit = (IDT_ENTRIES * sizeof(KIDTENTRY)) - 1;
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_POWER_MANAGEMENT;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Load GDT, IDT and TSS */
|
/* Store CPU power management features in processor control block */
|
||||||
AR::CpuFunc::LoadGlobalDescriptorTable(&GdtDescriptor.Limit);
|
if(CpuRegisters.Eax & CPUID_FEATURES_EAX_ARAT) Prcb->CpuId.FeatureBits |= KCF_ARAT;
|
||||||
AR::CpuFunc::LoadInterruptDescriptorTable(&IdtDescriptor.Limit);
|
}
|
||||||
AR::CpuFunc::LoadTaskRegister((UINT)KGDT_SYS_TSS);
|
|
||||||
|
|
||||||
/* Enter passive IRQ level */
|
/* Check if CPU supports extended features leaf */
|
||||||
HL::RunLevel::SetRunLevel(PASSIVE_LEVEL);
|
if(MaxExtendedLeaf >= CPUID_GET_EXTENDED_FEATURES)
|
||||||
|
{
|
||||||
|
/* Get CPU extended features */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_EXTENDED_FEATURES;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Initialize segment registers */
|
/* Store CPU extended features in processor control block */
|
||||||
InitializeSegments();
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SVM) Prcb->CpuId.ExtendedFeatureBits |= KCF_SVM;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE4A) Prcb->CpuId.ExtendedFeatureBits |= KCF_SSE4A;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_FMA4) Prcb->CpuId.ExtendedFeatureBits |= KCF_FMA4;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_TOPOLOGY_EXTENSIONS) Prcb->CpuId.ExtendedFeatureBits |= KCF_TOPOEXT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SYSCALL_SYSRET) Prcb->CpuId.ExtendedFeatureBits |= KCF_SYSCALL;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_NX) Prcb->CpuId.ExtendedFeatureBits |= KCF_NX_BIT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_RDTSCP) Prcb->CpuId.ExtendedFeatureBits |= KCF_RDTSCP;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_LONG_MODE) Prcb->CpuId.ExtendedFeatureBits |= KCF_64BIT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_3DNOW_EXT) Prcb->CpuId.ExtendedFeatureBits |= KCF_3DNOW_EXT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_3DNOW) Prcb->CpuId.ExtendedFeatureBits |= KCF_3DNOW;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set GS base */
|
/* Check if CPU supports advanced power management leaf */
|
||||||
AR::CpuFunc::WriteModelSpecificRegister(X86_MSR_GSBASE, (ULONGLONG)ProcessorBlock);
|
if(MaxExtendedLeaf >= CPUID_GET_ADVANCED_POWER_MANAGEMENT)
|
||||||
AR::CpuFunc::WriteModelSpecificRegister(X86_MSR_KERNEL_GSBASE, (ULONGLONG)ProcessorBlock);
|
{
|
||||||
|
/* Get CPU advanced power management features */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_ADVANCED_POWER_MANAGEMENT;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Initialize processor registers */
|
/* Store CPU advanced power management features in processor control block */
|
||||||
InitializeProcessorRegisters();
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_TSCI) Prcb->CpuId.ExtendedFeatureBits |= KCF_INVARIANT_TSC;
|
||||||
|
}
|
||||||
/* Identify processor */
|
|
||||||
IdentifyProcessor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -281,6 +346,79 @@ AR::ProcSup::InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock)
|
|||||||
SetIdtGate(ProcessorBlock->IdtBase, 0xE1, (PVOID)ArInterruptEntry[0xE1], 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes AMD64 processor specific structures.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
AR::ProcSup::InitializeProcessor(IN PVOID ProcessorStructures)
|
||||||
|
{
|
||||||
|
PVOID KernelBootStack, KernelFaultStack, KernelNmiStack;
|
||||||
|
KDESCRIPTOR GdtDescriptor, IdtDescriptor;
|
||||||
|
PKPROCESSOR_BLOCK ProcessorBlock;
|
||||||
|
PKGDTENTRY Gdt;
|
||||||
|
PKIDTENTRY Idt;
|
||||||
|
PKTSS Tss;
|
||||||
|
|
||||||
|
/* Check if processor structures buffer provided */
|
||||||
|
if(ProcessorStructures)
|
||||||
|
{
|
||||||
|
/* Assign CPU structures from provided buffer */
|
||||||
|
InitializeProcessorStructures(ProcessorStructures, &Gdt, &Tss, &ProcessorBlock,
|
||||||
|
&KernelBootStack, &KernelFaultStack, &KernelNmiStack);
|
||||||
|
|
||||||
|
/* Use global IDT */
|
||||||
|
Idt = InitialIdt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Use initial structures */
|
||||||
|
Gdt = InitialGdt;
|
||||||
|
Idt = InitialIdt;
|
||||||
|
Tss = &InitialTss;
|
||||||
|
KernelBootStack = (PVOID)((ULONG_PTR)&BootStack + KERNEL_STACK_SIZE);
|
||||||
|
KernelFaultStack = (PVOID)((ULONG_PTR)&FaultStack + KERNEL_STACK_SIZE);
|
||||||
|
KernelNmiStack = (PVOID)((ULONG_PTR)&NmiStack + KERNEL_STACK_SIZE);
|
||||||
|
ProcessorBlock = &InitialProcessorBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize processor block */
|
||||||
|
InitializeProcessorBlock(ProcessorBlock, Gdt, Idt, Tss, KernelFaultStack);
|
||||||
|
|
||||||
|
/* Initialize GDT, IDT and TSS */
|
||||||
|
InitializeGdt(ProcessorBlock);
|
||||||
|
InitializeIdt(ProcessorBlock);
|
||||||
|
InitializeTss(ProcessorBlock, KernelBootStack, KernelFaultStack, KernelNmiStack);
|
||||||
|
|
||||||
|
/* Set GDT and IDT descriptors */
|
||||||
|
GdtDescriptor.Base = Gdt;
|
||||||
|
GdtDescriptor.Limit = (GDT_ENTRIES * sizeof(KGDTENTRY)) - 1;
|
||||||
|
IdtDescriptor.Base = Idt;
|
||||||
|
IdtDescriptor.Limit = (IDT_ENTRIES * sizeof(KIDTENTRY)) - 1;
|
||||||
|
|
||||||
|
/* Load GDT, IDT and TSS */
|
||||||
|
AR::CpuFunc::LoadGlobalDescriptorTable(&GdtDescriptor.Limit);
|
||||||
|
AR::CpuFunc::LoadInterruptDescriptorTable(&IdtDescriptor.Limit);
|
||||||
|
AR::CpuFunc::LoadTaskRegister((UINT)KGDT_SYS_TSS);
|
||||||
|
|
||||||
|
/* Initialize segment registers */
|
||||||
|
InitializeSegments();
|
||||||
|
|
||||||
|
/* Set GS base */
|
||||||
|
AR::CpuFunc::WriteModelSpecificRegister(X86_MSR_GSBASE, (ULONGLONG)ProcessorBlock);
|
||||||
|
AR::CpuFunc::WriteModelSpecificRegister(X86_MSR_KERNEL_GSBASE, (ULONGLONG)ProcessorBlock);
|
||||||
|
|
||||||
|
/* Initialize processor registers */
|
||||||
|
InitializeProcessorRegisters();
|
||||||
|
|
||||||
|
/* Identify processor */
|
||||||
|
IdentifyProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes processor block.
|
* Initializes processor block.
|
||||||
*
|
*
|
||||||
@@ -439,26 +577,49 @@ AR::ProcSup::InitializeProcessorStructures(IN PVOID ProcessorStructures,
|
|||||||
Address = ROUND_UP((UINT_PTR)ProcessorStructures, MM_PAGE_SIZE) + KERNEL_STACK_SIZE;
|
Address = ROUND_UP((UINT_PTR)ProcessorStructures, MM_PAGE_SIZE) + KERNEL_STACK_SIZE;
|
||||||
|
|
||||||
/* Assign a space for kernel boot stack and advance */
|
/* Assign a space for kernel boot stack and advance */
|
||||||
|
if(KernelBootStack != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return kernel boot stack address */
|
||||||
*KernelBootStack = (PVOID)Address;
|
*KernelBootStack = (PVOID)Address;
|
||||||
|
}
|
||||||
Address += KERNEL_STACK_SIZE;
|
Address += KERNEL_STACK_SIZE;
|
||||||
|
|
||||||
/* Assign a space for kernel fault stack and advance */
|
/* Assign a space for kernel fault stack and advance */
|
||||||
|
if(KernelFaultStack != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return kernel fault stack address */
|
||||||
*KernelFaultStack = (PVOID)Address;
|
*KernelFaultStack = (PVOID)Address;
|
||||||
|
}
|
||||||
Address += KERNEL_STACK_SIZE;
|
Address += KERNEL_STACK_SIZE;
|
||||||
|
|
||||||
/* Assign a space for kernel NMI stack, no advance needed as stack grows down */
|
/* Assign a space for kernel NMI stack, no advance needed as stack grows down */
|
||||||
|
if(KernelNmiStack != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return kernel NMI stack address */
|
||||||
*KernelNmiStack = (PVOID)Address;
|
*KernelNmiStack = (PVOID)Address;
|
||||||
|
}
|
||||||
|
|
||||||
/* Assign a space for GDT and advance */
|
/* Assign a space for GDT and advance */
|
||||||
|
if(Gdt != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return GDT base address */
|
||||||
*Gdt = (PKGDTENTRY)(PVOID)Address;
|
*Gdt = (PKGDTENTRY)(PVOID)Address;
|
||||||
Address += sizeof(InitialGdt);
|
}
|
||||||
|
Address += (GDT_ENTRIES * sizeof(KGDTENTRY));
|
||||||
|
|
||||||
|
/* Assign a space for TSS and advance */
|
||||||
|
if(Tss != NULLPTR)
|
||||||
|
{
|
||||||
|
*Tss = (PKTSS)(PVOID)Address;
|
||||||
|
}
|
||||||
|
Address += sizeof(KTSS);
|
||||||
|
|
||||||
/* Assign a space for Processor Block and advance */
|
/* Assign a space for Processor Block and advance */
|
||||||
|
if(ProcessorBlock != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return processor block address */
|
||||||
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
|
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
|
||||||
Address += sizeof(InitialProcessorBlock);
|
}
|
||||||
|
|
||||||
/* Assign a space for TSS */
|
|
||||||
*Tss = (PKTSS)(PVOID)Address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ _ArHandleSpuriousInterrupt:
|
|||||||
iret
|
iret
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts an application processor (AP). This is just a stub.
|
* Starts an application processor (AP).
|
||||||
*
|
*
|
||||||
* @return This routine does not return any value.
|
* @return This routine does not return any value.
|
||||||
*
|
*
|
||||||
@@ -242,6 +242,96 @@ _ArHandleSpuriousInterrupt:
|
|||||||
*/
|
*/
|
||||||
.global _ArStartApplicationProcessor
|
.global _ArStartApplicationProcessor
|
||||||
_ArStartApplicationProcessor:
|
_ArStartApplicationProcessor:
|
||||||
|
/* Enter 16-bit real mode */
|
||||||
|
.code16
|
||||||
|
|
||||||
|
/* Disable interrupts and clear direction flag */
|
||||||
|
cli
|
||||||
|
cld
|
||||||
|
|
||||||
|
/* Establish a flat addressing baseline */
|
||||||
|
movw %cs, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %ss
|
||||||
|
|
||||||
|
/* Calculate absolute physical base address */
|
||||||
|
xorl %ebx, %ebx
|
||||||
|
movw %cs, %bx
|
||||||
|
shll $4, %ebx
|
||||||
|
|
||||||
|
/* Set up a temporary stack for the AP initialization */
|
||||||
|
movl %ebx, %esp
|
||||||
|
addl $0x1000, %esp
|
||||||
|
|
||||||
|
/* Load the temporary Global Descriptor Table */
|
||||||
|
leal (ApTemporaryGdtDesc - _ArStartApplicationProcessor)(%ebx), %eax
|
||||||
|
movl %eax, (ApTemporaryGdtBase - _ArStartApplicationProcessor)
|
||||||
|
lgdtl (ApTemporaryGdtSize - _ArStartApplicationProcessor)
|
||||||
|
|
||||||
|
/* Enable Protected Mode */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $0x01, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
/* Far return to enter 32-bit protected mode */
|
||||||
|
leal (ApEnterProtectedMode - _ArStartApplicationProcessor)(%ebx), %eax
|
||||||
|
pushl $KGDT_R0_CODE
|
||||||
|
pushl %eax
|
||||||
|
lretl
|
||||||
|
|
||||||
|
ApEnterProtectedMode:
|
||||||
|
/* Enter 32-bit protected mode */
|
||||||
|
.code32
|
||||||
|
|
||||||
|
/* Setup all data segment registers */
|
||||||
|
movw $KGDT_R0_DATA, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %ss
|
||||||
|
xorw %ax, %ax
|
||||||
|
movw %ax, %fs
|
||||||
|
movw %ax, %gs
|
||||||
|
|
||||||
|
/* Locate PROCESSOR_START_BLOCK structure */
|
||||||
|
leal (_ArStartApplicationProcessorEnd - _ArStartApplicationProcessor)(%ebx), %edi
|
||||||
|
|
||||||
|
/* Load CR4 from BSP, but mask PCIDE and PGE */
|
||||||
|
movl PROCESSOR_START_BLOCK_Cr4(%edi), %eax
|
||||||
|
andl $~(CR4_PGE | CR4_PCIDE), %eax
|
||||||
|
movl %eax, %cr4
|
||||||
|
|
||||||
|
/* Load the Kernel Page Directory Base from BSP */
|
||||||
|
movl PROCESSOR_START_BLOCK_Cr3(%edi), %eax
|
||||||
|
movl %eax, %cr3
|
||||||
|
|
||||||
|
/* Enable Paging */
|
||||||
|
movl %cr0, %eax
|
||||||
|
orl $CR0_PG, %eax
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
/* Load dedicated Stack for AP */
|
||||||
|
movl PROCESSOR_START_BLOCK_Stack(%edi), %esp
|
||||||
|
|
||||||
|
/* Save the pointer to PROCESSOR_START_BLOCK */
|
||||||
|
movl %edi, %ecx
|
||||||
|
pushl %edi
|
||||||
|
|
||||||
|
/* Call the EntryPoint routine */
|
||||||
|
movl PROCESSOR_START_BLOCK_EntryPoint(%edi), %eax
|
||||||
|
call *%eax
|
||||||
|
|
||||||
|
/* Fire the breakpoint and halt if the entry point returns */
|
||||||
|
.ApNoReturnPoint:
|
||||||
|
int $0x03
|
||||||
|
hlt
|
||||||
|
jmp .ApNoReturnPoint
|
||||||
|
|
||||||
|
/* Data section for temporary GDT */
|
||||||
|
.align 8
|
||||||
|
ApTemporaryGdtSize: .short _ArStartApplicationProcessorEnd - ApTemporaryGdtDesc - 1
|
||||||
|
ApTemporaryGdtBase: .long 0x00000000
|
||||||
|
ApTemporaryGdtDesc: .quad 0x0000000000000000, 0x00CF9A000000FFFF, 0x00CF92000000FFFF
|
||||||
|
|
||||||
.global _ArStartApplicationProcessorEnd
|
.global _ArStartApplicationProcessorEnd
|
||||||
_ArStartApplicationProcessorEnd:
|
_ArStartApplicationProcessorEnd:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ XTAPI
|
|||||||
PVOID
|
PVOID
|
||||||
AR::ProcSup::GetBootStack(VOID)
|
AR::ProcSup::GetBootStack(VOID)
|
||||||
{
|
{
|
||||||
|
/* Return base address of kernel boot stack */
|
||||||
return (PVOID)((ULONG_PTR)BootStack + KERNEL_STACK_SIZE);
|
return (PVOID)((ULONG_PTR)BootStack + KERNEL_STACK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,14 +30,17 @@ AR::ProcSup::GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType,
|
|||||||
OUT PVOID *TrampolineCode,
|
OUT PVOID *TrampolineCode,
|
||||||
OUT PULONG_PTR TrampolineSize)
|
OUT PULONG_PTR TrampolineSize)
|
||||||
{
|
{
|
||||||
|
/* Get trampoline information */
|
||||||
switch(TrampolineType)
|
switch(TrampolineType)
|
||||||
{
|
{
|
||||||
case TrampolineApStartup:
|
case TrampolineApStartup:
|
||||||
|
/* Get AP startup trampoline information */
|
||||||
*TrampolineCode = (PVOID)ArStartApplicationProcessor;
|
*TrampolineCode = (PVOID)ArStartApplicationProcessor;
|
||||||
*TrampolineSize = (ULONG_PTR)ArStartApplicationProcessorEnd -
|
*TrampolineSize = (ULONG_PTR)ArStartApplicationProcessorEnd -
|
||||||
(ULONG_PTR)ArStartApplicationProcessor;
|
(ULONG_PTR)ArStartApplicationProcessor;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
/* Unknown trampoline type */
|
||||||
*TrampolineCode = NULLPTR;
|
*TrampolineCode = NULLPTR;
|
||||||
*TrampolineSize = 0;
|
*TrampolineSize = 0;
|
||||||
break;
|
break;
|
||||||
@@ -44,8 +48,7 @@ AR::ProcSup::GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifies processor type (vendor, model, stepping) as well as looks for available CPU features and stores them
|
* Identifies processor type (vendor, model, stepping) and stores them in Processor Control Block (PRCB).
|
||||||
* in Processor Control Block (PRCB).
|
|
||||||
*
|
*
|
||||||
* @return This routine does not return any value.
|
* @return This routine does not return any value.
|
||||||
*
|
*
|
||||||
@@ -59,9 +62,6 @@ AR::ProcSup::IdentifyProcessor(VOID)
|
|||||||
CPUID_REGISTERS CpuRegisters;
|
CPUID_REGISTERS CpuRegisters;
|
||||||
CPUID_SIGNATURE CpuSignature;
|
CPUID_SIGNATURE CpuSignature;
|
||||||
|
|
||||||
/* Not fully implemented yet */
|
|
||||||
UNIMPLEMENTED;
|
|
||||||
|
|
||||||
/* Get current processor control block */
|
/* Get current processor control block */
|
||||||
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
||||||
|
|
||||||
@@ -117,11 +117,12 @@ AR::ProcSup::IdentifyProcessor(VOID)
|
|||||||
Prcb->CpuId.Vendor = CPU_VENDOR_UNKNOWN;
|
Prcb->CpuId.Vendor = CPU_VENDOR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Store a list of CPU features in processor control block */
|
/* Identify processor features */
|
||||||
|
IdentifyProcessorFeatures();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes i686 processor specific structures.
|
* Identifies processor features and stores them in Processor Control Block (PRCB).
|
||||||
*
|
*
|
||||||
* @return This routine does not return any value.
|
* @return This routine does not return any value.
|
||||||
*
|
*
|
||||||
@@ -129,67 +130,133 @@ AR::ProcSup::IdentifyProcessor(VOID)
|
|||||||
*/
|
*/
|
||||||
XTAPI
|
XTAPI
|
||||||
VOID
|
VOID
|
||||||
AR::ProcSup::InitializeProcessor(IN PVOID ProcessorStructures)
|
AR::ProcSup::IdentifyProcessorFeatures(VOID)
|
||||||
{
|
{
|
||||||
KDESCRIPTOR GdtDescriptor, IdtDescriptor;
|
ULONG MaxExtendedLeaf, MaxStandardLeaf;
|
||||||
PVOID KernelBootStack, KernelFaultStack, KernelNmiStack;
|
PKPROCESSOR_CONTROL_BLOCK Prcb;
|
||||||
PKPROCESSOR_BLOCK ProcessorBlock;
|
CPUID_REGISTERS CpuRegisters;
|
||||||
PKGDTENTRY Gdt;
|
|
||||||
PKIDTENTRY Idt;
|
|
||||||
PKTSS Tss;
|
|
||||||
|
|
||||||
/* Check if processor structures buffer provided */
|
/* Get current processor control block */
|
||||||
if(ProcessorStructures)
|
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
||||||
{
|
|
||||||
/* Assign CPU structures from provided buffer */
|
|
||||||
InitializeProcessorStructures(ProcessorStructures, &Gdt, &Tss, &ProcessorBlock,
|
|
||||||
&KernelBootStack, &KernelFaultStack, &KernelNmiStack);
|
|
||||||
|
|
||||||
/* Use global IDT */
|
/* Get maximum CPUID standard leaf */
|
||||||
Idt = InitialIdt;
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
}
|
CpuRegisters.Leaf = CPUID_GET_VENDOR_STRING;
|
||||||
else
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
MaxStandardLeaf = CpuRegisters.Eax;
|
||||||
|
|
||||||
|
/* Get maximum CPUID extended leaf */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_EXTENDED_MAX;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
MaxExtendedLeaf = CpuRegisters.Eax;
|
||||||
|
|
||||||
|
/* Check if CPU supports standard features leaf */
|
||||||
|
if(MaxStandardLeaf >= CPUID_GET_STANDARD1_FEATURES)
|
||||||
{
|
{
|
||||||
/* Use initial structures */
|
/* Get CPU standard features */
|
||||||
Gdt = InitialGdt;
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
Idt = InitialIdt;
|
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
|
||||||
Tss = &InitialTss;
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
KernelBootStack = (PVOID)((ULONG_PTR)&BootStack + KERNEL_STACK_SIZE);
|
|
||||||
KernelFaultStack = (PVOID)((ULONG_PTR)&FaultStack + KERNEL_STACK_SIZE);
|
/* Store CPU standard features in processor control block */
|
||||||
KernelNmiStack = (PVOID)((ULONG_PTR)&NmiStack + KERNEL_STACK_SIZE);
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE3) Prcb->CpuId.FeatureBits |= KCF_SSE3;
|
||||||
ProcessorBlock = &InitialProcessorBlock;
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_VMX) Prcb->CpuId.FeatureBits |= KCF_VMX;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSSE3) Prcb->CpuId.FeatureBits |= KCF_SSSE3;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE4_1) Prcb->CpuId.FeatureBits |= KCF_SSE41;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE4_2) Prcb->CpuId.FeatureBits |= KCF_SSE42;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_X2APIC) Prcb->CpuId.FeatureBits |= KCF_X2APIC;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_POPCNT) Prcb->CpuId.FeatureBits |= KCF_POPCNT;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_TSC_DEADLINE) Prcb->CpuId.FeatureBits |= KCF_TSC_DEADLINE;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_AES) Prcb->CpuId.FeatureBits |= KCF_AES;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_XSAVE) Prcb->CpuId.FeatureBits |= KCF_XSAVE;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_AVX) Prcb->CpuId.FeatureBits |= KCF_AVX;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_RDRAND) Prcb->CpuId.FeatureBits |= KCF_RDRAND;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_VME) Prcb->CpuId.FeatureBits |= KCF_VME;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PSE) Prcb->CpuId.FeatureBits |= KCF_LARGE_PAGE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_TSC) Prcb->CpuId.FeatureBits |= KCF_RDTSC;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PAE) Prcb->CpuId.FeatureBits |= KCF_PAE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MCE) Prcb->CpuId.FeatureBits |= KCF_MCE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_CX8) Prcb->CpuId.FeatureBits |= KCF_CMPXCHG8B;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_APIC) Prcb->CpuId.FeatureBits |= KCF_APIC;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SEP) Prcb->CpuId.FeatureBits |= KCF_FAST_SYSCALL;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MTRR) Prcb->CpuId.FeatureBits |= KCF_MTRR;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PGE) Prcb->CpuId.FeatureBits |= KCF_GLOBAL_PAGE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MCA) Prcb->CpuId.FeatureBits |= KCF_MCA;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_CMOV) Prcb->CpuId.FeatureBits |= KCF_CMOV;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PAT) Prcb->CpuId.FeatureBits |= KCF_PAT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_PSE36) Prcb->CpuId.FeatureBits |= KCF_PSE36;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_CLFLUSH) Prcb->CpuId.FeatureBits |= KCF_CLFLUSH;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_FXSR) Prcb->CpuId.FeatureBits |= KCF_FXSR;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_ACPI) Prcb->CpuId.FeatureBits |= KCF_ACPI;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_MMX) Prcb->CpuId.FeatureBits |= KCF_MMX;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SSE) Prcb->CpuId.FeatureBits |= KCF_SSE;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SSE2) Prcb->CpuId.FeatureBits |= KCF_SSE2;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_HTT) Prcb->CpuId.FeatureBits |= KCF_SMT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize processor block */
|
/* Check if CPU supports standard7 features leaf */
|
||||||
InitializeProcessorBlock(ProcessorBlock, Gdt, Idt, Tss, KernelFaultStack);
|
if(MaxStandardLeaf >= CPUID_GET_STANDARD7_FEATURES)
|
||||||
|
{
|
||||||
|
/* Get CPU standard features */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_STANDARD7_FEATURES;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Initialize GDT, IDT and TSS */
|
/* Store CPU standard7 features in processor control block */
|
||||||
InitializeGdt(ProcessorBlock);
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_FSGSBASE) Prcb->CpuId.FeatureBits |= KCF_FSGSBASE;
|
||||||
InitializeIdt(ProcessorBlock);
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_AVX2) Prcb->CpuId.FeatureBits |= KCF_AVX2;
|
||||||
InitializeTss(ProcessorBlock, KernelBootStack, KernelFaultStack, KernelNmiStack);
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_SMEP) Prcb->CpuId.FeatureBits |= KCF_SMEP;
|
||||||
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_RDSEED) Prcb->CpuId.FeatureBits |= KCF_RDSEED;
|
||||||
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_SMAP) Prcb->CpuId.FeatureBits |= KCF_SMAP;
|
||||||
|
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_SHA) Prcb->CpuId.FeatureBits |= KCF_SHA;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_LA57) Prcb->CpuId.FeatureBits |= KCF_LA57;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set GDT and IDT descriptors */
|
/* Check if CPU supports power management leaf */
|
||||||
GdtDescriptor.Base = Gdt;
|
if(MaxStandardLeaf >= CPUID_GET_POWER_MANAGEMENT)
|
||||||
GdtDescriptor.Limit = (GDT_ENTRIES * sizeof(KGDTENTRY)) - 1;
|
{
|
||||||
IdtDescriptor.Base = Idt;
|
/* Get CPU power management features */
|
||||||
IdtDescriptor.Limit = (IDT_ENTRIES * sizeof(KIDTENTRY)) - 1;
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_POWER_MANAGEMENT;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Load GDT, IDT and TSS */
|
/* Store CPU power management features in processor control block */
|
||||||
AR::CpuFunc::LoadGlobalDescriptorTable(&GdtDescriptor.Limit);
|
if(CpuRegisters.Eax & CPUID_FEATURES_EAX_ARAT) Prcb->CpuId.FeatureBits |= KCF_ARAT;
|
||||||
AR::CpuFunc::LoadInterruptDescriptorTable(&IdtDescriptor.Limit);
|
}
|
||||||
AR::CpuFunc::LoadTaskRegister((UINT)KGDT_SYS_TSS);
|
|
||||||
|
|
||||||
/* Enter passive IRQ level */
|
/* Check if CPU supports extended features leaf */
|
||||||
HL::RunLevel::SetRunLevel(PASSIVE_LEVEL);
|
if(MaxExtendedLeaf >= CPUID_GET_EXTENDED_FEATURES)
|
||||||
|
{
|
||||||
|
/* Get CPU extended features */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_EXTENDED_FEATURES;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Initialize segment registers */
|
/* Store CPU extended features in processor control block */
|
||||||
InitializeSegments();
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SVM) Prcb->CpuId.ExtendedFeatureBits |= KCF_SVM;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE4A) Prcb->CpuId.ExtendedFeatureBits |= KCF_SSE4A;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_FMA4) Prcb->CpuId.ExtendedFeatureBits |= KCF_FMA4;
|
||||||
|
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_TOPOLOGY_EXTENSIONS) Prcb->CpuId.ExtendedFeatureBits |= KCF_TOPOEXT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_SYSCALL_SYSRET) Prcb->CpuId.ExtendedFeatureBits |= KCF_SYSCALL;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_NX) Prcb->CpuId.ExtendedFeatureBits |= KCF_NX_BIT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_RDTSCP) Prcb->CpuId.ExtendedFeatureBits |= KCF_RDTSCP;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_LONG_MODE) Prcb->CpuId.ExtendedFeatureBits |= KCF_64BIT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_3DNOW_EXT) Prcb->CpuId.ExtendedFeatureBits |= KCF_3DNOW_EXT;
|
||||||
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_3DNOW) Prcb->CpuId.ExtendedFeatureBits |= KCF_3DNOW;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize processor registers */
|
/* Check if CPU supports advanced power management leaf */
|
||||||
InitializeProcessorRegisters();
|
if(MaxExtendedLeaf >= CPUID_GET_ADVANCED_POWER_MANAGEMENT)
|
||||||
|
{
|
||||||
|
/* Get CPU advanced power management features */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
|
CpuRegisters.Leaf = CPUID_GET_ADVANCED_POWER_MANAGEMENT;
|
||||||
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Identify processor */
|
/* Store CPU advanced power management features in processor control block */
|
||||||
IdentifyProcessor();
|
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_TSCI) Prcb->CpuId.ExtendedFeatureBits |= KCF_INVARIANT_TSC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -274,6 +341,76 @@ AR::ProcSup::InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock)
|
|||||||
SetIdtGate(ProcessorBlock->IdtBase, 0x2E, (PVOID)ArTrapEntry[0x2E], KGDT_R0_CODE, 0, KIDT_ACCESS_RING3, I686_INTERRUPT_GATE);
|
SetIdtGate(ProcessorBlock->IdtBase, 0x2E, (PVOID)ArTrapEntry[0x2E], KGDT_R0_CODE, 0, KIDT_ACCESS_RING3, I686_INTERRUPT_GATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes i686 processor specific structures.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
AR::ProcSup::InitializeProcessor(IN PVOID ProcessorStructures)
|
||||||
|
{
|
||||||
|
KDESCRIPTOR GdtDescriptor, IdtDescriptor;
|
||||||
|
PVOID KernelBootStack, KernelFaultStack, KernelNmiStack;
|
||||||
|
PKPROCESSOR_BLOCK ProcessorBlock;
|
||||||
|
PKGDTENTRY Gdt;
|
||||||
|
PKIDTENTRY Idt;
|
||||||
|
PKTSS Tss;
|
||||||
|
|
||||||
|
/* Check if processor structures buffer provided */
|
||||||
|
if(ProcessorStructures)
|
||||||
|
{
|
||||||
|
/* Assign CPU structures from provided buffer */
|
||||||
|
InitializeProcessorStructures(ProcessorStructures, &Gdt, &Tss, &ProcessorBlock,
|
||||||
|
&KernelBootStack, &KernelFaultStack, &KernelNmiStack);
|
||||||
|
|
||||||
|
/* Use global IDT */
|
||||||
|
Idt = InitialIdt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Use initial structures */
|
||||||
|
Gdt = InitialGdt;
|
||||||
|
Idt = InitialIdt;
|
||||||
|
Tss = &InitialTss;
|
||||||
|
KernelBootStack = (PVOID)((ULONG_PTR)&BootStack + KERNEL_STACK_SIZE);
|
||||||
|
KernelFaultStack = (PVOID)((ULONG_PTR)&FaultStack + KERNEL_STACK_SIZE);
|
||||||
|
KernelNmiStack = (PVOID)((ULONG_PTR)&NmiStack + KERNEL_STACK_SIZE);
|
||||||
|
ProcessorBlock = &InitialProcessorBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize processor block */
|
||||||
|
InitializeProcessorBlock(ProcessorBlock, Gdt, Idt, Tss, KernelFaultStack);
|
||||||
|
|
||||||
|
/* Initialize GDT, IDT and TSS */
|
||||||
|
InitializeGdt(ProcessorBlock);
|
||||||
|
InitializeIdt(ProcessorBlock);
|
||||||
|
InitializeTss(ProcessorBlock, KernelBootStack, KernelFaultStack, KernelNmiStack);
|
||||||
|
|
||||||
|
/* Set GDT and IDT descriptors */
|
||||||
|
GdtDescriptor.Base = Gdt;
|
||||||
|
GdtDescriptor.Limit = (GDT_ENTRIES * sizeof(KGDTENTRY)) - 1;
|
||||||
|
IdtDescriptor.Base = Idt;
|
||||||
|
IdtDescriptor.Limit = (IDT_ENTRIES * sizeof(KIDTENTRY)) - 1;
|
||||||
|
|
||||||
|
/* Load GDT, IDT and TSS */
|
||||||
|
AR::CpuFunc::LoadGlobalDescriptorTable(&GdtDescriptor.Limit);
|
||||||
|
AR::CpuFunc::LoadInterruptDescriptorTable(&IdtDescriptor.Limit);
|
||||||
|
AR::CpuFunc::LoadTaskRegister((UINT)KGDT_SYS_TSS);
|
||||||
|
|
||||||
|
/* Initialize segment registers */
|
||||||
|
InitializeSegments();
|
||||||
|
|
||||||
|
/* Initialize processor registers */
|
||||||
|
InitializeProcessorRegisters();
|
||||||
|
|
||||||
|
/* Identify processor */
|
||||||
|
IdentifyProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes processor block.
|
* Initializes processor block.
|
||||||
*
|
*
|
||||||
@@ -391,26 +528,49 @@ AR::ProcSup::InitializeProcessorStructures(IN PVOID ProcessorStructures,
|
|||||||
Address = ROUND_UP((UINT_PTR)ProcessorStructures, MM_PAGE_SIZE) + KERNEL_STACK_SIZE;
|
Address = ROUND_UP((UINT_PTR)ProcessorStructures, MM_PAGE_SIZE) + KERNEL_STACK_SIZE;
|
||||||
|
|
||||||
/* Assign a space for kernel boot stack and advance */
|
/* Assign a space for kernel boot stack and advance */
|
||||||
|
if(KernelBootStack != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return kernel boot stack address */
|
||||||
*KernelBootStack = (PVOID)Address;
|
*KernelBootStack = (PVOID)Address;
|
||||||
|
}
|
||||||
Address += KERNEL_STACK_SIZE;
|
Address += KERNEL_STACK_SIZE;
|
||||||
|
|
||||||
/* Assign a space for kernel fault stack and advance */
|
/* Assign a space for kernel fault stack and advance */
|
||||||
|
if(KernelFaultStack != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return kernel fault stack address */
|
||||||
*KernelFaultStack = (PVOID)Address;
|
*KernelFaultStack = (PVOID)Address;
|
||||||
|
}
|
||||||
Address += KERNEL_STACK_SIZE;
|
Address += KERNEL_STACK_SIZE;
|
||||||
|
|
||||||
/* Assign a space for kernel NMI stack, no advance needed as stack grows down */
|
/* Assign a space for kernel NMI stack, no advance needed as stack grows down */
|
||||||
|
if(KernelNmiStack != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return kernel NMI stack address */
|
||||||
*KernelNmiStack = (PVOID)Address;
|
*KernelNmiStack = (PVOID)Address;
|
||||||
|
}
|
||||||
|
|
||||||
/* Assign a space for GDT and advance */
|
/* Assign a space for GDT and advance */
|
||||||
|
if(Gdt != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return GDT base address */
|
||||||
*Gdt = (PKGDTENTRY)(PVOID)Address;
|
*Gdt = (PKGDTENTRY)(PVOID)Address;
|
||||||
Address += sizeof(InitialGdt);
|
}
|
||||||
|
Address += (GDT_ENTRIES * sizeof(KGDTENTRY));
|
||||||
|
|
||||||
|
/* Assign a space for TSS and advance */
|
||||||
|
if(Tss != NULLPTR)
|
||||||
|
{
|
||||||
|
*Tss = (PKTSS)(PVOID)Address;
|
||||||
|
}
|
||||||
|
Address += sizeof(KTSS);
|
||||||
|
|
||||||
/* Assign a space for Processor Block and advance */
|
/* Assign a space for Processor Block and advance */
|
||||||
|
if(ProcessorBlock != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Return processor block address */
|
||||||
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
|
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
|
||||||
Address += sizeof(InitialProcessorBlock);
|
}
|
||||||
|
|
||||||
/* Assign a space for TSS */
|
|
||||||
*Tss = (PKTSS)(PVOID)Address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -127,6 +127,24 @@ HL::Acpi::GetAcpiTimerInfo(OUT PACPI_TIMER_INFO *AcpiTimerInfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ACPI system information structure containing processor and topology data.
|
||||||
|
*
|
||||||
|
* @param SystemInfo
|
||||||
|
* Supplies a pointer to the memory area where the pointer to the system information structure will be stored.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
HL::Acpi::GetSystemInformation(OUT PACPI_SYSTEM_INFO *SystemInfo)
|
||||||
|
{
|
||||||
|
/* Return a pointer to the ACPI system information */
|
||||||
|
*SystemInfo = &HL::Acpi::SystemInfo;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs an initialization of the ACPI subsystem.
|
* Performs an initialization of the ACPI subsystem.
|
||||||
*
|
*
|
||||||
@@ -478,7 +496,7 @@ HL::Acpi::InitializeAcpiSystemStructure(VOID)
|
|||||||
PageCount = SIZE_TO_PAGES(CpuCount * sizeof(PROCESSOR_IDENTITY));
|
PageCount = SIZE_TO_PAGES(CpuCount * sizeof(PROCESSOR_IDENTITY));
|
||||||
|
|
||||||
/* Allocate memory for CPU information */
|
/* Allocate memory for CPU information */
|
||||||
Status = MM::HardwarePool::AllocateHardwareMemory(PageCount, TRUE, &PhysicalAddress);
|
Status = MM::HardwarePool::AllocateHardwareMemory(PageCount, TRUE, MM_MAXIMUM_PHYSICAL_ADDRESS, &PhysicalAddress);
|
||||||
if(Status != STATUS_SUCCESS)
|
if(Status != STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
/* Failed to allocate memory, return error */
|
/* Failed to allocate memory, return error */
|
||||||
|
|||||||
@@ -78,28 +78,13 @@ XTAPI
|
|||||||
BOOLEAN
|
BOOLEAN
|
||||||
HL::Pic::CheckApicSupport(VOID)
|
HL::Pic::CheckApicSupport(VOID)
|
||||||
{
|
{
|
||||||
CPUID_REGISTERS CpuRegisters;
|
PKPROCESSOR_CONTROL_BLOCK Prcb;
|
||||||
|
|
||||||
/* Prepare CPUID registers */
|
/* Get current processor control block */
|
||||||
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
|
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
|
|
||||||
/* Get CPUID */
|
/* Return APIC status */
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
return (Prcb->CpuId.FeatureBits & KCF_APIC) ? TRUE : FALSE;
|
||||||
|
|
||||||
/* Check APIC status from the CPUID results */
|
|
||||||
if(!(CpuRegisters.Edx & CPUID_FEATURES_EDX_APIC))
|
|
||||||
{
|
|
||||||
/* APIC is not supported */
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* APIC is supported */
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,28 +101,21 @@ XTAPI
|
|||||||
BOOLEAN
|
BOOLEAN
|
||||||
HL::Pic::CheckX2ApicSupport(VOID)
|
HL::Pic::CheckX2ApicSupport(VOID)
|
||||||
{
|
{
|
||||||
CPUID_REGISTERS CpuRegisters;
|
PKPROCESSOR_CONTROL_BLOCK Prcb;
|
||||||
|
PCWSTR KernelParameter;
|
||||||
|
|
||||||
/* Prepare CPUID registers */
|
/* Check if the user forced xAPIC via boot parameters */
|
||||||
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
|
if(KE::BootInformation::GetKernelParameter(L"NOX2APIC", &KernelParameter) == STATUS_SUCCESS)
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
|
|
||||||
/* Get CPUID */
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
|
||||||
|
|
||||||
/* Check x2APIC status from the CPUID results */
|
|
||||||
if(!(CpuRegisters.Ecx & CPUID_FEATURES_ECX_X2APIC))
|
|
||||||
{
|
{
|
||||||
/* x2APIC is not supported */
|
/* The NOX2APIC flag is present, explicitly disable x2APIC support */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* x2APIC is supported */
|
/* Get current processor control block */
|
||||||
return TRUE;
|
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
||||||
|
|
||||||
|
/* Return x2APIC status */
|
||||||
|
return (Prcb->CpuId.FeatureBits & KCF_X2APIC) ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -402,6 +380,9 @@ HL::Pic::InitializeApic(VOID)
|
|||||||
WriteApicRegister(APIC_LDR, (1UL << CpuNumber) << 24);
|
WriteApicRegister(APIC_LDR, (1UL << CpuNumber) << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Report the APIC ID to the kernel logic */
|
||||||
|
KE::Processor::RegisterHardwareId(GetCpuApicId());
|
||||||
|
|
||||||
/* Configure the spurious interrupt vector */
|
/* Configure the spurious interrupt vector */
|
||||||
SpuriousRegister.Long = ReadApicRegister(APIC_SIVR);
|
SpuriousRegister.Long = ReadApicRegister(APIC_SIVR);
|
||||||
SpuriousRegister.Vector = APIC_VECTOR_SPURIOUS;
|
SpuriousRegister.Vector = APIC_VECTOR_SPURIOUS;
|
||||||
@@ -781,25 +762,21 @@ VOID
|
|||||||
HL::Pic::SendBroadcastIpi(IN ULONG Vector,
|
HL::Pic::SendBroadcastIpi(IN ULONG Vector,
|
||||||
IN BOOLEAN Self)
|
IN BOOLEAN Self)
|
||||||
{
|
{
|
||||||
APIC_COMMAND_REGISTER Register;
|
PKPROCESSOR_BLOCK CurrentProcessorBlock, TargetProcessorBlock;
|
||||||
|
PACPI_SYSTEM_INFO SysInfo;
|
||||||
BOOLEAN Interrupts;
|
BOOLEAN Interrupts;
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
/* SMP not implemented */
|
/* Get the current processor block */
|
||||||
if(TRUE)
|
CurrentProcessorBlock = KE::Processor::GetCurrentProcessorBlock();
|
||||||
|
if(CurrentProcessorBlock == NULLPTR)
|
||||||
{
|
{
|
||||||
/* Check if IPI is addressed to the current CPU */
|
/* Processor block not available, return */
|
||||||
if(Self)
|
|
||||||
{
|
|
||||||
/* Send IPI to the current CPU */
|
|
||||||
SendSelfIpi(Vector);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
/* Get the ACPI system information */
|
||||||
/* Nothing to do */
|
HL::Acpi::GetSystemInformation(&SysInfo);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check whether interrupts are enabled */
|
/* Check whether interrupts are enabled */
|
||||||
Interrupts = AR::CpuFunc::InterruptsEnabled();
|
Interrupts = AR::CpuFunc::InterruptsEnabled();
|
||||||
@@ -807,32 +784,31 @@ HL::Pic::SendBroadcastIpi(IN ULONG Vector,
|
|||||||
/* Disable interrupts */
|
/* Disable interrupts */
|
||||||
AR::CpuFunc::ClearInterruptFlag();
|
AR::CpuFunc::ClearInterruptFlag();
|
||||||
|
|
||||||
/* Prepare the APIC command register */
|
/* Iterate over all logical CPUs */
|
||||||
Register.LongLong = 0;
|
for(Index = 0; Index < SysInfo->CpuCount; Index++)
|
||||||
Register.DeliveryMode = APIC_DM_FIXED;
|
|
||||||
Register.DestinationShortHand = Self ? APIC_DSH_AllIncludingSelf : APIC_DSH_AllExclusingSelf;
|
|
||||||
Register.Level = 1;
|
|
||||||
Register.TriggerMode = APIC_TGM_EDGE;
|
|
||||||
Register.Vector = Vector;
|
|
||||||
|
|
||||||
/* Check current APIC mode */
|
|
||||||
if(ApicMode == APIC_MODE_X2APIC)
|
|
||||||
{
|
{
|
||||||
/* In x2APIC mode, writing the full 64-bit value to the ICR MSR is sufficient */
|
/* Retrieve the target processor block by its Logical CPU Number */
|
||||||
WriteApicRegister(APIC_ICR0, Register.LongLong);
|
TargetProcessorBlock = KE::Processor::GetProcessorBlock(Index);
|
||||||
|
|
||||||
|
/* Only send to 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)
|
||||||
|
{
|
||||||
|
/* Dispatch the IPI to the current processor */
|
||||||
|
SendSelfIpi(Vector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Wait for the APIC to clear the delivery status */
|
/* Dispatch the IPI to the target processor */
|
||||||
while((ReadApicRegister(APIC_ICR0) & 0x1000) != 0)
|
SendIpi(TargetProcessorBlock->HardwareId, Vector, APIC_DM_FIXED, APIC_DSH_Destination, APIC_TGM_EDGE);
|
||||||
{
|
}
|
||||||
/* Yield the processor */
|
|
||||||
AR::CpuFunc::YieldProcessor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In xAPIC compatibility mode, write the command to the ICR registers */
|
|
||||||
WriteApicRegister(APIC_ICR1, Register.Long1);
|
|
||||||
WriteApicRegister(APIC_ICR0, Register.Long0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check whether interrupts need to be re-enabled */
|
/* Check whether interrupts need to be re-enabled */
|
||||||
@@ -867,6 +843,15 @@ HL::Pic::SendEoi(VOID)
|
|||||||
* @param Vector
|
* @param Vector
|
||||||
* Supplies the IPI vector to send.
|
* Supplies the IPI vector to send.
|
||||||
*
|
*
|
||||||
|
* @param DeliveryMode
|
||||||
|
* Supplies the delivery mode for the IPI.
|
||||||
|
*
|
||||||
|
* @param DestinationShorthand
|
||||||
|
* Supplies the shorthand.
|
||||||
|
*
|
||||||
|
* @param TriggerMode
|
||||||
|
* Supplies the trigger mode (Edge or Level).
|
||||||
|
*
|
||||||
* @return This routine does not return any value.
|
* @return This routine does not return any value.
|
||||||
*
|
*
|
||||||
* @since XT 1.0
|
* @since XT 1.0
|
||||||
@@ -874,19 +859,85 @@ HL::Pic::SendEoi(VOID)
|
|||||||
XTAPI
|
XTAPI
|
||||||
VOID
|
VOID
|
||||||
HL::Pic::SendIpi(IN ULONG ApicId,
|
HL::Pic::SendIpi(IN ULONG ApicId,
|
||||||
IN ULONG Vector)
|
IN ULONG Vector,
|
||||||
|
IN APIC_DM DeliveryMode,
|
||||||
|
IN APIC_DSH DestinationShortHand,
|
||||||
|
IN ULONG TriggerMode)
|
||||||
{
|
{
|
||||||
|
APIC_COMMAND_REGISTER Register;
|
||||||
|
BOOLEAN Interrupts;
|
||||||
|
|
||||||
|
/* Check whether interrupts are enabled */
|
||||||
|
Interrupts = AR::CpuFunc::InterruptsEnabled();
|
||||||
|
|
||||||
|
/* Disable interrupts */
|
||||||
|
AR::CpuFunc::ClearInterruptFlag();
|
||||||
|
|
||||||
|
/* Check current APIC mode and destination */
|
||||||
|
if(ApicMode == APIC_MODE_X2APIC && DestinationShortHand == APIC_DSH_Self)
|
||||||
|
{
|
||||||
|
/* In x2APIC mode, a dedicated Self-IPI register is used */
|
||||||
|
WriteApicRegister(APIC_SIPI, Vector);
|
||||||
|
|
||||||
|
/* Check whether interrupts need to be re-enabled */
|
||||||
|
if(Interrupts)
|
||||||
|
{
|
||||||
|
/* Check whether interrupts need to be re-enabled */
|
||||||
|
AR::CpuFunc::SetInterruptFlag();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing more to do */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare APIC command register struct */
|
||||||
|
Register.LongLong = 0;
|
||||||
|
Register.DeliveryMode = DeliveryMode;
|
||||||
|
Register.Destination = ApicId;
|
||||||
|
Register.DestinationShortHand = DestinationShortHand;
|
||||||
|
Register.Level = 1;
|
||||||
|
Register.TriggerMode = TriggerMode;
|
||||||
|
Register.Vector = Vector;
|
||||||
|
|
||||||
/* Check current APIC mode */
|
/* Check current APIC mode */
|
||||||
if(ApicMode == APIC_MODE_X2APIC)
|
if(ApicMode == APIC_MODE_X2APIC)
|
||||||
{
|
{
|
||||||
|
/* Set destination APIC ID */
|
||||||
|
Register.Long1 = ApicId;
|
||||||
|
|
||||||
/* Send IPI using x2APIC mode */
|
/* Send IPI using x2APIC mode */
|
||||||
WriteApicRegister(APIC_ICR0, ((ULONGLONG)ApicId << 32) | Vector);
|
WriteApicRegister(APIC_ICR0, Register.LongLong);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Send IPI using xAPIC compatibility mode */
|
/* Wait for the APIC to clear the delivery status */
|
||||||
WriteApicRegister(APIC_ICR1, ApicId << 24);
|
while((ReadApicRegister(APIC_ICR0) & 0x1000) != 0)
|
||||||
WriteApicRegister(APIC_ICR0, Vector);
|
{
|
||||||
|
/* Yield the processor */
|
||||||
|
AR::CpuFunc::YieldProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In xAPIC compatibility mode, write the command to the ICR registers */
|
||||||
|
WriteApicRegister(APIC_ICR1, Register.Long1);
|
||||||
|
WriteApicRegister(APIC_ICR0, Register.Long0);
|
||||||
|
|
||||||
|
/* Check if this is a Self-IPI */
|
||||||
|
if(DestinationShortHand == APIC_DSH_Self)
|
||||||
|
{
|
||||||
|
/* Wait until the interrupt physically arrives in the requested state */
|
||||||
|
while((ReadApicRegister((APIC_REGISTER)(APIC_IRR + (Vector / 32))) & (1UL << (Vector % 32))) == 0)
|
||||||
|
{
|
||||||
|
/* Yield the processor */
|
||||||
|
AR::CpuFunc::YieldProcessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether interrupts need to be re-enabled */
|
||||||
|
if(Interrupts)
|
||||||
|
{
|
||||||
|
/* Re-enable interrupts */
|
||||||
|
AR::CpuFunc::SetInterruptFlag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,55 +955,7 @@ XTAPI
|
|||||||
VOID
|
VOID
|
||||||
HL::Pic::SendSelfIpi(IN ULONG Vector)
|
HL::Pic::SendSelfIpi(IN ULONG Vector)
|
||||||
{
|
{
|
||||||
APIC_COMMAND_REGISTER Register;
|
SendIpi(0, Vector, APIC_DM_FIXED, APIC_DSH_Self, APIC_TGM_EDGE);
|
||||||
BOOLEAN Interrupts;
|
|
||||||
|
|
||||||
/* Check whether interrupts are enabled */
|
|
||||||
Interrupts = AR::CpuFunc::InterruptsEnabled();
|
|
||||||
|
|
||||||
/* Disable interrupts */
|
|
||||||
AR::CpuFunc::ClearInterruptFlag();
|
|
||||||
|
|
||||||
/* Check current APIC mode */
|
|
||||||
if(ApicMode == APIC_MODE_X2APIC)
|
|
||||||
{
|
|
||||||
/* In x2APIC mode, a dedicated Self-IPI register is used */
|
|
||||||
WriteApicRegister(APIC_SIPI, Vector);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Prepare APIC command register */
|
|
||||||
Register.LongLong = 0;
|
|
||||||
Register.DeliveryMode = APIC_DM_FIXED;
|
|
||||||
Register.DestinationShortHand = APIC_DSH_Self;
|
|
||||||
Register.TriggerMode = APIC_TGM_EDGE;
|
|
||||||
Register.Vector = Vector;
|
|
||||||
|
|
||||||
/* Wait for the APIC to clear the delivery status */
|
|
||||||
while((ReadApicRegister(APIC_ICR0) & 0x1000) != 0)
|
|
||||||
{
|
|
||||||
/* Yield the processor */
|
|
||||||
AR::CpuFunc::YieldProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In xAPIC compatibility mode, write the command to the ICR registers */
|
|
||||||
WriteApicRegister(APIC_ICR1, Register.Long1);
|
|
||||||
WriteApicRegister(APIC_ICR0, Register.Long0);
|
|
||||||
|
|
||||||
/* Wait until the interrupt physically arrives in the requested state */
|
|
||||||
while((ReadApicRegister((APIC_REGISTER)(APIC_IRR + (Vector / 32))) & (1UL << (Vector % 32))) == 0)
|
|
||||||
{
|
|
||||||
/* Yield the processor */
|
|
||||||
AR::CpuFunc::YieldProcessor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check whether interrupts need to be re-enabled */
|
|
||||||
if(Interrupts)
|
|
||||||
{
|
|
||||||
/* Re-enable interrupts */
|
|
||||||
AR::CpuFunc::SetInterruptFlag();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -925,84 +925,31 @@ XTAPI
|
|||||||
VOID
|
VOID
|
||||||
HL::Timer::QueryTimerCapabilities(VOID)
|
HL::Timer::QueryTimerCapabilities(VOID)
|
||||||
{
|
{
|
||||||
|
PKPROCESSOR_CONTROL_BLOCK Prcb;
|
||||||
CPUID_REGISTERS CpuRegisters;
|
CPUID_REGISTERS CpuRegisters;
|
||||||
ULONG MaxStandardLeaf;
|
ULONG MaxStandardLeaf;
|
||||||
ULONG MaxExtendedLeaf;
|
|
||||||
|
/* Get current processor control block */
|
||||||
|
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
|
||||||
|
|
||||||
|
/* Set timer capabilities based on supported CPU features */
|
||||||
|
TimerCapabilities.Arat = (Prcb->CpuId.FeatureBits & KCF_ARAT) != 0;
|
||||||
|
TimerCapabilities.InvariantTsc= (Prcb->CpuId.ExtendedFeatureBits & KCF_INVARIANT_TSC) != 0;
|
||||||
|
TimerCapabilities.RDTSCP = (Prcb->CpuId.ExtendedFeatureBits & KCF_RDTSCP) != 0;
|
||||||
|
TimerCapabilities.TscDeadline = (Prcb->CpuId.FeatureBits & KCF_TSC_DEADLINE) != 0;
|
||||||
|
|
||||||
/* Query maximum standard CPUID leaf */
|
/* Query maximum standard CPUID leaf */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
CpuRegisters.Leaf = CPUID_GET_VENDOR_STRING;
|
CpuRegisters.Leaf = CPUID_GET_VENDOR_STRING;
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Save maximum supported standard CPUID leaf */
|
|
||||||
MaxStandardLeaf = CpuRegisters.Eax;
|
MaxStandardLeaf = CpuRegisters.Eax;
|
||||||
|
|
||||||
/* Query maximum extended CPUID leaf */
|
|
||||||
CpuRegisters.Leaf = CPUID_GET_EXTENDED_MAX;
|
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
|
||||||
|
|
||||||
/* Save maximum supported extended CPUID leaf */
|
|
||||||
MaxExtendedLeaf = CpuRegisters.Eax;
|
|
||||||
|
|
||||||
/* Check TSC-Deadline mode if leaf supported */
|
|
||||||
if(MaxStandardLeaf >= CPUID_GET_STANDARD1_FEATURES)
|
|
||||||
{
|
|
||||||
/* Query the standard feature CPUI leaf */
|
|
||||||
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
|
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
|
||||||
|
|
||||||
/* Verify TSC-Deadline support */
|
|
||||||
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_TSC_DEADLINE)
|
|
||||||
{
|
|
||||||
/* Mark the TSC-Deadline mode as supported */
|
|
||||||
TimerCapabilities.TscDeadline = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check Always Running APIC Timer - ARAT if leaf supported */
|
|
||||||
if(MaxStandardLeaf >= CPUID_GET_POWER_MANAGEMENT)
|
|
||||||
{
|
|
||||||
/* Query the thermal and power management features CPUID leaf */
|
|
||||||
CpuRegisters.Leaf = CPUID_GET_POWER_MANAGEMENT;
|
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
|
||||||
|
|
||||||
/* Verify Always Running APIC Timer support */
|
|
||||||
if(CpuRegisters.Eax & CPUID_FEATURES_EAX_ARAT)
|
|
||||||
{
|
|
||||||
/* Mark the ARAT as supported */
|
|
||||||
TimerCapabilities.Arat = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check Always Running Timer - ART if leaf supported */
|
/* Check Always Running Timer - ART if leaf supported */
|
||||||
if(MaxStandardLeaf >= CPUID_GET_TSC_CRYSTAL_CLOCK)
|
if(MaxStandardLeaf >= CPUID_GET_TSC_CRYSTAL_CLOCK)
|
||||||
{
|
{
|
||||||
/* Query the Time Stamp Counter and Core Crystal Clock information CPUID leaf */
|
/* Query the Time Stamp Counter and Core Crystal Clock information CPUID leaf */
|
||||||
|
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
|
||||||
CpuRegisters.Leaf = CPUID_GET_TSC_CRYSTAL_CLOCK;
|
CpuRegisters.Leaf = CPUID_GET_TSC_CRYSTAL_CLOCK;
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
AR::CpuFunc::CpuId(&CpuRegisters);
|
||||||
|
|
||||||
/* Verify Always Running Timer support */
|
/* Verify Always Running Timer support */
|
||||||
@@ -1023,46 +970,6 @@ HL::Timer::QueryTimerCapabilities(VOID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check RDTSCP instruction support if leaf supported */
|
|
||||||
if(MaxExtendedLeaf >= CPUID_GET_EXTENDED_FEATURES)
|
|
||||||
{
|
|
||||||
/* Query the extended processor features CPUID leaf */
|
|
||||||
CpuRegisters.Leaf = CPUID_GET_EXTENDED_FEATURES;
|
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
|
||||||
|
|
||||||
/* Verify RDTSCP support */
|
|
||||||
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_RDTSCP)
|
|
||||||
{
|
|
||||||
/* Mark the RDTSCP instruction as supported */
|
|
||||||
TimerCapabilities.RDTSCP = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check Invariant TSC if leaf supported */
|
|
||||||
if(MaxExtendedLeaf >= CPUID_GET_ADVANCED_POWER_MANAGEMENT)
|
|
||||||
{
|
|
||||||
/* Query the advanced power management features CPUID leaf */
|
|
||||||
CpuRegisters.Leaf = CPUID_GET_ADVANCED_POWER_MANAGEMENT;
|
|
||||||
CpuRegisters.SubLeaf = 0;
|
|
||||||
CpuRegisters.Eax = 0;
|
|
||||||
CpuRegisters.Ebx = 0;
|
|
||||||
CpuRegisters.Ecx = 0;
|
|
||||||
CpuRegisters.Edx = 0;
|
|
||||||
AR::CpuFunc::CpuId(&CpuRegisters);
|
|
||||||
|
|
||||||
/* Verify Invariant TSC support */
|
|
||||||
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_TSCI)
|
|
||||||
{
|
|
||||||
/* Mark the Invariant TSC feature as supported */
|
|
||||||
TimerCapabilities.InvariantTsc = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ namespace AR
|
|||||||
OUT PVOID *TrampolineCode,
|
OUT PVOID *TrampolineCode,
|
||||||
OUT PULONG_PTR TrampolineSize);
|
OUT PULONG_PTR TrampolineSize);
|
||||||
STATIC XTAPI VOID InitializeProcessor(IN PVOID ProcessorStructures);
|
STATIC XTAPI VOID InitializeProcessor(IN PVOID ProcessorStructures);
|
||||||
|
STATIC XTAPI VOID InitializeProcessorStructures(IN PVOID ProcessorStructures,
|
||||||
|
OUT PKGDTENTRY *Gdt,
|
||||||
|
OUT PKTSS *Tss,
|
||||||
|
OUT PKPROCESSOR_BLOCK *ProcessorBlock,
|
||||||
|
OUT PVOID *KernelBootStack,
|
||||||
|
OUT PVOID *KernelFaultStack,
|
||||||
|
OUT PVOID *KernelNmiStack);
|
||||||
STATIC XTAPI VOID SetIdtGate(IN PKIDTENTRY Idt,
|
STATIC XTAPI VOID SetIdtGate(IN PKIDTENTRY Idt,
|
||||||
IN USHORT Vector,
|
IN USHORT Vector,
|
||||||
IN PVOID Handler,
|
IN PVOID Handler,
|
||||||
@@ -42,6 +49,7 @@ namespace AR
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
STATIC XTAPI VOID IdentifyProcessor(VOID);
|
STATIC XTAPI VOID IdentifyProcessor(VOID);
|
||||||
|
STATIC XTAPI VOID IdentifyProcessorFeatures(VOID);
|
||||||
STATIC XTAPI VOID InitializeGdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
STATIC XTAPI VOID InitializeGdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
||||||
STATIC XTAPI VOID InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
STATIC XTAPI VOID InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
||||||
STATIC XTAPI VOID InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBlock,
|
STATIC XTAPI VOID InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBlock,
|
||||||
@@ -50,13 +58,6 @@ namespace AR
|
|||||||
IN PKTSS Tss,
|
IN PKTSS Tss,
|
||||||
IN PVOID DpcStack);
|
IN PVOID DpcStack);
|
||||||
STATIC XTAPI VOID InitializeProcessorRegisters(VOID);
|
STATIC XTAPI VOID InitializeProcessorRegisters(VOID);
|
||||||
STATIC XTAPI VOID InitializeProcessorStructures(IN PVOID ProcessorStructures,
|
|
||||||
OUT PKGDTENTRY *Gdt,
|
|
||||||
OUT PKTSS *Tss,
|
|
||||||
OUT PKPROCESSOR_BLOCK *ProcessorBlock,
|
|
||||||
OUT PVOID *KernelBootStack,
|
|
||||||
OUT PVOID *KernelFaultStack,
|
|
||||||
OUT PVOID *KernelNmiStack);
|
|
||||||
STATIC XTAPI VOID InitializeSegments(VOID);
|
STATIC XTAPI VOID InitializeSegments(VOID);
|
||||||
STATIC XTAPI VOID InitializeTss(IN PKPROCESSOR_BLOCK ProcessorBlock,
|
STATIC XTAPI VOID InitializeTss(IN PKPROCESSOR_BLOCK ProcessorBlock,
|
||||||
IN PVOID KernelBootStack,
|
IN PVOID KernelBootStack,
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ namespace AR
|
|||||||
OUT PVOID *TrampolineCode,
|
OUT PVOID *TrampolineCode,
|
||||||
OUT PULONG_PTR TrampolineSize);
|
OUT PULONG_PTR TrampolineSize);
|
||||||
STATIC XTAPI VOID InitializeProcessor(IN PVOID ProcessorStructures);
|
STATIC XTAPI VOID InitializeProcessor(IN PVOID ProcessorStructures);
|
||||||
|
STATIC XTAPI VOID InitializeProcessorStructures(IN PVOID ProcessorStructures,
|
||||||
|
OUT PKGDTENTRY *Gdt,
|
||||||
|
OUT PKTSS *Tss,
|
||||||
|
OUT PKPROCESSOR_BLOCK *ProcessorBlock,
|
||||||
|
OUT PVOID *KernelBootStack,
|
||||||
|
OUT PVOID *KernelFaultStack,
|
||||||
|
OUT PVOID *KernelNmiStack);
|
||||||
STATIC XTAPI VOID SetIdtGate(IN PKIDTENTRY Idt,
|
STATIC XTAPI VOID SetIdtGate(IN PKIDTENTRY Idt,
|
||||||
IN USHORT Vector,
|
IN USHORT Vector,
|
||||||
IN PVOID Handler,
|
IN PVOID Handler,
|
||||||
@@ -45,6 +52,7 @@ namespace AR
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
STATIC XTAPI VOID IdentifyProcessor(VOID);
|
STATIC XTAPI VOID IdentifyProcessor(VOID);
|
||||||
|
STATIC XTAPI VOID IdentifyProcessorFeatures(VOID);
|
||||||
STATIC XTAPI VOID InitializeGdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
STATIC XTAPI VOID InitializeGdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
||||||
STATIC XTAPI VOID InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
STATIC XTAPI VOID InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
|
||||||
STATIC XTAPI VOID InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBlock,
|
STATIC XTAPI VOID InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBlock,
|
||||||
@@ -53,13 +61,6 @@ namespace AR
|
|||||||
IN PKTSS Tss,
|
IN PKTSS Tss,
|
||||||
IN PVOID DpcStack);
|
IN PVOID DpcStack);
|
||||||
STATIC XTAPI VOID InitializeProcessorRegisters(VOID);
|
STATIC XTAPI VOID InitializeProcessorRegisters(VOID);
|
||||||
STATIC XTAPI VOID InitializeProcessorStructures(IN PVOID ProcessorStructures,
|
|
||||||
OUT PKGDTENTRY *Gdt,
|
|
||||||
OUT PKTSS *Tss,
|
|
||||||
OUT PKPROCESSOR_BLOCK *ProcessorBlock,
|
|
||||||
OUT PVOID *KernelBootStack,
|
|
||||||
OUT PVOID *KernelFaultStack,
|
|
||||||
OUT PVOID *KernelNmiStack);
|
|
||||||
STATIC XTAPI VOID InitializeSegments(VOID);
|
STATIC XTAPI VOID InitializeSegments(VOID);
|
||||||
STATIC XTAPI VOID InitializeTss(IN PKPROCESSOR_BLOCK ProcessorBlock,
|
STATIC XTAPI VOID InitializeTss(IN PKPROCESSOR_BLOCK ProcessorBlock,
|
||||||
IN PVOID KernelBootStack,
|
IN PVOID KernelBootStack,
|
||||||
@@ -79,7 +80,6 @@ namespace AR
|
|||||||
IN ULONG_PTR Base);
|
IN ULONG_PTR Base);
|
||||||
STATIC XTAPI VOID SetNonMaskableInterruptTssEntry(IN PKPROCESSOR_BLOCK ProcessorBlock,
|
STATIC XTAPI VOID SetNonMaskableInterruptTssEntry(IN PKPROCESSOR_BLOCK ProcessorBlock,
|
||||||
IN PVOID KernelNmiStack);
|
IN PVOID KernelNmiStack);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace HL
|
|||||||
STATIC XTAPI XTSTATUS GetAcpiTable(IN ULONG Signature,
|
STATIC XTAPI XTSTATUS GetAcpiTable(IN ULONG Signature,
|
||||||
OUT PACPI_DESCRIPTION_HEADER *AcpiTable);
|
OUT PACPI_DESCRIPTION_HEADER *AcpiTable);
|
||||||
STATIC XTAPI VOID GetAcpiTimerInfo(OUT PACPI_TIMER_INFO *AcpiTimerInfo);
|
STATIC XTAPI VOID GetAcpiTimerInfo(OUT PACPI_TIMER_INFO *AcpiTimerInfo);
|
||||||
|
STATIC XTAPI VOID GetSystemInformation(OUT PACPI_SYSTEM_INFO *SystemInfo);
|
||||||
STATIC XTAPI XTSTATUS InitializeAcpi(VOID);
|
STATIC XTAPI XTSTATUS InitializeAcpi(VOID);
|
||||||
STATIC XTAPI XTSTATUS InitializeAcpiSystemInformation(VOID);
|
STATIC XTAPI XTSTATUS InitializeAcpiSystemInformation(VOID);
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ namespace HL
|
|||||||
IN BOOLEAN Self);
|
IN BOOLEAN Self);
|
||||||
STATIC XTAPI VOID SendEoi(VOID);
|
STATIC XTAPI VOID SendEoi(VOID);
|
||||||
STATIC XTAPI VOID SendIpi(IN ULONG ApicId,
|
STATIC XTAPI VOID SendIpi(IN ULONG ApicId,
|
||||||
IN ULONG Vector);
|
IN ULONG Vector,
|
||||||
|
IN APIC_DM DeliveryMode,
|
||||||
|
IN APIC_DSH Destination,
|
||||||
|
IN ULONG TriggerMode);
|
||||||
STATIC XTAPI VOID SendSelfIpi(IN ULONG Vector);
|
STATIC XTAPI VOID SendSelfIpi(IN ULONG Vector);
|
||||||
STATIC XTFASTCALL VOID WriteApicRegister(IN APIC_REGISTER Register,
|
STATIC XTFASTCALL VOID WriteApicRegister(IN APIC_REGISTER Register,
|
||||||
IN ULONGLONG Value);
|
IN ULONGLONG Value);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace KD
|
|||||||
STATIC PKD_PRINT_ROUTINE KdPrint;
|
STATIC PKD_PRINT_ROUTINE KdPrint;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
STATIC KSPIN_LOCK DebugIoLock;
|
||||||
STATIC KD_DEBUG_MODE DebugMode;
|
STATIC KD_DEBUG_MODE DebugMode;
|
||||||
STATIC PKD_INIT_ROUTINE IoProvidersInitRoutines[KDBG_PROVIDERS_COUNT];
|
STATIC PKD_INIT_ROUTINE IoProvidersInitRoutines[KDBG_PROVIDERS_COUNT];
|
||||||
STATIC LIST_ENTRY Providers;
|
STATIC LIST_ENTRY Providers;
|
||||||
@@ -30,7 +31,7 @@ namespace KD
|
|||||||
public:
|
public:
|
||||||
STATIC XTCDECL VOID DbgPrint(PCWSTR Format,
|
STATIC XTCDECL VOID DbgPrint(PCWSTR Format,
|
||||||
...);
|
...);
|
||||||
STATIC XTCDECL VOID DbgPrintEx(PCWSTR Format,
|
STATIC XTCDECL VOID DbgPrint(PCWSTR Format,
|
||||||
VA_LIST Arguments);
|
VA_LIST Arguments);
|
||||||
STATIC XTAPI XTSTATUS InitializeDebugIoProviders(VOID);
|
STATIC XTAPI XTSTATUS InitializeDebugIoProviders(VOID);
|
||||||
STATIC XTAPI VOID SetPrintRoutine(PKD_PRINT_ROUTINE DebugPrintRoutine);
|
STATIC XTAPI VOID SetPrintRoutine(PKD_PRINT_ROUTINE DebugPrintRoutine);
|
||||||
|
|||||||
@@ -17,11 +17,20 @@ namespace KE
|
|||||||
{
|
{
|
||||||
class Processor
|
class Processor
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
STATIC ULONG InstalledCpus;
|
||||||
|
STATIC PKPROCESSOR_BLOCK *ProcessorBlocks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
STATIC XTAPI PKPROCESSOR_BLOCK GetCurrentProcessorBlock(VOID);
|
STATIC XTAPI PKPROCESSOR_BLOCK GetCurrentProcessorBlock(VOID);
|
||||||
STATIC XTAPI PKPROCESSOR_CONTROL_BLOCK GetCurrentProcessorControlBlock(VOID);
|
STATIC XTAPI PKPROCESSOR_CONTROL_BLOCK GetCurrentProcessorControlBlock(VOID);
|
||||||
STATIC XTAPI ULONG GetCurrentProcessorNumber(VOID);
|
STATIC XTAPI ULONG GetCurrentProcessorNumber(VOID);
|
||||||
STATIC XTAPI PKTHREAD GetCurrentThread(VOID);
|
STATIC XTAPI PKTHREAD GetCurrentThread(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 SaveProcessorState(OUT PKPROCESSOR_STATE CpuState);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ namespace MM
|
|||||||
STATIC XTAPI PVOID GetPxeVirtualAddress(IN PMMPXE PxePointer);
|
STATIC XTAPI PVOID GetPxeVirtualAddress(IN PMMPXE PxePointer);
|
||||||
STATIC XTAPI BOOLEAN GetXpaStatus(VOID);
|
STATIC XTAPI BOOLEAN GetXpaStatus(VOID);
|
||||||
STATIC XTAPI VOID InitializePageMapSupport(VOID);
|
STATIC XTAPI VOID InitializePageMapSupport(VOID);
|
||||||
|
STATIC XTAPI XTSTATUS MapVirtualAddress(IN PVOID VirtualAddress,
|
||||||
|
IN PFN_NUMBER PageFrameNumber,
|
||||||
|
IN ULONGLONG Attributes);
|
||||||
STATIC XTAPI BOOLEAN PteValid(IN PMMPTE PtePointer);
|
STATIC XTAPI BOOLEAN PteValid(IN PMMPTE PtePointer);
|
||||||
STATIC XTAPI VOID SetNextEntry(IN PMMPTE Pte,
|
STATIC XTAPI VOID SetNextEntry(IN PMMPTE Pte,
|
||||||
IN ULONG_PTR Value);
|
IN ULONG_PTR Value);
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ namespace MM
|
|||||||
public:
|
public:
|
||||||
STATIC XTAPI XTSTATUS AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
STATIC XTAPI XTSTATUS AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
||||||
IN BOOLEAN Aligned,
|
IN BOOLEAN Aligned,
|
||||||
|
IN ULONGLONG MaximumAddress,
|
||||||
OUT PPHYSICAL_ADDRESS Buffer);
|
OUT PPHYSICAL_ADDRESS Buffer);
|
||||||
|
STATIC XTAPI XTSTATUS AllocateRealModeMemory(IN PFN_NUMBER PageCount,
|
||||||
|
OUT PVOID *MemoryAddress);
|
||||||
STATIC XTAPI XTSTATUS MapHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
STATIC XTAPI XTSTATUS MapHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||||
IN PFN_NUMBER PageCount,
|
IN PFN_NUMBER PageCount,
|
||||||
IN BOOLEAN FlushTlb,
|
IN BOOLEAN FlushTlb,
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ namespace MM
|
|||||||
STATIC XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer);
|
STATIC XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer);
|
||||||
STATIC XTAPI BOOLEAN GetXpaStatus(VOID);
|
STATIC XTAPI BOOLEAN GetXpaStatus(VOID);
|
||||||
STATIC XTAPI VOID InitializePageMapSupport(VOID);
|
STATIC XTAPI VOID InitializePageMapSupport(VOID);
|
||||||
|
STATIC XTAPI XTSTATUS MapVirtualAddress(IN PVOID VirtualAddress,
|
||||||
|
IN PFN_NUMBER PageFrameNumber,
|
||||||
|
IN ULONGLONG Attributes);
|
||||||
STATIC XTAPI BOOLEAN PteValid(IN PMMPTE PtePointer);
|
STATIC XTAPI BOOLEAN PteValid(IN PMMPTE PtePointer);
|
||||||
STATIC XTAPI VOID SetNextEntry(IN PMMPTE Pte,
|
STATIC XTAPI VOID SetNextEntry(IN PMMPTE Pte,
|
||||||
IN ULONG_PTR Value);
|
IN ULONG_PTR Value);
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ namespace MM
|
|||||||
public:
|
public:
|
||||||
STATIC XTAPI XTSTATUS AllocateKernelStack(OUT PVOID *Stack,
|
STATIC XTAPI XTSTATUS AllocateKernelStack(OUT PVOID *Stack,
|
||||||
IN ULONG StackSize);
|
IN ULONG StackSize);
|
||||||
STATIC XTAPI XTSTATUS AllocateProcessorStructures(IN ULONG CpuNumber,
|
STATIC XTAPI XTSTATUS AllocateProcessorStructures(OUT PVOID *StructuresData);
|
||||||
OUT PVOID *StructuresData);
|
|
||||||
STATIC XTAPI VOID FreeKernelStack(IN PVOID Stack,
|
STATIC XTAPI VOID FreeKernelStack(IN PVOID Stack,
|
||||||
IN ULONG StackSize);
|
IN ULONG StackSize);
|
||||||
STATIC XTAPI VOID FreeProcessorStructures(IN PVOID StructuresData);
|
STATIC XTAPI VOID FreeProcessorStructures(IN PVOID StructuresData);
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ namespace RTL
|
|||||||
IN ULONG Length);
|
IN ULONG Length);
|
||||||
STATIC XTAPI SIZE_T StringLength(IN PCSTR String,
|
STATIC XTAPI SIZE_T StringLength(IN PCSTR String,
|
||||||
IN SIZE_T MaxLength);
|
IN SIZE_T MaxLength);
|
||||||
|
STATIC XTAPI XTSTATUS StringToNumber(IN PCSTR String,
|
||||||
|
IN ULONG Base,
|
||||||
|
OUT PULONG Value);
|
||||||
STATIC XTAPI SIZE_T StringToWideString(OUT PWCHAR Destination,
|
STATIC XTAPI SIZE_T StringToWideString(OUT PWCHAR Destination,
|
||||||
IN PCSTR *Source,
|
IN PCSTR *Source,
|
||||||
IN SIZE_T Length);
|
IN SIZE_T Length);
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ namespace RTL
|
|||||||
STATIC XTAPI PWCHAR TrimWideString(IN PWCHAR String);
|
STATIC XTAPI PWCHAR TrimWideString(IN PWCHAR String);
|
||||||
STATIC XTAPI SIZE_T WideStringLength(IN PCWSTR String,
|
STATIC XTAPI SIZE_T WideStringLength(IN PCWSTR String,
|
||||||
IN SIZE_T MaxLength);
|
IN SIZE_T MaxLength);
|
||||||
|
STATIC XTAPI XTSTATUS WideStringToNumber(IN PCWSTR String,
|
||||||
|
IN ULONG Base,
|
||||||
|
OUT PULONG Value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
STATIC XTAPI XTSTATUS FormatArgumentSpecifier(IN PRTL_PRINT_CONTEXT Context,
|
STATIC XTAPI XTSTATUS FormatArgumentSpecifier(IN PRTL_PRINT_CONTEXT Context,
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#include <xtos.hh>
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* Debug I/O spinlock */
|
||||||
|
KSPIN_LOCK KD::DebugIo::DebugIoLock;
|
||||||
|
|
||||||
/* Kernel Debugger mode */
|
/* Kernel Debugger mode */
|
||||||
KD_DEBUG_MODE KD::DebugIo::DebugMode;
|
KD_DEBUG_MODE KD::DebugIo::DebugMode;
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ KD::DebugIo::DbgPrint(PCWSTR Format,
|
|||||||
VA_START(Arguments, Format);
|
VA_START(Arguments, Format);
|
||||||
|
|
||||||
/* Call the actual debug print routine */
|
/* Call the actual debug print routine */
|
||||||
DbgPrintEx(Format, Arguments);
|
DbgPrint(Format, Arguments);
|
||||||
|
|
||||||
/* Clean up the va_list */
|
/* Clean up the va_list */
|
||||||
VA_END(Arguments);
|
VA_END(Arguments);
|
||||||
@@ -54,12 +54,16 @@ KD::DebugIo::DbgPrint(PCWSTR Format,
|
|||||||
*/
|
*/
|
||||||
XTCDECL
|
XTCDECL
|
||||||
VOID
|
VOID
|
||||||
KD::DebugIo::DbgPrintEx(PCWSTR Format,
|
KD::DebugIo::DbgPrint(PCWSTR Format,
|
||||||
VA_LIST Arguments)
|
VA_LIST Arguments)
|
||||||
{
|
{
|
||||||
PLIST_ENTRY DispatchTableEntry;
|
PLIST_ENTRY DispatchTableEntry;
|
||||||
PKD_DISPATCH_TABLE DispatchTable;
|
PKD_DISPATCH_TABLE DispatchTable;
|
||||||
|
|
||||||
|
/* Raise runlevel and acquire the Debug I/O lock */
|
||||||
|
KE::RaiseRunLevel RunLevel(HIGH_LEVEL);
|
||||||
|
KE::SpinLockGuard SpinLock(&DebugIoLock);
|
||||||
|
|
||||||
/* Iterate over all registered debug providers */
|
/* Iterate over all registered debug providers */
|
||||||
DispatchTableEntry = Providers.Flink;
|
DispatchTableEntry = Providers.Flink;
|
||||||
while(DispatchTableEntry != &Providers)
|
while(DispatchTableEntry != &Providers)
|
||||||
@@ -218,6 +222,9 @@ KD::DebugIo::InitializeDebugIoProviders(VOID)
|
|||||||
ULONG Index;
|
ULONG Index;
|
||||||
XTSTATUS ProviderStatus, Status;
|
XTSTATUS ProviderStatus, Status;
|
||||||
|
|
||||||
|
/* Initialize debug I/O spinlock */
|
||||||
|
KE::SpinLock::InitializeSpinLock(&DebugIoLock);
|
||||||
|
|
||||||
/* Initialize debug providers list */
|
/* Initialize debug providers list */
|
||||||
RTL::LinkedList::InitializeListHead(&Providers);
|
RTL::LinkedList::InitializeListHead(&Providers);
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ DbgPrint(PCWSTR Format,
|
|||||||
/* Initialise the va_list */
|
/* Initialise the va_list */
|
||||||
VA_START(Arguments, Format);
|
VA_START(Arguments, Format);
|
||||||
|
|
||||||
KD::DebugIo::DbgPrintEx(Format, Arguments);
|
KD::DebugIo::DbgPrint(Format, Arguments);
|
||||||
|
|
||||||
/* Clean up the va_list */
|
/* Clean up the va_list */
|
||||||
VA_END(Arguments);
|
VA_END(Arguments);
|
||||||
|
|||||||
@@ -66,6 +66,117 @@ KE::Processor::GetCurrentThread(VOID)
|
|||||||
return (PKTHREAD)AR::CpuFunc::ReadGSQuadWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread));
|
return (PKTHREAD)AR::CpuFunc::ReadGSQuadWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the processor block for the specified processor number.
|
||||||
|
*
|
||||||
|
* @param CpuNumber
|
||||||
|
* Supplies the zero-indexed processor number.
|
||||||
|
*
|
||||||
|
* @return This routine returns a pointer to the processor block, or NULLPTR if invalid.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
PKPROCESSOR_BLOCK
|
||||||
|
KE::Processor::GetProcessorBlock(IN ULONG CpuNumber)
|
||||||
|
{
|
||||||
|
/* Check if the requested CPU number is within dynamic bounds */
|
||||||
|
if(CpuNumber >= InstalledCpus || ProcessorBlocks == NULLPTR || ProcessorBlocks[CpuNumber] == NULLPTR)
|
||||||
|
{
|
||||||
|
/* Invalid CPU number, return NULLPTR */
|
||||||
|
return NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return requested processor block */
|
||||||
|
return ProcessorBlocks[CpuNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the global processor structures by allocating an array of processor block pointers.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code indicating the success or failure of the allocation.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
KE::Processor::InitializeProcessorBlocks()
|
||||||
|
{
|
||||||
|
PACPI_SYSTEM_INFO SystemInfo;
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Save number of CPUs installed */
|
||||||
|
HL::Acpi::GetSystemInformation(&SystemInfo);
|
||||||
|
InstalledCpus = SystemInfo->CpuCount;
|
||||||
|
|
||||||
|
/* Allocate an array of pointers */
|
||||||
|
Status = MM::Allocator::AllocatePool(NonPagedPool,
|
||||||
|
InstalledCpus * sizeof(PKPROCESSOR_BLOCK),
|
||||||
|
(PVOID*)&ProcessorBlocks);
|
||||||
|
if(Status != STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* Failed to allocate memory, return error */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zero the array initially */
|
||||||
|
RTL::Memory::ZeroMemory(ProcessorBlocks, InstalledCpus * sizeof(PKPROCESSOR_BLOCK));
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the hardware APIC ID for the currently executing processor.
|
||||||
|
*
|
||||||
|
* @param ApicId
|
||||||
|
* Supplies the hardware APIC ID to register in the processor block.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
KE::Processor::RegisterHardwareId(IN ULONG HardwareId)
|
||||||
|
{
|
||||||
|
PKPROCESSOR_BLOCK CurrentBlock;
|
||||||
|
|
||||||
|
/* Retrieve the processor block for the executing core */
|
||||||
|
CurrentBlock = GetCurrentProcessorBlock();
|
||||||
|
if(CurrentBlock != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Register the hardware identifier for IPI targeting */
|
||||||
|
CurrentBlock->HardwareId = HardwareId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers or deregisters a processor block in the global CPU table.
|
||||||
|
*
|
||||||
|
* @param CpuNumber
|
||||||
|
* Specifies the logical processor number.
|
||||||
|
*
|
||||||
|
* @param ProcessorBlock
|
||||||
|
* Supplies a pointer to the processor block.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
KE::Processor::RegisterProcessorBlock(ULONG CpuNumber,
|
||||||
|
PKPROCESSOR_BLOCK ProcessorBlock)
|
||||||
|
{
|
||||||
|
/* Check if the requested CPU number is within dynamic bounds */
|
||||||
|
if(ProcessorBlocks != NULLPTR && CpuNumber < InstalledCpus)
|
||||||
|
{
|
||||||
|
/* Register processor block */
|
||||||
|
ProcessorBlocks[CpuNumber] = ProcessorBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current processor state.
|
* Saves the current processor state.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ ETHREAD KE::KThread::InitialThread = {};
|
|||||||
/* Kernel UBSAN active frame flag */
|
/* Kernel UBSAN active frame flag */
|
||||||
BOOLEAN KE::KUbsan::ActiveFrame = FALSE;
|
BOOLEAN KE::KUbsan::ActiveFrame = FALSE;
|
||||||
|
|
||||||
|
/* Total number of installed processors in the system */
|
||||||
|
ULONG KE::Processor::InstalledCpus;
|
||||||
|
|
||||||
|
/* Array of pointers to processor control blocks */
|
||||||
|
PKPROCESSOR_BLOCK *KE::Processor::ProcessorBlocks;
|
||||||
|
|
||||||
/* Kernel shared data (KSD) */
|
/* Kernel shared data (KSD) */
|
||||||
PKSHARED_DATA KE::SharedData::KernelSharedData;
|
PKSHARED_DATA KE::SharedData::KernelSharedData;
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,117 @@ KE::Processor::GetCurrentThread(VOID)
|
|||||||
return (PKTHREAD)AR::CpuFunc::ReadFSDualWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread));
|
return (PKTHREAD)AR::CpuFunc::ReadFSDualWord(FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the processor block for the specified processor number.
|
||||||
|
*
|
||||||
|
* @param CpuNumber
|
||||||
|
* Supplies the zero-indexed processor number.
|
||||||
|
*
|
||||||
|
* @return This routine returns a pointer to the processor block, or NULLPTR if invalid.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
PKPROCESSOR_BLOCK
|
||||||
|
KE::Processor::GetProcessorBlock(IN ULONG CpuNumber)
|
||||||
|
{
|
||||||
|
/* Check if the requested CPU number is within dynamic bounds */
|
||||||
|
if(CpuNumber >= InstalledCpus || ProcessorBlocks == NULLPTR || ProcessorBlocks[CpuNumber] == NULLPTR)
|
||||||
|
{
|
||||||
|
/* Invalid CPU number, return NULLPTR */
|
||||||
|
return NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return requested processor block */
|
||||||
|
return ProcessorBlocks[CpuNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the global processor structures by allocating an array of processor block pointers.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code indicating the success or failure of the allocation.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
KE::Processor::InitializeProcessorBlocks()
|
||||||
|
{
|
||||||
|
PACPI_SYSTEM_INFO SystemInfo;
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Save number of CPUs installed */
|
||||||
|
HL::Acpi::GetSystemInformation(&SystemInfo);
|
||||||
|
InstalledCpus = SystemInfo->CpuCount;
|
||||||
|
|
||||||
|
/* Allocate an array of pointers */
|
||||||
|
Status = MM::Allocator::AllocatePool(NonPagedPool,
|
||||||
|
InstalledCpus * sizeof(PKPROCESSOR_BLOCK),
|
||||||
|
(PVOID*)&ProcessorBlocks);
|
||||||
|
if(Status != STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* Failed to allocate memory, return error */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zero the array initially */
|
||||||
|
RTL::Memory::ZeroMemory(ProcessorBlocks, InstalledCpus * sizeof(PKPROCESSOR_BLOCK));
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the hardware APIC ID for the currently executing processor.
|
||||||
|
*
|
||||||
|
* @param ApicId
|
||||||
|
* Supplies the hardware APIC ID to register in the processor block.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
KE::Processor::RegisterHardwareId(IN ULONG HardwareId)
|
||||||
|
{
|
||||||
|
PKPROCESSOR_BLOCK CurrentBlock;
|
||||||
|
|
||||||
|
/* Retrieve the processor block for the executing core */
|
||||||
|
CurrentBlock = GetCurrentProcessorBlock();
|
||||||
|
if(CurrentBlock != NULLPTR)
|
||||||
|
{
|
||||||
|
/* Register the hardware identifier for IPI targeting */
|
||||||
|
CurrentBlock->HardwareId = HardwareId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers or deregisters a processor block in the global CPU table.
|
||||||
|
*
|
||||||
|
* @param CpuNumber
|
||||||
|
* Specifies the logical processor number.
|
||||||
|
*
|
||||||
|
* @param ProcessorBlock
|
||||||
|
* Supplies a pointer to the processor block.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
KE::Processor::RegisterProcessorBlock(ULONG CpuNumber,
|
||||||
|
PKPROCESSOR_BLOCK ProcessorBlock)
|
||||||
|
{
|
||||||
|
/* Check if the requested CPU number is within dynamic bounds */
|
||||||
|
if(ProcessorBlocks != NULLPTR && CpuNumber < InstalledCpus)
|
||||||
|
{
|
||||||
|
/* Register processor block */
|
||||||
|
ProcessorBlocks[CpuNumber] = ProcessorBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current processor state.
|
* Saves the current processor state.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -97,6 +97,64 @@ MM::Paging::GetPxeVirtualAddress(IN PMMPXE PxePointer)
|
|||||||
return PmlRoutines->GetPxeVirtualAddress(PxePointer);
|
return PmlRoutines->GetPxeVirtualAddress(PxePointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a specific virtual address to a specific physical page frame.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress
|
||||||
|
* The virtual address to map.
|
||||||
|
*
|
||||||
|
* @param PageFrameNumber
|
||||||
|
* The physical frame number to back the virtual address.
|
||||||
|
*
|
||||||
|
* @param Attributes
|
||||||
|
* Specifies the attributes (protections, caching) to apply to the PTE.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
MM::Paging::MapVirtualAddress(IN PVOID VirtualAddress,
|
||||||
|
IN PFN_NUMBER PageFrameNumber,
|
||||||
|
IN ULONGLONG Attributes)
|
||||||
|
{
|
||||||
|
MMPTE TemplatePte;
|
||||||
|
PMMPTE PointerPte;
|
||||||
|
|
||||||
|
/* Initialize the template PTE */
|
||||||
|
MM::Paging::ClearPte(&TemplatePte);
|
||||||
|
MM::Paging::SetPte(&TemplatePte, 0, Attributes | MM_PTE_CACHE_ENABLE);
|
||||||
|
|
||||||
|
/* Check if XPA is enabled */
|
||||||
|
if(MM::Paging::GetXpaStatus())
|
||||||
|
{
|
||||||
|
/* Map Page 5-level Entry*/
|
||||||
|
MM::Pte::MapP5E(VirtualAddress, VirtualAddress, (PMMP5E)&TemplatePte);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map PXE, PPE and PDE for the corresponding virtual address */
|
||||||
|
MM::Pte::MapPXE(VirtualAddress, VirtualAddress, (PMMPXE)&TemplatePte);
|
||||||
|
MM::Pte::MapPPE(VirtualAddress, VirtualAddress, (PMMPPE)&TemplatePte);
|
||||||
|
MM::Pte::MapPDE(VirtualAddress, VirtualAddress, (PMMPDE)&TemplatePte);
|
||||||
|
|
||||||
|
/* Get PTE address */
|
||||||
|
PointerPte = MM::Paging::GetPteAddress(VirtualAddress);
|
||||||
|
|
||||||
|
/* Initialize the template PTE */
|
||||||
|
MM::Paging::ClearPte(&TemplatePte);
|
||||||
|
MM::Paging::SetPte(&TemplatePte, PageFrameNumber, Attributes);
|
||||||
|
|
||||||
|
/* Write the PTE */
|
||||||
|
MM::Paging::WritePte(PointerPte, TemplatePte);
|
||||||
|
|
||||||
|
/* Flush the TLB to reflect the changes */
|
||||||
|
MM::Paging::FlushTlb();
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills a section of memory with zeroes like RtlZeroMemory(), but in more efficient way.
|
* Fills a section of memory with zeroes like RtlZeroMemory(), but in more efficient way.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* FILE: xtoskrnl/mm/hlpool.cc
|
* FILE: xtoskrnl/mm/hlpool.cc
|
||||||
* DESCRIPTION: Hardware layer pool memory management
|
* DESCRIPTION: Hardware layer pool memory management
|
||||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||||
|
* Aiken Harris <harraiken91@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <xtos.hh>
|
#include <xtos.hh>
|
||||||
@@ -18,6 +19,9 @@
|
|||||||
* @param Aligned
|
* @param Aligned
|
||||||
* Specifies whether allocated memory should be aligned to 64k boundary or not.
|
* Specifies whether allocated memory should be aligned to 64k boundary or not.
|
||||||
*
|
*
|
||||||
|
* @param MaximumAddress
|
||||||
|
* Supplies the maximum acceptable physical address for the allocation.
|
||||||
|
*
|
||||||
* @param Buffer
|
* @param Buffer
|
||||||
* Supplies a buffer that receives the physical address.
|
* Supplies a buffer that receives the physical address.
|
||||||
*
|
*
|
||||||
@@ -29,18 +33,19 @@ XTAPI
|
|||||||
XTSTATUS
|
XTSTATUS
|
||||||
MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
||||||
IN BOOLEAN Aligned,
|
IN BOOLEAN Aligned,
|
||||||
|
IN ULONGLONG MaximumAddress,
|
||||||
OUT PPHYSICAL_ADDRESS Buffer)
|
OUT PPHYSICAL_ADDRESS Buffer)
|
||||||
{
|
{
|
||||||
PLOADER_MEMORY_DESCRIPTOR Descriptor, ExtraDescriptor, HardwareDescriptor;
|
PLOADER_MEMORY_DESCRIPTOR Descriptor, ExtraDescriptor, HardwareDescriptor;
|
||||||
|
PLIST_ENTRY ListEntry, LoaderMemoryDescriptors;
|
||||||
PFN_NUMBER Alignment, MaxPage;
|
PFN_NUMBER Alignment, MaxPage;
|
||||||
ULONGLONG PhysicalAddress;
|
ULONGLONG PhysicalAddress;
|
||||||
PLIST_ENTRY ListEntry, LoaderMemoryDescriptors;
|
|
||||||
|
|
||||||
/* Assume failure */
|
/* Assume failure */
|
||||||
(*Buffer).QuadPart = 0;
|
(*Buffer).QuadPart = 0;
|
||||||
|
|
||||||
/* Calculate maximum page address */
|
/* Calculate maximum page address based on the requested limit */
|
||||||
MaxPage = MM_MAXIMUM_PHYSICAL_ADDRESS >> MM_PAGE_SHIFT;
|
MaxPage = MaximumAddress >> MM_PAGE_SHIFT;
|
||||||
|
|
||||||
/* Make sure there are at least 2 descriptors available */
|
/* Make sure there are at least 2 descriptors available */
|
||||||
if((UsedHardwareAllocationDescriptors + 2) > MM_HARDWARE_ALLOCATION_DESCRIPTORS)
|
if((UsedHardwareAllocationDescriptors + 2) > MM_HARDWARE_ALLOCATION_DESCRIPTORS)
|
||||||
@@ -53,7 +58,7 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
|||||||
LoaderMemoryDescriptors = KE::BootInformation::GetMemoryDescriptors();
|
LoaderMemoryDescriptors = KE::BootInformation::GetMemoryDescriptors();
|
||||||
|
|
||||||
/* Scan memory descriptors provided by the boot loader */
|
/* Scan memory descriptors provided by the boot loader */
|
||||||
ListEntry = LoaderMemoryDescriptors->Flink;
|
ListEntry = LoaderMemoryDescriptors->Blink;
|
||||||
while(ListEntry != LoaderMemoryDescriptors)
|
while(ListEntry != LoaderMemoryDescriptors)
|
||||||
{
|
{
|
||||||
Descriptor = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_DESCRIPTOR, ListEntry);
|
Descriptor = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_DESCRIPTOR, ListEntry);
|
||||||
@@ -75,8 +80,8 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move to next descriptor */
|
/* Move to previous descriptor */
|
||||||
ListEntry = ListEntry->Flink;
|
ListEntry = ListEntry->Blink;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure we found a descriptor */
|
/* Make sure we found a descriptor */
|
||||||
@@ -142,6 +147,51 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
MM::HardwarePool::AllocateRealModeMemory(IN PFN_NUMBER PageCount,
|
||||||
|
OUT PVOID *MemoryAddress)
|
||||||
|
{
|
||||||
|
PHYSICAL_ADDRESS PhysicalAddress;
|
||||||
|
PFN_NUMBER PageFrameNumber;
|
||||||
|
PVOID VirtualAddress;
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Allocate physical memory in first 1MB */
|
||||||
|
Status = AllocateHardwareMemory(PageCount, TRUE, 0x100000, &PhysicalAddress);
|
||||||
|
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);
|
||||||
|
if(Status != STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
/* Failed to map memory, return error */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the trampoline virtual address and return success */
|
||||||
|
*MemoryAddress = VirtualAddress;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps physical address to the virtual memory area used by kernel hardware layer.
|
* Maps physical address to the virtual memory area used by kernel hardware layer.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -25,6 +25,62 @@ MM::Paging::GetExtendedPhysicalAddressingStatus(VOID)
|
|||||||
return ((AR::CpuFunc::ReadControlRegister(4) & CR4_PAE) != 0) ? TRUE : FALSE;
|
return ((AR::CpuFunc::ReadControlRegister(4) & CR4_PAE) != 0) ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a specific virtual address to a specific physical page frame (i686 specific).
|
||||||
|
*
|
||||||
|
* @param VirtualAddress
|
||||||
|
* The virtual address to map.
|
||||||
|
*
|
||||||
|
* @param PageFrameNumber
|
||||||
|
* The physical frame number to back the virtual address.
|
||||||
|
*
|
||||||
|
* @param Attributes
|
||||||
|
* Specifies the attributes (protections, caching) to apply to the PTE.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
MM::Paging::MapVirtualAddress(IN PVOID VirtualAddress,
|
||||||
|
IN PFN_NUMBER PageFrameNumber,
|
||||||
|
IN ULONGLONG Attributes)
|
||||||
|
{
|
||||||
|
MMPTE TemplatePte;
|
||||||
|
PMMPTE PointerPte;
|
||||||
|
|
||||||
|
/* Initialize the template PTE */
|
||||||
|
MM::Paging::ClearPte(&TemplatePte);
|
||||||
|
MM::Paging::SetPte(&TemplatePte, 0, Attributes | MM_PTE_CACHE_ENABLE);
|
||||||
|
|
||||||
|
/* Check if XPA is enabled */
|
||||||
|
if(MM::Paging::GetXpaStatus())
|
||||||
|
{
|
||||||
|
/* Map Page Directory Pointer Table */
|
||||||
|
MM::Pte::MapPPE(VirtualAddress, VirtualAddress, (PMMPPE)&TemplatePte);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map Page Directory Entry */
|
||||||
|
MM::Pte::MapPDE(VirtualAddress, VirtualAddress, (PMMPDE)&TemplatePte);
|
||||||
|
|
||||||
|
/* Get PTE address */
|
||||||
|
PointerPte = MM::Paging::GetPteAddress(VirtualAddress);
|
||||||
|
|
||||||
|
/* Initialize the template PTE */
|
||||||
|
MM::Paging::ClearPte(&TemplatePte);
|
||||||
|
MM::Paging::SetPte(&TemplatePte, PageFrameNumber, Attributes);
|
||||||
|
|
||||||
|
/* Write the PTE */
|
||||||
|
MM::Paging::WritePte(PointerPte, TemplatePte);
|
||||||
|
|
||||||
|
/* Flush the TLB to reflect the changes */
|
||||||
|
MM::Paging::FlushTlb();
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills a section of memory with zeroes like RtlZeroMemory(), but in more efficient way.
|
* Fills a section of memory with zeroes like RtlZeroMemory(), but in more efficient way.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,11 +16,8 @@
|
|||||||
* @param Stack
|
* @param Stack
|
||||||
* Supplies a pointer to the memory area that will contain a new kernel stack.
|
* Supplies a pointer to the memory area that will contain a new kernel stack.
|
||||||
*
|
*
|
||||||
* @param LargeStack
|
* @param StackSize
|
||||||
* Determines whether the stack is large or small.
|
* Supplies the size of the stack to be allocated, in bytes.
|
||||||
*
|
|
||||||
* @param SystemNode
|
|
||||||
* Specifies a preferred node used for new stack on multi-processor systems.
|
|
||||||
*
|
*
|
||||||
* @return This routine returns a status code.
|
* @return This routine returns a status code.
|
||||||
*
|
*
|
||||||
@@ -95,9 +92,6 @@ MM::KernelPool::AllocateKernelStack(OUT PVOID *Stack,
|
|||||||
/**
|
/**
|
||||||
* Allocates a buffer for structures needed by a processor and assigns it to a corresponding CPU.
|
* Allocates a buffer for structures needed by a processor and assigns it to a corresponding CPU.
|
||||||
*
|
*
|
||||||
* @param CpuNumber
|
|
||||||
* Specifies the zero-indexed CPU number as an owner of the allocated structures.
|
|
||||||
*
|
|
||||||
* @param StructuresData
|
* @param StructuresData
|
||||||
* Supplies a pointer to the memory area that will contain the allocated buffer.
|
* Supplies a pointer to the memory area that will contain the allocated buffer.
|
||||||
*
|
*
|
||||||
@@ -107,12 +101,9 @@ MM::KernelPool::AllocateKernelStack(OUT PVOID *Stack,
|
|||||||
*/
|
*/
|
||||||
XTAPI
|
XTAPI
|
||||||
XTSTATUS
|
XTSTATUS
|
||||||
MM::KernelPool::AllocateProcessorStructures(IN ULONG CpuNumber,
|
MM::KernelPool::AllocateProcessorStructures(OUT PVOID *StructuresData)
|
||||||
OUT PVOID *StructuresData)
|
|
||||||
{
|
{
|
||||||
PKPROCESSOR_BLOCK ProcessorBlock;
|
|
||||||
PVOID ProcessorStructures;
|
PVOID ProcessorStructures;
|
||||||
UINT_PTR Address;
|
|
||||||
XTSTATUS Status;
|
XTSTATUS Status;
|
||||||
|
|
||||||
/* Assign memory for processor structures */
|
/* Assign memory for processor structures */
|
||||||
@@ -126,15 +117,6 @@ MM::KernelPool::AllocateProcessorStructures(IN ULONG CpuNumber,
|
|||||||
/* Make sure all structures are zeroed */
|
/* Make sure all structures are zeroed */
|
||||||
RTL::Memory::ZeroMemory(ProcessorStructures, KPROCESSOR_STRUCTURES_SIZE);
|
RTL::Memory::ZeroMemory(ProcessorStructures, KPROCESSOR_STRUCTURES_SIZE);
|
||||||
|
|
||||||
/* Align address to page size boundary and find a space for processor block */
|
|
||||||
Address = ROUND_UP((UINT_PTR)ProcessorStructures, MM_PAGE_SIZE);
|
|
||||||
ProcessorBlock = (PKPROCESSOR_BLOCK)((PUCHAR)Address +
|
|
||||||
(KERNEL_STACKS * KERNEL_STACK_SIZE) +
|
|
||||||
(GDT_ENTRIES * sizeof(KGDTENTRY)));
|
|
||||||
|
|
||||||
/* Store processor number in the processor block */
|
|
||||||
ProcessorBlock->CpuNumber = CpuNumber;
|
|
||||||
|
|
||||||
/* Return pointer to the processor structures */
|
/* Return pointer to the processor structures */
|
||||||
*StructuresData = ProcessorStructures;
|
*StructuresData = ProcessorStructures;
|
||||||
|
|
||||||
@@ -148,8 +130,8 @@ MM::KernelPool::AllocateProcessorStructures(IN ULONG CpuNumber,
|
|||||||
* @param Stack
|
* @param Stack
|
||||||
* Supplies a pointer to the memory area containing a kernel stack.
|
* Supplies a pointer to the memory area containing a kernel stack.
|
||||||
*
|
*
|
||||||
* @param LargeStack
|
* @param StackSize
|
||||||
* Determines whether the stack is large or small.
|
* Supplies the size of the stack to be freed, in bytes.
|
||||||
*
|
*
|
||||||
* @return This routine does not return any value.
|
* @return This routine does not return any value.
|
||||||
*
|
*
|
||||||
@@ -212,6 +194,6 @@ MM::KernelPool::FreeProcessorStructures(IN PVOID StructuresData)
|
|||||||
if(StructuresData != NULLPTR)
|
if(StructuresData != NULLPTR)
|
||||||
{
|
{
|
||||||
/* Release the contiguous memory block back */
|
/* Release the contiguous memory block back */
|
||||||
MM::Allocator::FreePool(StructuresData, 0);
|
MM::Allocator::FreePool(StructuresData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ MM::Manager::MapKernelSharedData(VOID)
|
|||||||
XTSTATUS Status;
|
XTSTATUS Status;
|
||||||
|
|
||||||
/* Allocate one physical page from the hardware pool for the shared data */
|
/* Allocate one physical page from the hardware pool for the shared data */
|
||||||
Status = MM::HardwarePool::AllocateHardwareMemory(1, FALSE, &PhysAddr);
|
Status = MM::HardwarePool::AllocateHardwareMemory(1, FALSE, MM_MAXIMUM_PHYSICAL_ADDRESS, &PhysAddr);
|
||||||
if(Status != STATUS_SUCCESS)
|
if(Status != STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
/* Memory allocation failed, return error code */
|
/* Memory allocation failed, return error code */
|
||||||
|
|||||||
@@ -427,6 +427,192 @@ RTL::String::StringLength(IN PCSTR String,
|
|||||||
return Length;
|
return Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a string to a number.
|
||||||
|
*
|
||||||
|
* @param String
|
||||||
|
* Supplies a pointer to the NULL-terminated string to convert.
|
||||||
|
*
|
||||||
|
* @param Base
|
||||||
|
* Supplies the optional numerical base for the conversion (2, 8, 10, or 16).
|
||||||
|
*
|
||||||
|
* @param Value
|
||||||
|
* Supplies a pointer to a variable that receives the converted numeric value.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
RTL::String::StringToNumber(IN PCSTR String,
|
||||||
|
IN ULONG Base,
|
||||||
|
OUT PULONG Value)
|
||||||
|
{
|
||||||
|
BOOLEAN NegativeValue;
|
||||||
|
ULONG Digit, Result;
|
||||||
|
|
||||||
|
/* Validate input parameters */
|
||||||
|
if(!String || !Value)
|
||||||
|
{
|
||||||
|
/* Invalid input parameters, return error code */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize local variables */
|
||||||
|
NegativeValue = FALSE;
|
||||||
|
Result = 0;
|
||||||
|
|
||||||
|
/* Skip leading whitespaces and control characters */
|
||||||
|
while(*String != '\0' && *String <= ' ')
|
||||||
|
{
|
||||||
|
/* Advance to the next character */
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume and record sign */
|
||||||
|
if(*String == '-')
|
||||||
|
{
|
||||||
|
/* Set negative value flag and advance to the next character */
|
||||||
|
NegativeValue = TRUE;
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
else if(*String == '+')
|
||||||
|
{
|
||||||
|
/* Advance to the next character */
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Autodetect and validate the base */
|
||||||
|
if(Base == 0)
|
||||||
|
{
|
||||||
|
/* Autodetect base based on prefix */
|
||||||
|
if(String[0] == '0')
|
||||||
|
{
|
||||||
|
/* Validate prefix */
|
||||||
|
if(String[1] == 'x' || String[1] == 'X')
|
||||||
|
{
|
||||||
|
/* Hexadecimal base */
|
||||||
|
Base = 16;
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(String[1] == 'o' || String[1] == 'O')
|
||||||
|
{
|
||||||
|
/* Octal base */
|
||||||
|
Base = 8;
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(String[1] == 'b' || String[1] == 'B')
|
||||||
|
{
|
||||||
|
/* Binary base */
|
||||||
|
Base = 2;
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Starts with 0 but no known prefix, treat as decimal */
|
||||||
|
Base = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Default to decimal base */
|
||||||
|
Base = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Validate explicitly provided base */
|
||||||
|
if(Base != 2 && Base != 8 && Base != 10 && Base != 16)
|
||||||
|
{
|
||||||
|
/* Invalid base, return error code */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if number starts with 0 */
|
||||||
|
if(String[0] == '0')
|
||||||
|
{
|
||||||
|
/* Check for prefix */
|
||||||
|
if(Base == 16 && (String[1] == 'x' || String[1] == 'X'))
|
||||||
|
{
|
||||||
|
/* Skip hexadecimal prefix */
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(Base == 8 && (String[1] == 'o' || String[1] == 'O'))
|
||||||
|
{
|
||||||
|
/* Skip octal prefix */
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(Base == 2 && (String[1] == 'b' || String[1] == 'B'))
|
||||||
|
{
|
||||||
|
/* Skip binary prefix */
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse string character by character */
|
||||||
|
while(*String != '\0')
|
||||||
|
{
|
||||||
|
/* Convert character to numeric digit */
|
||||||
|
if(*String >= '0' && *String <= '9')
|
||||||
|
{
|
||||||
|
/* Convert decimal digit */
|
||||||
|
Digit = *String - '0';
|
||||||
|
}
|
||||||
|
else if(*String >= 'A' && *String <= 'F')
|
||||||
|
{
|
||||||
|
/* Convert hexadecimal digit */
|
||||||
|
Digit = *String - 'A' + 10;
|
||||||
|
}
|
||||||
|
else if(*String >= 'a' && *String <= 'f')
|
||||||
|
{
|
||||||
|
/* Convert hexadecimal digit */
|
||||||
|
Digit = *String - 'a' + 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Invalid character for a number encountered, stop parsing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if digit is valid for the current base */
|
||||||
|
if(Digit >= Base)
|
||||||
|
{
|
||||||
|
/* Digit out of range for this base, stop parsing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for integer overflow */
|
||||||
|
if((Result > (MAXULONG / Base)) || ((Result * Base) > (MAXULONG - Digit)))
|
||||||
|
{
|
||||||
|
/* Integer overflow, return error code */
|
||||||
|
return STATUS_INTEGER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accumulate result */
|
||||||
|
Result = (Result * Base) + Digit;
|
||||||
|
|
||||||
|
/* Advance to the next character */
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for negative value */
|
||||||
|
if(NegativeValue)
|
||||||
|
{
|
||||||
|
/* Apply sign and return the result */
|
||||||
|
*Value = (ULONG)(-(LONG)Result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Return the result */
|
||||||
|
*Value = Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a multibyte character string to its wide character representation.
|
* Converts a multibyte character string to its wide character representation.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1524,6 +1524,192 @@ RTL::WideString::WideStringLength(IN PCWSTR String,
|
|||||||
return Length;
|
return Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a wide string to a number.
|
||||||
|
*
|
||||||
|
* @param String
|
||||||
|
* Supplies a pointer to the NULL-terminated wide string to convert.
|
||||||
|
*
|
||||||
|
* @param Base
|
||||||
|
* Supplies the optional numerical base for the conversion (2, 8, 10, or 16).
|
||||||
|
*
|
||||||
|
* @param Value
|
||||||
|
* Supplies a pointer to a variable that receives the converted numeric value.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
RTL::WideString::WideStringToNumber(IN PCWSTR String,
|
||||||
|
IN ULONG Base,
|
||||||
|
OUT PULONG Value)
|
||||||
|
{
|
||||||
|
BOOLEAN NegativeValue;
|
||||||
|
ULONG Digit, Result;
|
||||||
|
|
||||||
|
/* Validate input parameters */
|
||||||
|
if(!String || !Value)
|
||||||
|
{
|
||||||
|
/* Invalid input parameters, return error code */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize local variables */
|
||||||
|
NegativeValue = FALSE;
|
||||||
|
Result = 0;
|
||||||
|
|
||||||
|
/* Skip leading whitespaces and control characters */
|
||||||
|
while(*String != L'\0' && *String <= L' ')
|
||||||
|
{
|
||||||
|
/* Advance to the next character */
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume and record sign */
|
||||||
|
if(*String == L'-')
|
||||||
|
{
|
||||||
|
/* Set negative value flag and advance to the next character */
|
||||||
|
NegativeValue = TRUE;
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
else if(*String == L'+')
|
||||||
|
{
|
||||||
|
/* Advance to the next character */
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Autodetect and validate the base */
|
||||||
|
if(Base == 0)
|
||||||
|
{
|
||||||
|
/* Autodetect base based on prefix */
|
||||||
|
if(String[0] == L'0')
|
||||||
|
{
|
||||||
|
/* Validate prefix */
|
||||||
|
if(String[1] == L'x' || String[1] == L'X')
|
||||||
|
{
|
||||||
|
/* Hexadecimal base */
|
||||||
|
Base = 16;
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(String[1] == L'o' || String[1] == L'O')
|
||||||
|
{
|
||||||
|
/* Octal base */
|
||||||
|
Base = 8;
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(String[1] == L'b' || String[1] == L'B')
|
||||||
|
{
|
||||||
|
/* Binary base */
|
||||||
|
Base = 2;
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Starts with 0 but no known prefix, treat as decimal */
|
||||||
|
Base = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Default to decimal base */
|
||||||
|
Base = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Validate explicitly provided base */
|
||||||
|
if(Base != 2 && Base != 8 && Base != 10 && Base != 16)
|
||||||
|
{
|
||||||
|
/* Invalid base, return error code */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if number starts with 0 */
|
||||||
|
if(String[0] == L'0')
|
||||||
|
{
|
||||||
|
/* Check for prefix */
|
||||||
|
if(Base == 16 && (String[1] == L'x' || String[1] == L'X'))
|
||||||
|
{
|
||||||
|
/* Skip hexadecimal prefix */
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(Base == 8 && (String[1] == L'o' || String[1] == L'O'))
|
||||||
|
{
|
||||||
|
/* Skip octal prefix */
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
else if(Base == 2 && (String[1] == L'b' || String[1] == L'B'))
|
||||||
|
{
|
||||||
|
/* Skip binary prefix */
|
||||||
|
String += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse string character by character */
|
||||||
|
while(*String != L'\0')
|
||||||
|
{
|
||||||
|
/* Convert wide character to numeric digit */
|
||||||
|
if(*String >= L'0' && *String <= L'9')
|
||||||
|
{
|
||||||
|
/* Convert decimal digit */
|
||||||
|
Digit = *String - L'0';
|
||||||
|
}
|
||||||
|
else if(*String >= L'A' && *String <= L'F')
|
||||||
|
{
|
||||||
|
/* Convert hexadecimal digit */
|
||||||
|
Digit = *String - L'A' + 10;
|
||||||
|
}
|
||||||
|
else if(*String >= L'a' && *String <= L'f')
|
||||||
|
{
|
||||||
|
/* Convert hexadecimal digit */
|
||||||
|
Digit = *String - L'a' + 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Invalid character for a number encountered, stop parsing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if digit is valid for the current base */
|
||||||
|
if(Digit >= Base)
|
||||||
|
{
|
||||||
|
/* Digit out of range for this base, stop parsing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for integer overflow */
|
||||||
|
if((Result > (MAXULONG / Base)) || ((Result * Base) > (MAXULONG - Digit)))
|
||||||
|
{
|
||||||
|
/* Integer overflow, return error code */
|
||||||
|
return STATUS_INTEGER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accumulate result */
|
||||||
|
Result = (Result * Base) + Digit;
|
||||||
|
|
||||||
|
/* Advance to the next character */
|
||||||
|
String++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for negative value */
|
||||||
|
if(NegativeValue)
|
||||||
|
{
|
||||||
|
/* Apply sign and return the result */
|
||||||
|
*Value = (ULONG)(-(LONG)Result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Return the result */
|
||||||
|
*Value = Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a wide character to the destination provided by the print context.
|
* Writes a wide character to the destination provided by the print context.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user