Compare commits

28 Commits
master ... smp

Author SHA1 Message Date
29368a0dd8 Implement string to number conversion functions
All checks were successful
Builds / ExectOS (i686, release) (push) Successful in 29s
Builds / ExectOS (amd64, release) (push) Successful in 27s
Builds / ExectOS (i686, debug) (push) Successful in 41s
Builds / ExectOS (amd64, debug) (push) Successful in 43s
2026-05-15 15:02:22 +02:00
8ee97ac0ae Add NOX2APIC boot parameter to bypass hardware detection
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m32s
Builds / ExectOS (amd64, release) (push) Successful in 31s
Builds / ExectOS (i686, debug) (push) Successful in -59m31s
Builds / ExectOS (i686, release) (push) Successful in 37s
2026-05-15 12:00:50 +02:00
6bbeb657ea Merge branch 'master' into smp
All checks were successful
Builds / ExectOS (i686, debug) (push) Successful in -59m30s
Builds / ExectOS (amd64, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, release) (push) Successful in 38s
Builds / ExectOS (amd64, release) (push) Successful in 40s
2026-05-15 11:43:45 +02:00
c824e15cdb Fix stack allocation documentation and remove redundant parameter
All checks were successful
Builds / ExectOS (i686, debug) (push) Successful in -59m28s
Builds / ExectOS (amd64, debug) (push) Successful in -59m26s
Builds / ExectOS (i686, release) (push) Successful in 1m27s
Builds / ExectOS (amd64, release) (push) Successful in 1m30s
2026-05-15 11:42:19 +02:00
38b2e7a1ed Read previously identified CPU features from PRCB
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m13s
Builds / ExectOS (amd64, release) (push) Successful in -59m15s
Builds / ExectOS (i686, release) (push) Successful in -59m31s
Builds / ExectOS (i686, debug) (push) Successful in -59m29s
2026-05-15 11:33:23 +02:00
efff262fb5 Replace CPUID queries with cached PRCB feature bits
All checks were successful
Builds / ExectOS (i686, debug) (push) Successful in -59m0s
Builds / ExectOS (amd64, debug) (push) Successful in -58m55s
Builds / ExectOS (i686, release) (push) Successful in 1m39s
Builds / ExectOS (amd64, release) (push) Successful in 1m44s
2026-05-15 09:13:56 +02:00
14cbd63b01 Remove premature SetRunLevel call from InitializeProcessor before APIC initialization
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m29s
Builds / ExectOS (amd64, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, release) (push) Successful in -59m30s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
2026-05-14 21:52:42 +02:00
63d18aad1e Add ExtendedFeatureBits field
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m28s
Builds / ExectOS (amd64, release) (push) Successful in -59m29s
Builds / ExectOS (i686, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, release) (push) Successful in -59m29s
2026-05-14 21:37:11 +02:00
ed52d421ea Implement processor feature enumeration mapping
Some checks failed
Builds / ExectOS (amd64, release) (push) Failing after -59m37s
Builds / ExectOS (amd64, debug) (push) Failing after -59m35s
Builds / ExectOS (i686, release) (push) Failing after -59m36s
Builds / ExectOS (i686, debug) (push) Failing after -59m35s
2026-05-14 21:35:43 +02:00
6df6a012d2 Partially revert ca4f3acc0e
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m30s
Builds / ExectOS (amd64, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, debug) (push) Successful in -59m29s
Builds / ExectOS (i686, release) (push) Successful in -59m31s
2026-05-14 21:12:09 +02:00
ac675b037e Add FeatureBits field to CPU identification structure
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m8s
Builds / ExectOS (amd64, release) (push) Successful in -59m37s
Builds / ExectOS (i686, debug) (push) Successful in -59m29s
Builds / ExectOS (i686, release) (push) Successful in -59m32s
2026-05-14 19:28:45 +02:00
ca4f3acc0e Properly identify CPU vendor
Some checks failed
Builds / ExectOS (amd64, debug) (push) Has been cancelled
Builds / ExectOS (amd64, release) (push) Has been cancelled
Builds / ExectOS (i686, debug) (push) Has been cancelled
Builds / ExectOS (i686, release) (push) Has been cancelled
2026-05-14 18:59:00 +02:00
5b7761fe7d Expose InitializeProcessorStructures as a public method
Some checks failed
Builds / ExectOS (amd64, debug) (push) Has been cancelled
Builds / ExectOS (amd64, release) (push) Has been cancelled
Builds / ExectOS (i686, debug) (push) Has been cancelled
Builds / ExectOS (i686, release) (push) Has been cancelled
2026-05-14 18:10:29 +02:00
7a2a27b1b9 Consolidate ProcessorBlock and ProcessorNumber into ProcessorStructures
Some checks failed
Builds / ExectOS (amd64, debug) (push) Has been cancelled
Builds / ExectOS (amd64, release) (push) Has been cancelled
Builds / ExectOS (i686, debug) (push) Has been cancelled
Builds / ExectOS (i686, release) (push) Has been cancelled
2026-05-14 18:00:56 +02:00
1cff58c106 Refactor processor block initialization and add registration function
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m26s
Builds / ExectOS (amd64, release) (push) Successful in -59m28s
Builds / ExectOS (i686, release) (push) Successful in -59m26s
Builds / ExectOS (i686, debug) (push) Successful in -59m24s
2026-05-14 13:15:55 +02:00
9185ceade6 Decouple processor block initialization from AllocateProcessorStructures
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m26s
Builds / ExectOS (amd64, release) (push) Successful in -59m28s
Builds / ExectOS (i686, release) (push) Successful in -59m30s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
2026-05-14 11:07:42 +02:00
908bc87b06 Add NULL checks to InitializeProcessorStructures and reorder TSS allocation
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m29s
Builds / ExectOS (amd64, debug) (push) Successful in -59m26s
Builds / ExectOS (i686, release) (push) Successful in -59m29s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
2026-05-14 11:06:00 +02:00
6b852556a5 Replace magic numbers with architectural defines
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m29s
Builds / ExectOS (amd64, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, release) (push) Successful in -59m28s
Builds / ExectOS (i686, debug) (push) Successful in -59m26s
2026-05-13 22:01:49 +02:00
ae18468bad Add AP startup assembly trampoline for AMD64
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m26s
Builds / ExectOS (amd64, debug) (push) Successful in -59m25s
Builds / ExectOS (i686, release) (push) Successful in -59m30s
Builds / ExectOS (i686, debug) (push) Successful in -59m28s
2026-05-13 21:48:42 +02:00
42bbdc9b26 Fix AP trampoline stack setup
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m27s
Builds / ExectOS (amd64, release) (push) Successful in -59m28s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, release) (push) Successful in -59m29s
2026-05-13 21:24:27 +02:00
b1ecdc3439 Add AP startup assembly trampoline for i686
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m29s
Builds / ExectOS (amd64, release) (push) Successful in -59m29s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, release) (push) Successful in -59m29s
2026-05-13 20:31:30 +02:00
fd7e18989d Protect debug print output with spinlock
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m28s
Builds / ExectOS (amd64, release) (push) Successful in -59m30s
Builds / ExectOS (i686, release) (push) Successful in -59m29s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
2026-05-13 14:33:41 +02:00
757eac08c6 Refactor APIC IPI dispatching
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m29s
Builds / ExectOS (amd64, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, release) (push) Successful in -59m30s
Builds / ExectOS (i686, debug) (push) Successful in -59m28s
2026-05-13 11:27:01 +02:00
760e58f993 Correct doxygen parameter name
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m26s
Builds / ExectOS (amd64, release) (push) Successful in -59m28s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, release) (push) Successful in -59m29s
2026-05-13 10:10:03 +02:00
c8868ead47 Add AllocateRealModeMemory routine for low memory allocations
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m29s
Builds / ExectOS (amd64, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, release) (push) Successful in -59m30s
2026-05-13 10:08:30 +02:00
58981e0087 Add MapVirtualAddress to memory manager paging interface
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m27s
Builds / ExectOS (amd64, release) (push) Successful in -59m28s
Builds / ExectOS (i686, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, release) (push) Successful in -59m30s
2026-05-13 09:58:13 +02:00
06635ed014 Parameterize maximum allocation address in hardware pool and scan memory descriptors in reverse
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m30s
Builds / ExectOS (amd64, debug) (push) Successful in -59m28s
Builds / ExectOS (i686, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, release) (push) Successful in -59m29s
2026-05-12 19:35:06 +02:00
5a92173586 Implement targeted IPI broadcasting using processor block array
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in -59m28s
Builds / ExectOS (amd64, debug) (push) Successful in -59m27s
Builds / ExectOS (i686, debug) (push) Successful in -59m29s
Builds / ExectOS (i686, release) (push) Successful in -59m30s
2026-05-11 00:07:21 +02:00
40 changed files with 1833 additions and 429 deletions

