reactos/ntoskrnl/include/internal/i386/intrin_i.h
Justin Miller 516ccad340
[NTOS:KE][HALX86] Implement AP startup code (#5879)
Co-authored-by: Victor Perevertkin <victor.perevertkin@reactos.org>

Introduce the initial changes needed to get other processors up and into kernel mode. 
This only supports x86 as of now but is the first real step towards using other system processors.
2023-11-19 15:51:33 -08:00

461 lines
8 KiB
C

#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
FORCEINLINE
PKGDTENTRY
KiGetGdtEntry(
_In_ PVOID pGdt,
_In_ USHORT Selector)
{
return (PKGDTENTRY)((ULONG_PTR)pGdt + (Selector & ~RPL_MASK));
}
FORCEINLINE
VOID
KiSetGdtDescriptorBase(
_Inout_ PKGDTENTRY Entry,
_In_ ULONG32 Base)
{
Entry->BaseLow = (USHORT)(Base & 0xffff);
Entry->HighWord.Bytes.BaseMid = (UCHAR)((Base >> 16) & 0xff);
Entry->HighWord.Bytes.BaseHi = (UCHAR)((Base >> 24) & 0xff);
// Entry->BaseUpper = (ULONG)(Base >> 32);
}
FORCEINLINE
VOID
KiSetGdtDescriptorLimit(
_Inout_ PKGDTENTRY Entry,
_In_ ULONG Limit)
{
if (Limit < 0x100000)
{
Entry->HighWord.Bits.Granularity = 0;
}
else
{
Limit >>= 12;
Entry->HighWord.Bits.Granularity = 1;
}
Entry->LimitLow = (USHORT)(Limit & 0xffff);
Entry->HighWord.Bits.LimitHi = ((Limit >> 16) & 0x0f);
}
FORCEINLINE
VOID
KiSetGdtEntryEx(
_Inout_ PKGDTENTRY Entry,
_In_ ULONG32 Base,
_In_ ULONG Limit,
_In_ UCHAR Type,
_In_ UCHAR Dpl,
_In_ BOOLEAN Granularity,
_In_ UCHAR SegMode) // 0: 16-bit, 1: 32-bit, 2: 64-bit
{
KiSetGdtDescriptorBase(Entry, Base);
KiSetGdtDescriptorLimit(Entry, Limit);
Entry->HighWord.Bits.Type = (Type & 0x1f);
Entry->HighWord.Bits.Dpl = (Dpl & 0x3);
Entry->HighWord.Bits.Pres = (Type != 0); // Present, must be 1 when the GDT entry is valid.
Entry->HighWord.Bits.Sys = 0; // System
Entry->HighWord.Bits.Reserved_0 = 0; // LongMode = !!(SegMode & 1);
Entry->HighWord.Bits.Default_Big = !!(SegMode & 2);
Entry->HighWord.Bits.Granularity |= !!Granularity; // The flag may have been already set by KiSetGdtDescriptorLimit().
// Entry->MustBeZero = 0;
}
FORCEINLINE
VOID
KiSetGdtEntry(
_Inout_ PKGDTENTRY Entry,
_In_ ULONG32 Base,
_In_ ULONG Limit,
_In_ UCHAR Type,
_In_ UCHAR Dpl,
_In_ UCHAR SegMode) // 0: 16-bit, 1: 32-bit, 2: 64-bit
{
KiSetGdtEntryEx(Entry, Base, Limit, Type, Dpl, FALSE, SegMode);
}
#if defined(__GNUC__)
FORCEINLINE
VOID
__lgdt(_Out_ PVOID Descriptor)
{
PVOID* desc = (PVOID*)Descriptor;
__asm__ __volatile__(
"lgdt %0"
: "=m" (*desc)
: /* no input */
: "memory");
}
FORCEINLINE
VOID
__sgdt(_Out_ PVOID Descriptor)
{
PVOID* desc = (PVOID*)Descriptor;
__asm__ __volatile__(
"sgdt %0"
: "=m" (*desc)
: /* no input */
: "memory");
}
FORCEINLINE
VOID
Ke386FxStore(IN PFX_SAVE_AREA SaveArea)
{
asm volatile ("fxrstor (%0)" : : "r"(SaveArea));
}
FORCEINLINE
VOID
Ke386FxSave(IN PFX_SAVE_AREA SaveArea)
{
asm volatile ("fxsave (%0)" : : "r"(SaveArea));
}
FORCEINLINE
VOID
Ke386FnSave(IN PFLOATING_SAVE_AREA SaveArea)
{
asm volatile ("fnsave (%0); wait" : : "r"(SaveArea));
}
FORCEINLINE
VOID
Ke386SaveFpuState(IN PFX_SAVE_AREA SaveArea)
{
extern ULONG KeI386FxsrPresent;
if (KeI386FxsrPresent)
{
__asm__ __volatile__ ("fxsave %0\n" : : "m"(*SaveArea));
}
else
{
__asm__ __volatile__ ("fnsave %0\n wait\n" : : "m"(*SaveArea));
}
}
FORCEINLINE
VOID
Ke386RestoreFpuState(_In_ PFX_SAVE_AREA SaveArea)
{
extern ULONG KeI386FxsrPresent;
if (KeI386FxsrPresent)
{
__asm__ __volatile__ ("fxrstor %0\n" : : "m"(*SaveArea));
}
else
{
__asm__ __volatile__ ("frstor %0\n\t" : "=m" (*SaveArea));
}
}
FORCEINLINE
VOID
Ke386ClearFpExceptions(VOID)
{
__asm__ __volatile__ ("fnclex");
}
FORCEINLINE
VOID
__sldt(PVOID Descriptor)
{
__asm__ __volatile__(
"sldt %0"
: "=m" (*((short*)Descriptor))
: /* no input */
: "memory");
}
#define Ke386SetLocalDescriptorTable(X) \
__asm__("lldt %w0\n\t" \
: /* no outputs */ \
: "q" (X));
#define Ke386SetTr(X) __asm__ __volatile__("ltr %%ax" : :"a" (X));
FORCEINLINE
USHORT
Ke386GetTr(VOID)
{
USHORT Tr;
__asm__("str %0\n\t"
: "=m" (Tr));
return Tr;
}
#define _Ke386GetSeg(N) ({ \
unsigned int __d; \
__asm__("movl %%" #N ",%0\n\t" :"=r" (__d)); \
__d; \
})
#define _Ke386SetSeg(N,X) __asm__ __volatile__("movl %0,%%" #N : :"r" (X));
#define Ke386FnInit() __asm__("fninit\n\t");
#define Ke386ClearDirectionFlag() __asm__ __volatile__ ("cld")
//
// CR Macros
//
#define Ke386SetCr2(X) __asm__ __volatile__("movl %0,%%cr2" : :"r" (X));
//
// Segment Macros
//
#define Ke386GetSs() _Ke386GetSeg(ss)
#define Ke386GetFs() _Ke386GetSeg(fs)
#define Ke386GetDs() _Ke386GetSeg(ds)
#define Ke386GetEs() _Ke386GetSeg(es)
#define Ke386GetGs() _Ke386GetSeg(gs)
#define Ke386SetFs(X) _Ke386SetSeg(fs, X)
#define Ke386SetDs(X) _Ke386SetSeg(ds, X)
#define Ke386SetEs(X) _Ke386SetSeg(es, X)
#define Ke386SetSs(X) _Ke386SetSeg(ss, X)
#define Ke386SetGs(X) _Ke386SetSeg(gs, X)
#elif defined(_MSC_VER)
FORCEINLINE
VOID
Ke386FnInit(VOID)
{
__asm fninit;
}
FORCEINLINE
VOID
__sgdt(OUT PVOID Descriptor)
{
__asm
{
mov eax, Descriptor
sgdt [eax]
}
}
FORCEINLINE
VOID
__fxsave(OUT PFX_SAVE_AREA SaveArea)
{
__asm mov eax, SaveArea
__asm fxsave [eax]
}
FORCEINLINE
VOID
__fxrstor(IN PFX_SAVE_AREA SaveArea)
{
__asm mov eax, SaveArea
__asm fxrstor [eax]
}
FORCEINLINE
VOID
__frstor(_In_ PFX_SAVE_AREA SaveArea)
{
__asm mov eax, SaveArea
__asm frstor [eax]
}
FORCEINLINE
VOID
__fnsave(OUT PFLOATING_SAVE_AREA SaveArea)
{
__asm mov eax, SaveArea
__asm fnsave [eax]
__asm wait;
}
FORCEINLINE
VOID
__lgdt(IN PVOID Descriptor)
{
__asm
{
mov eax, Descriptor
lgdt [eax]
}
}
FORCEINLINE
VOID
__sldt(PVOID Descriptor)
{
__asm
{
sldt ax
mov ecx, Descriptor
mov [ecx], ax
}
}
FORCEINLINE
VOID
Ke386SetLocalDescriptorTable(IN USHORT Descriptor)
{
__asm lldt Descriptor;
}
FORCEINLINE
VOID
Ke386SetTr(IN USHORT Tr)
{
__asm ltr Tr;
}
FORCEINLINE
USHORT
Ke386GetTr(VOID)
{
__asm str ax;
}
//
// CR Macros
//
FORCEINLINE
VOID
Ke386SetCr2(IN ULONG Value)
{
__asm mov eax, Value;
__asm mov cr2, eax;
}
//
// Segment Macros
//
FORCEINLINE
USHORT
Ke386GetSs(VOID)
{
__asm mov ax, ss;
}
FORCEINLINE
USHORT
Ke386GetFs(VOID)
{
__asm mov ax, fs;
}
FORCEINLINE
USHORT
Ke386GetDs(VOID)
{
__asm mov ax, ds;
}
FORCEINLINE
USHORT
Ke386GetEs(VOID)
{
__asm mov ax, es;
}
FORCEINLINE
VOID
Ke386SetSs(IN USHORT Value)
{
__asm mov ax, Value;
__asm mov ss, ax;
}
FORCEINLINE
VOID
Ke386SetFs(IN USHORT Value)
{
__asm mov ax, Value;
__asm mov fs, ax;
}
FORCEINLINE
VOID
Ke386SetDs(IN USHORT Value)
{
__asm mov ax, Value;
__asm mov ds, ax;
}
FORCEINLINE
VOID
Ke386SetEs(IN USHORT Value)
{
__asm mov ax, Value;
__asm mov es, ax;
}
FORCEINLINE
VOID
Ke386SetGs(IN USHORT Value)
{
__asm mov ax, Value;
__asm mov gs, ax;
}
extern ULONG KeI386FxsrPresent;
FORCEINLINE
VOID
Ke386SaveFpuState(IN PVOID SaveArea)
{
if (KeI386FxsrPresent)
{
__fxsave((PFX_SAVE_AREA)SaveArea);
}
else
{
__fnsave((PFLOATING_SAVE_AREA)SaveArea);
}
}
FORCEINLINE
VOID
Ke386RestoreFpuState(_In_ PVOID SaveArea)
{
if (KeI386FxsrPresent)
{
__fxrstor((PFX_SAVE_AREA)SaveArea);
}
else
{
__frstor((PFX_SAVE_AREA)SaveArea);
}
}
FORCEINLINE
VOID
Ke386ClearFpExceptions(VOID)
{
__asm fnclex;
}
#define Ke386FnSave __fnsave
#define Ke386FxSave __fxsave
// The name suggest, that the original author didn't understand what frstor means
#define Ke386FxStore __fxrstor
#else
#error Unknown compiler for inline assembler
#endif
#define Ke386GetGlobalDescriptorTable __sgdt
#define Ke386SetGlobalDescriptorTable __lgdt
#define Ke386GetLocalDescriptorTable __sldt
#ifdef __cplusplus
} // extern "C"
#endif
/* EOF */