View File

@@ -80,4 +80,12 @@ GenerateAssemblyDefinitions(VOID)
/* Generate KTRAP_FRAME size and REGISTERS_SIZE */
ADK_SIZE(KTRAP_FRAME);
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);
}

View File

@@ -54,4 +54,12 @@ GenerateAssemblyDefinitions(VOID)
/* Generate KTRAP_FRAME size and REGISTERS_SIZE */
ADK_SIZE(KTRAP_FRAME);
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);
}

View File

@@ -430,7 +430,9 @@ typedef VOID (*PINTERRUPT_HANDLER)(PKTRAP_FRAME TrapFrame);
/* Processor identification information */
typedef struct _CPU_IDENTIFICATION
{
ULONGLONG ExtendedFeatureBits;
USHORT Family;
ULONGLONG FeatureBits;
USHORT Model;
USHORT Stepping;
CPU_VENDOR Vendor;

View File

@@ -69,6 +69,62 @@
#define AMD64_INTERRUPT_GATE 0xE
#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 */
#define CONTEXT_ARCHITECTURE 0x00100000
#define CONTEXT_CONTROL (CONTEXT_ARCHITECTURE | 0x01)
@@ -118,8 +174,8 @@
#define KERNEL_STACK_GUARD_PAGES 1
/* Processor structures size */
#define KPROCESSOR_STRUCTURES_SIZE ((2 * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + sizeof(KTSS) + \
sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
#define KPROCESSOR_STRUCTURES_SIZE ((KERNEL_STACKS * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + \
sizeof(KTSS) + sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
/* Kernel frames */
#define KEXCEPTION_FRAME_SIZE sizeof(KEXCEPTION_FRAME)
@@ -470,11 +526,22 @@ typedef struct _KSPECIAL_REGISTERS
ULONG64 MsrSyscallMask;
} 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 */
typedef struct _KPROCESSOR_STATE
{
KSPECIAL_REGISTERS SpecialRegisters;
CONTEXT ContextFrame;
KSPECIAL_REGISTERS SpecialRegisters;
} KPROCESSOR_STATE, *PKPROCESSOR_STATE;
/* Processor Control Block (PRCB) structure definition */
@@ -524,6 +591,8 @@ typedef struct _KPROCESSOR_BLOCK
KAFFINITY SetMember;
ULONG StallScaleFactor;
UCHAR CpuNumber;
ULONG HardwareId;
VOLATILE BOOLEAN Started;
PINTERRUPT_HANDLER InterruptDispatchTable[256];
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;

View File

@@ -395,7 +395,9 @@ typedef VOID (*PINTERRUPT_HANDLER)(PKTRAP_FRAME TrapFrame);
/* Processor identification information */
typedef struct _CPU_IDENTIFICATION
{
ULONGLONG ExtendedFeatureBits;
USHORT Family;
ULONGLONG FeatureBits;
USHORT Model;
USHORT Stepping;
CPU_VENDOR Vendor;

View File

@@ -90,6 +90,62 @@
#define I686_INTERRUPT_GATE 0xE
#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 */
#define CONTEXT_ARCHITECTURE 0x00010000
#define CONTEXT_CONTROL (CONTEXT_ARCHITECTURE | 0x01)
@@ -137,8 +193,8 @@
#define KERNEL_STACK_GUARD_PAGES 1
/* Processor structures size */
#define KPROCESSOR_STRUCTURES_SIZE ((2 * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + sizeof(KTSS) + \
sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
#define KPROCESSOR_STRUCTURES_SIZE ((KERNEL_STACKS * KERNEL_STACK_SIZE) + (GDT_ENTRIES * sizeof(KGDTENTRY)) + \
sizeof(KTSS) + sizeof(KPROCESSOR_BLOCK) + MM_PAGE_SIZE)
/* Kernel frames */
#define KTRAP_FRAME_ALIGN 0x08
@@ -431,6 +487,17 @@ typedef struct _KSPECIAL_REGISTERS
ULONG Reserved[6];
} 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 */
typedef struct _KPROCESSOR_STATE
{
@@ -483,6 +550,8 @@ typedef struct _KPROCESSOR_BLOCK
KAFFINITY SetMember;
ULONG StallScaleFactor;
UCHAR CpuNumber;
ULONG HardwareId;
VOLATILE BOOLEAN Started;
PINTERRUPT_HANDLER InterruptDispatchTable[256];
} KPROCESSOR_BLOCK, *PKPROCESSOR_BLOCK;

View File

@@ -61,6 +61,8 @@
#define STATUS_NO_MEMORY ((XTSTATUS) 0xC0000017L)
#define STATUS_PORT_DISCONNECTED ((XTSTATUS) 0xC0000037L)
#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_DEVICE_NOT_READY ((XTSTATUS) 0xC00000A3L)
#define STATUS_NOT_SUPPORTED ((XTSTATUS) 0xC00000BBL)

View File

@@ -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`
(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.
* **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
bootloader, which configures paging and selects the appropriate Page Map Level (PML) before transferring control to
the kernel.

View File

@@ -359,7 +359,7 @@ ArHandleSpuriousInterrupt:
iretq
/**
* Starts an application processor (AP). This is just a stub.
* Starts an application processor (AP).
*
* @return This routine does not return any value.
*
@@ -367,6 +367,123 @@ ArHandleSpuriousInterrupt:
*/
.global 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
ArStartApplicationProcessorEnd:

View File

@@ -20,6 +20,7 @@ XTAPI
PVOID
AR::ProcSup::GetBootStack(VOID)
{
/* Return base address of kernel boot stack */
return (PVOID)((ULONG_PTR)BootStack + KERNEL_STACK_SIZE);
}
@@ -29,19 +30,23 @@ AR::ProcSup::GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType,
OUT PVOID *TrampolineCode,
OUT PULONG_PTR TrampolineSize)
{
/* Get trampoline information */
switch(TrampolineType)
{
case TrampolineApStartup:
/* Get AP startup trampoline information */
*TrampolineCode = (PVOID)ArStartApplicationProcessor;
*TrampolineSize = (ULONG_PTR)ArStartApplicationProcessorEnd -
(ULONG_PTR)ArStartApplicationProcessor;
break;
case TrampolineEnableXpa:
/* Get Enable XPA trampoline information */
*TrampolineCode = (PVOID)ArEnableExtendedPhysicalAddressing;
*TrampolineSize = (ULONG_PTR)ArEnableExtendedPhysicalAddressingEnd -
(ULONG_PTR)ArEnableExtendedPhysicalAddressing;
break;
default:
/* Unknown trampoline type */
*TrampolineCode = NULLPTR;
*TrampolineSize = 0;
break;
@@ -64,9 +69,6 @@ AR::ProcSup::IdentifyProcessor(VOID)
CPUID_REGISTERS CpuRegisters;
CPUID_SIGNATURE CpuSignature;
/* Not fully implemented yet */
UNIMPLEMENTED;
/* Get current processor control block */
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
@@ -122,11 +124,12 @@ AR::ProcSup::IdentifyProcessor(VOID)
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.
*
@@ -134,71 +137,133 @@ AR::ProcSup::IdentifyProcessor(VOID)
*/
XTAPI
VOID
AR::ProcSup::InitializeProcessor(IN PVOID ProcessorStructures)
AR::ProcSup::IdentifyProcessorFeatures(VOID)
{
PVOID KernelBootStack, KernelFaultStack, KernelNmiStack;
KDESCRIPTOR GdtDescriptor, IdtDescriptor;
PKPROCESSOR_BLOCK ProcessorBlock;
PKGDTENTRY Gdt;
PKIDTENTRY Idt;
PKTSS Tss;
ULONG MaxExtendedLeaf, MaxStandardLeaf;
PKPROCESSOR_CONTROL_BLOCK Prcb;
CPUID_REGISTERS CpuRegisters;
/* Check if processor structures buffer provided */
if(ProcessorStructures)
{
/* Assign CPU structures from provided buffer */
InitializeProcessorStructures(ProcessorStructures, &Gdt, &Tss, &ProcessorBlock,
&KernelBootStack, &KernelFaultStack, &KernelNmiStack);
/* Get current processor control block */
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
/* Use global IDT */
Idt = InitialIdt;
}
else
/* Get maximum CPUID standard leaf */
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_VENDOR_STRING;
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 */
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;
/* Get CPU standard features */
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
AR::CpuFunc::CpuId(&CpuRegisters);
/* Store CPU standard features in processor control block */
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE3) Prcb->CpuId.FeatureBits |= KCF_SSE3;
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 */
InitializeProcessorBlock(ProcessorBlock, Gdt, Idt, Tss, KernelFaultStack);
/* Check if CPU supports standard7 features leaf */
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 */
InitializeGdt(ProcessorBlock);
InitializeIdt(ProcessorBlock);
InitializeTss(ProcessorBlock, KernelBootStack, KernelFaultStack, KernelNmiStack);
/* Store CPU standard7 features in processor control block */
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_FSGSBASE) Prcb->CpuId.FeatureBits |= KCF_FSGSBASE;
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_AVX2) Prcb->CpuId.FeatureBits |= KCF_AVX2;
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 */
GdtDescriptor.Base = Gdt;
GdtDescriptor.Limit = (GDT_ENTRIES * sizeof(KGDTENTRY)) - 1;
IdtDescriptor.Base = Idt;
IdtDescriptor.Limit = (IDT_ENTRIES * sizeof(KIDTENTRY)) - 1;
/* Check if CPU supports power management leaf */
if(MaxStandardLeaf >= CPUID_GET_POWER_MANAGEMENT)
{
/* Get CPU power management features */
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_POWER_MANAGEMENT;
AR::CpuFunc::CpuId(&CpuRegisters);
/* Load GDT, IDT and TSS */
AR::CpuFunc::LoadGlobalDescriptorTable(&GdtDescriptor.Limit);
AR::CpuFunc::LoadInterruptDescriptorTable(&IdtDescriptor.Limit);
AR::CpuFunc::LoadTaskRegister((UINT)KGDT_SYS_TSS);
/* Store CPU power management features in processor control block */
if(CpuRegisters.Eax & CPUID_FEATURES_EAX_ARAT) Prcb->CpuId.FeatureBits |= KCF_ARAT;
}
/* Enter passive IRQ level */
HL::RunLevel::SetRunLevel(PASSIVE_LEVEL);
/* Check if CPU supports extended features leaf */
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 */
InitializeSegments();
/* Store CPU extended features in processor control block */
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 */
AR::CpuFunc::WriteModelSpecificRegister(X86_MSR_GSBASE, (ULONGLONG)ProcessorBlock);
AR::CpuFunc::WriteModelSpecificRegister(X86_MSR_KERNEL_GSBASE, (ULONGLONG)ProcessorBlock);
/* Check if CPU supports advanced power management leaf */
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);
/* Initialize processor registers */
InitializeProcessorRegisters();
/* Identify processor */
IdentifyProcessor();
/* Store CPU advanced power management features in processor control block */
if(CpuRegisters.Edx & CPUID_FEATURES_EDX_TSCI) Prcb->CpuId.ExtendedFeatureBits |= KCF_INVARIANT_TSC;
}
}
/**
@@ -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);
}
/**
* 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.
*
@@ -439,26 +577,49 @@ AR::ProcSup::InitializeProcessorStructures(IN PVOID ProcessorStructures,
Address = ROUND_UP((UINT_PTR)ProcessorStructures, MM_PAGE_SIZE) + KERNEL_STACK_SIZE;
/* Assign a space for kernel boot stack and advance */
*KernelBootStack = (PVOID)Address;
if(KernelBootStack != NULLPTR)
{
/* Return kernel boot stack address */
*KernelBootStack = (PVOID)Address;
}
Address += KERNEL_STACK_SIZE;
/* Assign a space for kernel fault stack and advance */
*KernelFaultStack = (PVOID)Address;
if(KernelFaultStack != NULLPTR)
{
/* Return kernel fault stack address */
*KernelFaultStack = (PVOID)Address;
}
Address += KERNEL_STACK_SIZE;
/* Assign a space for kernel NMI stack, no advance needed as stack grows down */
*KernelNmiStack = (PVOID)Address;
if(KernelNmiStack != NULLPTR)
{
/* Return kernel NMI stack address */
*KernelNmiStack = (PVOID)Address;
}
/* Assign a space for GDT and advance */
*Gdt = (PKGDTENTRY)(PVOID)Address;
Address += sizeof(InitialGdt);
if(Gdt != NULLPTR)
{
/* Return GDT base address */
*Gdt = (PKGDTENTRY)(PVOID)Address;
}
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 */
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
Address += sizeof(InitialProcessorBlock);
/* Assign a space for TSS */
*Tss = (PKTSS)(PVOID)Address;
if(ProcessorBlock != NULLPTR)
{
/* Return processor block address */
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
}
}
/**

View File

@@ -234,7 +234,7 @@ _ArHandleSpuriousInterrupt:
iret
/**
* Starts an application processor (AP). This is just a stub.
* Starts an application processor (AP).
*
* @return This routine does not return any value.
*
@@ -242,6 +242,96 @@ _ArHandleSpuriousInterrupt:
*/
.global _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
_ArStartApplicationProcessorEnd:

View File

@@ -20,6 +20,7 @@ XTAPI
PVOID
AR::ProcSup::GetBootStack(VOID)
{
/* Return base address of kernel boot stack */
return (PVOID)((ULONG_PTR)BootStack + KERNEL_STACK_SIZE);
}
@@ -29,14 +30,17 @@ AR::ProcSup::GetTrampolineInformation(IN TRAMPOLINE_TYPE TrampolineType,
OUT PVOID *TrampolineCode,
OUT PULONG_PTR TrampolineSize)
{
/* Get trampoline information */
switch(TrampolineType)
{
case TrampolineApStartup:
/* Get AP startup trampoline information */
*TrampolineCode = (PVOID)ArStartApplicationProcessor;
*TrampolineSize = (ULONG_PTR)ArStartApplicationProcessorEnd -
(ULONG_PTR)ArStartApplicationProcessor;
break;
default:
/* Unknown trampoline type */
*TrampolineCode = NULLPTR;
*TrampolineSize = 0;
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
* in Processor Control Block (PRCB).
* Identifies processor type (vendor, model, stepping) and stores them in Processor Control Block (PRCB).
*
* @return This routine does not return any value.
*
@@ -59,9 +62,6 @@ AR::ProcSup::IdentifyProcessor(VOID)
CPUID_REGISTERS CpuRegisters;
CPUID_SIGNATURE CpuSignature;
/* Not fully implemented yet */
UNIMPLEMENTED;
/* Get current processor control block */
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
@@ -117,11 +117,12 @@ AR::ProcSup::IdentifyProcessor(VOID)
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.
*
@@ -129,67 +130,133 @@ AR::ProcSup::IdentifyProcessor(VOID)
*/
XTAPI
VOID
AR::ProcSup::InitializeProcessor(IN PVOID ProcessorStructures)
AR::ProcSup::IdentifyProcessorFeatures(VOID)
{
KDESCRIPTOR GdtDescriptor, IdtDescriptor;
PVOID KernelBootStack, KernelFaultStack, KernelNmiStack;
PKPROCESSOR_BLOCK ProcessorBlock;
PKGDTENTRY Gdt;
PKIDTENTRY Idt;
PKTSS Tss;
ULONG MaxExtendedLeaf, MaxStandardLeaf;
PKPROCESSOR_CONTROL_BLOCK Prcb;
CPUID_REGISTERS CpuRegisters;
/* Check if processor structures buffer provided */
if(ProcessorStructures)
{
/* Assign CPU structures from provided buffer */
InitializeProcessorStructures(ProcessorStructures, &Gdt, &Tss, &ProcessorBlock,
&KernelBootStack, &KernelFaultStack, &KernelNmiStack);
/* Get current processor control block */
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
/* Use global IDT */
Idt = InitialIdt;
}
else
/* Get maximum CPUID standard leaf */
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_VENDOR_STRING;
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 */
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;
/* Get CPU standard features */
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
AR::CpuFunc::CpuId(&CpuRegisters);
/* Store CPU standard features in processor control block */
if(CpuRegisters.Ecx & CPUID_FEATURES_ECX_SSE3) Prcb->CpuId.FeatureBits |= KCF_SSE3;
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 */
InitializeProcessorBlock(ProcessorBlock, Gdt, Idt, Tss, KernelFaultStack);
/* Check if CPU supports standard7 features leaf */
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 */
InitializeGdt(ProcessorBlock);
InitializeIdt(ProcessorBlock);
InitializeTss(ProcessorBlock, KernelBootStack, KernelFaultStack, KernelNmiStack);
/* Store CPU standard7 features in processor control block */
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_FSGSBASE) Prcb->CpuId.FeatureBits |= KCF_FSGSBASE;
if(CpuRegisters.Ebx & CPUID_FEATURES_EBX_AVX2) Prcb->CpuId.FeatureBits |= KCF_AVX2;
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 */
GdtDescriptor.Base = Gdt;
GdtDescriptor.Limit = (GDT_ENTRIES * sizeof(KGDTENTRY)) - 1;
IdtDescriptor.Base = Idt;
IdtDescriptor.Limit = (IDT_ENTRIES * sizeof(KIDTENTRY)) - 1;
/* Check if CPU supports power management leaf */
if(MaxStandardLeaf >= CPUID_GET_POWER_MANAGEMENT)
{
/* Get CPU power management features */
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
CpuRegisters.Leaf = CPUID_GET_POWER_MANAGEMENT;
AR::CpuFunc::CpuId(&CpuRegisters);
/* Load GDT, IDT and TSS */
AR::CpuFunc::LoadGlobalDescriptorTable(&GdtDescriptor.Limit);
AR::CpuFunc::LoadInterruptDescriptorTable(&IdtDescriptor.Limit);
AR::CpuFunc::LoadTaskRegister((UINT)KGDT_SYS_TSS);
/* Store CPU power management features in processor control block */
if(CpuRegisters.Eax & CPUID_FEATURES_EAX_ARAT) Prcb->CpuId.FeatureBits |= KCF_ARAT;
}
/* Enter passive IRQ level */
HL::RunLevel::SetRunLevel(PASSIVE_LEVEL);
/* Check if CPU supports extended features leaf */
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 */
InitializeSegments();
/* Store CPU extended features in processor control block */
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 */
InitializeProcessorRegisters();
/* Check if CPU supports advanced power management leaf */
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 */
IdentifyProcessor();
/* Store CPU advanced power management features in processor control block */
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);
}
/**
* 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.
*
@@ -391,26 +528,49 @@ AR::ProcSup::InitializeProcessorStructures(IN PVOID ProcessorStructures,
Address = ROUND_UP((UINT_PTR)ProcessorStructures, MM_PAGE_SIZE) + KERNEL_STACK_SIZE;
/* Assign a space for kernel boot stack and advance */
*KernelBootStack = (PVOID)Address;
if(KernelBootStack != NULLPTR)
{
/* Return kernel boot stack address */
*KernelBootStack = (PVOID)Address;
}
Address += KERNEL_STACK_SIZE;
/* Assign a space for kernel fault stack and advance */
*KernelFaultStack = (PVOID)Address;
if(KernelFaultStack != NULLPTR)
{
/* Return kernel fault stack address */
*KernelFaultStack = (PVOID)Address;
}
Address += KERNEL_STACK_SIZE;
/* Assign a space for kernel NMI stack, no advance needed as stack grows down */
*KernelNmiStack = (PVOID)Address;
if(KernelNmiStack != NULLPTR)
{
/* Return kernel NMI stack address */
*KernelNmiStack = (PVOID)Address;
}
/* Assign a space for GDT and advance */
*Gdt = (PKGDTENTRY)(PVOID)Address;
Address += sizeof(InitialGdt);
if(Gdt != NULLPTR)
{
/* Return GDT base address */
*Gdt = (PKGDTENTRY)(PVOID)Address;
}
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 */
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
Address += sizeof(InitialProcessorBlock);
/* Assign a space for TSS */
*Tss = (PKTSS)(PVOID)Address;
if(ProcessorBlock != NULLPTR)
{
/* Return processor block address */
*ProcessorBlock = (PKPROCESSOR_BLOCK)(PVOID)Address;
}
}
/**

View File

@@ -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.
*
@@ -478,7 +496,7 @@ HL::Acpi::InitializeAcpiSystemStructure(VOID)
PageCount = SIZE_TO_PAGES(CpuCount * sizeof(PROCESSOR_IDENTITY));
/* 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)
{
/* Failed to allocate memory, return error */

View File

@@ -78,28 +78,13 @@ XTAPI
BOOLEAN
HL::Pic::CheckApicSupport(VOID)
{
CPUID_REGISTERS CpuRegisters;
PKPROCESSOR_CONTROL_BLOCK Prcb;
/* Prepare CPUID registers */
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
CpuRegisters.SubLeaf = 0;
CpuRegisters.Eax = 0;
CpuRegisters.Ebx = 0;
CpuRegisters.Ecx = 0;
CpuRegisters.Edx = 0;
/* Get current processor control block */
Prcb = KE::Processor::GetCurrentProcessorControlBlock();
/* Get CPUID */
AR::CpuFunc::CpuId(&CpuRegisters);
/* 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;
/* Return APIC status */
return (Prcb->CpuId.FeatureBits & KCF_APIC) ? TRUE : FALSE;
}
/**
@@ -116,28 +101,21 @@ XTAPI
BOOLEAN
HL::Pic::CheckX2ApicSupport(VOID)
{
CPUID_REGISTERS CpuRegisters;
PKPROCESSOR_CONTROL_BLOCK Prcb;
PCWSTR KernelParameter;
/* Prepare CPUID registers */
CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
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))
/* Check if the user forced xAPIC via boot parameters */
if(KE::BootInformation::GetKernelParameter(L"NOX2APIC", &KernelParameter) == STATUS_SUCCESS)
{
/* x2APIC is not supported */
/* The NOX2APIC flag is present, explicitly disable x2APIC support */
return FALSE;
}
/* x2APIC is supported */
return TRUE;
/* Get current processor control block */
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);
}
/* Report the APIC ID to the kernel logic */
KE::Processor::RegisterHardwareId(GetCpuApicId());
/* Configure the spurious interrupt vector */
SpuriousRegister.Long = ReadApicRegister(APIC_SIVR);
SpuriousRegister.Vector = APIC_VECTOR_SPURIOUS;
@@ -781,58 +762,53 @@ VOID
HL::Pic::SendBroadcastIpi(IN ULONG Vector,
IN BOOLEAN Self)
{
APIC_COMMAND_REGISTER Register;
PKPROCESSOR_BLOCK CurrentProcessorBlock, TargetProcessorBlock;
PACPI_SYSTEM_INFO SysInfo;
BOOLEAN Interrupts;
ULONG Index;
/* SMP not implemented */
if(TRUE)
/* Get the current processor block */
CurrentProcessorBlock = KE::Processor::GetCurrentProcessorBlock();
if(CurrentProcessorBlock == NULLPTR)
{
/* Check if IPI is addressed to the current CPU */
if(Self)
{
/* Send IPI to the current CPU */
SendSelfIpi(Vector);
return;
}
else
{
/* Nothing to do */
return;
}
/* Processor block not available, return */
return;
}
/* Get the ACPI system information */
HL::Acpi::GetSystemInformation(&SysInfo);
/* Check whether interrupts are enabled */
Interrupts = AR::CpuFunc::InterruptsEnabled();
/* Disable interrupts */
AR::CpuFunc::ClearInterruptFlag();
/* Prepare the APIC command register */
Register.LongLong = 0;
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;
/* Iterate over all logical CPUs */
for(Index = 0; Index < SysInfo->CpuCount; Index++)
{
/* Retrieve the target processor block by its Logical CPU Number */
TargetProcessorBlock = KE::Processor::GetProcessorBlock(Index);
/* Check current APIC mode */
if(ApicMode == APIC_MODE_X2APIC)
{
/* In x2APIC mode, writing the full 64-bit value to the ICR MSR is sufficient */
WriteApicRegister(APIC_ICR0, Register.LongLong);
}
else
{
/* Wait for the APIC to clear the delivery status */
while((ReadApicRegister(APIC_ICR0) & 0x1000) != 0)
/* Only send to processors that exist and have successfully started */
if(TargetProcessorBlock != NULLPTR && TargetProcessorBlock->Started)
{
/* Yield the processor */
AR::CpuFunc::YieldProcessor();
/* 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
{
/* Dispatch the IPI to the target processor */
SendIpi(TargetProcessorBlock->HardwareId, Vector, APIC_DM_FIXED, APIC_DSH_Destination, APIC_TGM_EDGE);
}
}
/* 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 */
@@ -867,6 +843,15 @@ HL::Pic::SendEoi(VOID)
* @param Vector
* 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.
*
* @since XT 1.0
@@ -874,19 +859,85 @@ HL::Pic::SendEoi(VOID)
XTAPI
VOID
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 */
if(ApicMode == APIC_MODE_X2APIC)
{
/* Set destination APIC ID */
Register.Long1 = ApicId;
/* Send IPI using x2APIC mode */
WriteApicRegister(APIC_ICR0, ((ULONGLONG)ApicId << 32) | Vector);
WriteApicRegister(APIC_ICR0, Register.LongLong);
}
else
{
/* Send IPI using xAPIC compatibility mode */
WriteApicRegister(APIC_ICR1, ApicId << 24);
WriteApicRegister(APIC_ICR0, 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);
/* 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
HL::Pic::SendSelfIpi(IN ULONG Vector)
{
APIC_COMMAND_REGISTER Register;
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();
}
SendIpi(0, Vector, APIC_DM_FIXED, APIC_DSH_Self, APIC_TGM_EDGE);
}
/**

View File

@@ -925,84 +925,31 @@ XTAPI
VOID
HL::Timer::QueryTimerCapabilities(VOID)
{
PKPROCESSOR_CONTROL_BLOCK Prcb;
CPUID_REGISTERS CpuRegisters;
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 */
RTL::Memory::ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
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);
/* Save maximum supported standard CPUID leaf */
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 */
if(MaxStandardLeaf >= CPUID_GET_TSC_CRYSTAL_CLOCK)
{
/* 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.SubLeaf = 0;
CpuRegisters.Eax = 0;
CpuRegisters.Ebx = 0;
CpuRegisters.Ecx = 0;
CpuRegisters.Edx = 0;
AR::CpuFunc::CpuId(&CpuRegisters);
/* 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;
}
}
}
/**

View File

@@ -32,6 +32,13 @@ namespace AR
OUT PVOID *TrampolineCode,
OUT PULONG_PTR TrampolineSize);
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,
IN USHORT Vector,
IN PVOID Handler,
@@ -42,6 +49,7 @@ namespace AR
private:
STATIC XTAPI VOID IdentifyProcessor(VOID);
STATIC XTAPI VOID IdentifyProcessorFeatures(VOID);
STATIC XTAPI VOID InitializeGdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
STATIC XTAPI VOID InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
STATIC XTAPI VOID InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBlock,
@@ -50,13 +58,6 @@ namespace AR
IN PKTSS Tss,
IN PVOID DpcStack);
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 InitializeTss(IN PKPROCESSOR_BLOCK ProcessorBlock,
IN PVOID KernelBootStack,

View File

@@ -35,6 +35,13 @@ namespace AR
OUT PVOID *TrampolineCode,
OUT PULONG_PTR TrampolineSize);
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,
IN USHORT Vector,
IN PVOID Handler,
@@ -45,6 +52,7 @@ namespace AR
private:
STATIC XTAPI VOID IdentifyProcessor(VOID);
STATIC XTAPI VOID IdentifyProcessorFeatures(VOID);
STATIC XTAPI VOID InitializeGdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
STATIC XTAPI VOID InitializeIdt(IN PKPROCESSOR_BLOCK ProcessorBlock);
STATIC XTAPI VOID InitializeProcessorBlock(OUT PKPROCESSOR_BLOCK ProcessorBlock,
@@ -53,13 +61,6 @@ namespace AR
IN PKTSS Tss,
IN PVOID DpcStack);
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 InitializeTss(IN PKPROCESSOR_BLOCK ProcessorBlock,
IN PVOID KernelBootStack,
@@ -79,7 +80,6 @@ namespace AR
IN ULONG_PTR Base);
STATIC XTAPI VOID SetNonMaskableInterruptTssEntry(IN PKPROCESSOR_BLOCK ProcessorBlock,
IN PVOID KernelNmiStack);
};
}

View File

@@ -30,6 +30,7 @@ namespace HL
STATIC XTAPI XTSTATUS GetAcpiTable(IN ULONG Signature,
OUT PACPI_DESCRIPTION_HEADER *AcpiTable);
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 InitializeAcpiSystemInformation(VOID);

View File

@@ -38,7 +38,10 @@ namespace HL
IN BOOLEAN Self);
STATIC XTAPI VOID SendEoi(VOID);
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 XTFASTCALL VOID WriteApicRegister(IN APIC_REGISTER Register,
IN ULONGLONG Value);

View File

@@ -21,6 +21,7 @@ namespace KD
STATIC PKD_PRINT_ROUTINE KdPrint;
private:
STATIC KSPIN_LOCK DebugIoLock;
STATIC KD_DEBUG_MODE DebugMode;
STATIC PKD_INIT_ROUTINE IoProvidersInitRoutines[KDBG_PROVIDERS_COUNT];
STATIC LIST_ENTRY Providers;
@@ -30,8 +31,8 @@ namespace KD
public:
STATIC XTCDECL VOID DbgPrint(PCWSTR Format,
...);
STATIC XTCDECL VOID DbgPrintEx(PCWSTR Format,
VA_LIST Arguments);
STATIC XTCDECL VOID DbgPrint(PCWSTR Format,
VA_LIST Arguments);
STATIC XTAPI XTSTATUS InitializeDebugIoProviders(VOID);
STATIC XTAPI VOID SetPrintRoutine(PKD_PRINT_ROUTINE DebugPrintRoutine);

View File

@@ -17,11 +17,20 @@ namespace KE
{
class Processor
{
private:
STATIC ULONG InstalledCpus;
STATIC PKPROCESSOR_BLOCK *ProcessorBlocks;
public:
STATIC XTAPI PKPROCESSOR_BLOCK GetCurrentProcessorBlock(VOID);
STATIC XTAPI PKPROCESSOR_CONTROL_BLOCK GetCurrentProcessorControlBlock(VOID);
STATIC XTAPI ULONG GetCurrentProcessorNumber(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);
};
}

View File

@@ -51,6 +51,9 @@ namespace MM
STATIC XTAPI PVOID GetPxeVirtualAddress(IN PMMPXE PxePointer);
STATIC XTAPI BOOLEAN GetXpaStatus(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 VOID SetNextEntry(IN PMMPTE Pte,
IN ULONG_PTR Value);

View File

@@ -25,7 +25,10 @@ namespace MM
public:
STATIC XTAPI XTSTATUS AllocateHardwareMemory(IN PFN_NUMBER PageCount,
IN BOOLEAN Aligned,
IN ULONGLONG MaximumAddress,
OUT PPHYSICAL_ADDRESS Buffer);
STATIC XTAPI XTSTATUS AllocateRealModeMemory(IN PFN_NUMBER PageCount,
OUT PVOID *MemoryAddress);
STATIC XTAPI XTSTATUS MapHardwareMemory(IN PHYSICAL_ADDRESS PhysicalAddress,
IN PFN_NUMBER PageCount,
IN BOOLEAN FlushTlb,

View File

@@ -47,6 +47,9 @@ namespace MM
STATIC XTAPI PVOID GetPteVirtualAddress(IN PMMPTE PtePointer);
STATIC XTAPI BOOLEAN GetXpaStatus(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 VOID SetNextEntry(IN PMMPTE Pte,
IN ULONG_PTR Value);

View File

@@ -20,8 +20,7 @@ namespace MM
public:
STATIC XTAPI XTSTATUS AllocateKernelStack(OUT PVOID *Stack,
IN ULONG StackSize);
STATIC XTAPI XTSTATUS AllocateProcessorStructures(IN ULONG CpuNumber,
OUT PVOID *StructuresData);
STATIC XTAPI XTSTATUS AllocateProcessorStructures(OUT PVOID *StructuresData);
STATIC XTAPI VOID FreeKernelStack(IN PVOID Stack,
IN ULONG StackSize);
STATIC XTAPI VOID FreeProcessorStructures(IN PVOID StructuresData);

View File

@@ -38,6 +38,9 @@ namespace RTL
IN ULONG Length);
STATIC XTAPI SIZE_T StringLength(IN PCSTR String,
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,
IN PCSTR *Source,
IN SIZE_T Length);

View File

@@ -49,6 +49,9 @@ namespace RTL
STATIC XTAPI PWCHAR TrimWideString(IN PWCHAR String);
STATIC XTAPI SIZE_T WideStringLength(IN PCWSTR String,
IN SIZE_T MaxLength);
STATIC XTAPI XTSTATUS WideStringToNumber(IN PCWSTR String,
IN ULONG Base,
OUT PULONG Value);
private:
STATIC XTAPI XTSTATUS FormatArgumentSpecifier(IN PRTL_PRINT_CONTEXT Context,

View File

@@ -9,6 +9,9 @@
#include <xtos.hh>
/* Debug I/O spinlock */
KSPIN_LOCK KD::DebugIo::DebugIoLock;
/* Kernel Debugger mode */
KD_DEBUG_MODE KD::DebugIo::DebugMode;

View File

@@ -33,7 +33,7 @@ KD::DebugIo::DbgPrint(PCWSTR Format,
VA_START(Arguments, Format);
/* Call the actual debug print routine */
DbgPrintEx(Format, Arguments);
DbgPrint(Format, Arguments);
/* Clean up the va_list */
VA_END(Arguments);
@@ -54,12 +54,16 @@ KD::DebugIo::DbgPrint(PCWSTR Format,
*/
XTCDECL
VOID
KD::DebugIo::DbgPrintEx(PCWSTR Format,
VA_LIST Arguments)
KD::DebugIo::DbgPrint(PCWSTR Format,
VA_LIST Arguments)
{
PLIST_ENTRY DispatchTableEntry;
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 */
DispatchTableEntry = Providers.Flink;
while(DispatchTableEntry != &Providers)
@@ -218,6 +222,9 @@ KD::DebugIo::InitializeDebugIoProviders(VOID)
ULONG Index;
XTSTATUS ProviderStatus, Status;
/* Initialize debug I/O spinlock */
KE::SpinLock::InitializeSpinLock(&DebugIoLock);
/* Initialize debug providers list */
RTL::LinkedList::InitializeListHead(&Providers);

View File

@@ -33,7 +33,7 @@ DbgPrint(PCWSTR Format,
/* Initialise the va_list */
VA_START(Arguments, Format);
KD::DebugIo::DbgPrintEx(Format, Arguments);
KD::DebugIo::DbgPrint(Format, Arguments);
/* Clean up the va_list */
VA_END(Arguments);

View File

@@ -66,6 +66,117 @@ KE::Processor::GetCurrentThread(VOID)
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.
*

View File

@@ -21,6 +21,12 @@ ETHREAD KE::KThread::InitialThread = {};
/* Kernel UBSAN active frame flag */
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) */
PKSHARED_DATA KE::SharedData::KernelSharedData;

View File

@@ -66,6 +66,117 @@ KE::Processor::GetCurrentThread(VOID)
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.
*

View File

@@ -97,6 +97,64 @@ MM::Paging::GetPxeVirtualAddress(IN PMMPXE 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.
*

View File

@@ -4,6 +4,7 @@
* FILE: xtoskrnl/mm/hlpool.cc
* DESCRIPTION: Hardware layer pool memory management
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
* Aiken Harris <harraiken91@gmail.com>
*/
#include <xtos.hh>
@@ -18,6 +19,9 @@
* @param Aligned
* 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
* Supplies a buffer that receives the physical address.
*
@@ -29,18 +33,19 @@ XTAPI
XTSTATUS
MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
IN BOOLEAN Aligned,
IN ULONGLONG MaximumAddress,
OUT PPHYSICAL_ADDRESS Buffer)
{
PLOADER_MEMORY_DESCRIPTOR Descriptor, ExtraDescriptor, HardwareDescriptor;
PLIST_ENTRY ListEntry, LoaderMemoryDescriptors;
PFN_NUMBER Alignment, MaxPage;
ULONGLONG PhysicalAddress;
PLIST_ENTRY ListEntry, LoaderMemoryDescriptors;
/* Assume failure */
(*Buffer).QuadPart = 0;
/* Calculate maximum page address */
MaxPage = MM_MAXIMUM_PHYSICAL_ADDRESS >> MM_PAGE_SHIFT;
/* Calculate maximum page address based on the requested limit */
MaxPage = MaximumAddress >> MM_PAGE_SHIFT;
/* Make sure there are at least 2 descriptors available */
if((UsedHardwareAllocationDescriptors + 2) > MM_HARDWARE_ALLOCATION_DESCRIPTORS)
@@ -53,7 +58,7 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
LoaderMemoryDescriptors = KE::BootInformation::GetMemoryDescriptors();
/* Scan memory descriptors provided by the boot loader */
ListEntry = LoaderMemoryDescriptors->Flink;
ListEntry = LoaderMemoryDescriptors->Blink;
while(ListEntry != LoaderMemoryDescriptors)
{
Descriptor = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_DESCRIPTOR, ListEntry);
@@ -75,8 +80,8 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
}
}
/* Move to next descriptor */
ListEntry = ListEntry->Flink;
/* Move to previous descriptor */
ListEntry = ListEntry->Blink;
}
/* Make sure we found a descriptor */
@@ -142,6 +147,51 @@ MM::HardwarePool::AllocateHardwareMemory(IN PFN_NUMBER PageCount,
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.
*

View File

@@ -25,6 +25,62 @@ MM::Paging::GetExtendedPhysicalAddressingStatus(VOID)
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.
*

View File

@@ -16,11 +16,8 @@
* @param Stack
* Supplies a pointer to the memory area that will contain a new kernel stack.
*
* @param LargeStack
* Determines whether the stack is large or small.
*
* @param SystemNode
* Specifies a preferred node used for new stack on multi-processor systems.
* @param StackSize
* Supplies the size of the stack to be allocated, in bytes.
*
* @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.
*
* @param CpuNumber
* Specifies the zero-indexed CPU number as an owner of the allocated structures.
*
* @param StructuresData
* Supplies a pointer to the memory area that will contain the allocated buffer.
*
@@ -107,12 +101,9 @@ MM::KernelPool::AllocateKernelStack(OUT PVOID *Stack,
*/
XTAPI
XTSTATUS
MM::KernelPool::AllocateProcessorStructures(IN ULONG CpuNumber,
OUT PVOID *StructuresData)
MM::KernelPool::AllocateProcessorStructures(OUT PVOID *StructuresData)
{
PKPROCESSOR_BLOCK ProcessorBlock;
PVOID ProcessorStructures;
UINT_PTR Address;
XTSTATUS Status;
/* Assign memory for processor structures */
@@ -126,15 +117,6 @@ MM::KernelPool::AllocateProcessorStructures(IN ULONG CpuNumber,
/* Make sure all structures are zeroed */
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 */
*StructuresData = ProcessorStructures;
@@ -148,8 +130,8 @@ MM::KernelPool::AllocateProcessorStructures(IN ULONG CpuNumber,
* @param Stack
* Supplies a pointer to the memory area containing a kernel stack.
*
* @param LargeStack
* Determines whether the stack is large or small.
* @param StackSize
* Supplies the size of the stack to be freed, in bytes.
*
* @return This routine does not return any value.
*
@@ -212,6 +194,6 @@ MM::KernelPool::FreeProcessorStructures(IN PVOID StructuresData)
if(StructuresData != NULLPTR)
{
/* Release the contiguous memory block back */
MM::Allocator::FreePool(StructuresData, 0);
MM::Allocator::FreePool(StructuresData);
}
}

View File

@@ -298,7 +298,7 @@ MM::Manager::MapKernelSharedData(VOID)
XTSTATUS Status;
/* 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)
{
/* Memory allocation failed, return error code */

View File

@@ -427,6 +427,192 @@ RTL::String::StringLength(IN PCSTR String,
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.
*

View File

@@ -1524,6 +1524,192 @@ RTL::WideString::WideStringLength(IN PCWSTR String,
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.
*