215 lines
5.5 KiB
C
215 lines
5.5 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
selector.c
|
||
|
||
Abstract:
|
||
|
||
This module allows the host side of the kernel debugger to look up
|
||
selector values in the GDT and LDT of the target machine.
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 10-Jun-1991
|
||
|
||
Revision History:
|
||
|
||
Wesley Witt (wesw) 26-Aug-1993 (ported to WinDbg)
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
#include "i386.h"
|
||
|
||
#define SELECTOR_CACHE_LENGTH 6
|
||
|
||
typedef struct _sc {
|
||
struct _sc *nextYoungest;
|
||
struct _sc *nextOldest;
|
||
USHORT processor;
|
||
DESCRIPTOR_TABLE_ENTRY_X86 desc;
|
||
} SELCACHEENTRY;
|
||
|
||
SELCACHEENTRY SelectorCache[SELECTOR_CACHE_LENGTH], *selYoungest, *selOldest;
|
||
|
||
BOOL fInitialized = FALSE;
|
||
|
||
void
|
||
InitSelCache(void)
|
||
{
|
||
int i;
|
||
|
||
for(i=0;i<SELECTOR_CACHE_LENGTH;i++){
|
||
SelectorCache[i].nextYoungest = &SelectorCache[i+1];
|
||
SelectorCache[i].nextOldest = &SelectorCache[i-1];
|
||
SelectorCache[i].processor = (USHORT)-1;
|
||
SelectorCache[i].desc.Selector = 0;
|
||
}
|
||
|
||
SelectorCache[--i].nextYoungest = NULL;
|
||
SelectorCache[0].nextOldest = NULL;
|
||
selYoungest = &SelectorCache[i];
|
||
selOldest = &SelectorCache[0];
|
||
}
|
||
|
||
BOOLEAN
|
||
FindSelector(USHORT Processor, PDESCRIPTOR_TABLE_ENTRY_X86 pdesc)
|
||
{
|
||
int i;
|
||
|
||
|
||
for(i=0;i<SELECTOR_CACHE_LENGTH;i++) {
|
||
if (SelectorCache[i].desc.Selector == pdesc->Selector &&
|
||
SelectorCache[i].processor == Processor) {
|
||
*pdesc = SelectorCache[i].desc;
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
void
|
||
PutSelector(USHORT Processor, PDESCRIPTOR_TABLE_ENTRY_X86 pdesc)
|
||
{
|
||
selOldest->desc = *pdesc;
|
||
selOldest->processor = Processor;
|
||
(selOldest->nextYoungest)->nextOldest = NULL;
|
||
selOldest->nextOldest = selYoungest;
|
||
selYoungest->nextYoungest= selOldest;
|
||
selYoungest = selOldest;
|
||
selOldest = selOldest->nextYoungest;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LookupSelector(
|
||
IN USHORT Processor,
|
||
IN OUT PDESCRIPTOR_TABLE_ENTRY_X86 pDescriptorTableEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Looks up a selector in the GDT or LDT on the host machine.
|
||
|
||
Arguments:
|
||
|
||
Processor - Supplies the processor whose selector is desired.
|
||
|
||
pDescriptorTableEntry->Selector - Supplies value of the selector to
|
||
be looked up.
|
||
|
||
pDescriptorTableEntry->Descriptor - Returns descriptor
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - The selector was found in the GDT or LDT, and the
|
||
Descriptor field pointed to by pDescriptorTableEntry
|
||
has been filled in with valid data.
|
||
|
||
STATUS_UNSUCCESSFUL - The selector's descriptor could not be read from
|
||
virtual memory. (Page is invalid or not present)
|
||
|
||
STATUS_INVALID_PARAMETER - The selector was not in the GDT or LDT,
|
||
and the Descriptor field is invalid.
|
||
|
||
--*/
|
||
{
|
||
ULONG64 Address;
|
||
ULONG TableBase=0;
|
||
USHORT TableLimit=0;
|
||
ULONG Result;
|
||
ULONG Index;
|
||
ULONG Off;
|
||
LDT_ENTRY_X86 Descriptor;
|
||
|
||
if (!fInitialized) {
|
||
fInitialized = TRUE;
|
||
InitSelCache();
|
||
}
|
||
|
||
if (FindSelector(Processor, pDescriptorTableEntry)) {
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// Fetch the address and limit of the GDT
|
||
//
|
||
|
||
if (GetFieldOffset("KPROCESSOR_STATE", "SpecialRegisters.Gdtr.Base", &Off)) {
|
||
dprintf("Cannot find KPROCESSOR_STATE type\n");
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
Address = Off;
|
||
ReadControlSpace64((USHORT)Processor, Address,
|
||
&TableBase, sizeof(TableBase));
|
||
if (!TableBase) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
GetFieldOffset("KPROCESSOR_STATE", "SpecialRegisters.Gdtr.Limit", &Off);
|
||
Address = Off;
|
||
ReadControlSpace64((USHORT)Processor, Address,
|
||
&TableLimit, sizeof(TableLimit));
|
||
|
||
//
|
||
// Find out whether this is a GDT or LDT selector
|
||
//
|
||
if (pDescriptorTableEntry->Selector & 0x4) {
|
||
|
||
//
|
||
// This is an LDT selector, so we reload the TableBase and TableLimit
|
||
// with the LDT's Base & Limit by loading the descriptor for the
|
||
// LDT selector.
|
||
//
|
||
|
||
ReadMemory((ULONG64) (LONG64) (LONG) (TableBase)+KGDT_LDT_I386,&Descriptor,
|
||
sizeof(Descriptor),&Result);
|
||
|
||
TableBase = ((ULONG)Descriptor.BaseLow +
|
||
((ULONG)Descriptor.HighWord.Bits.BaseMid << 16) +
|
||
((ULONG)Descriptor.HighWord.Bytes.BaseHi << 24));
|
||
|
||
TableLimit = Descriptor.LimitLow; // LDT can't be > 64k
|
||
|
||
if(Descriptor.HighWord.Bits.Granularity == GRAN_PAGE) {
|
||
|
||
//
|
||
// I suppose it's possible, although strange to have an
|
||
// LDT with page granularity.
|
||
//
|
||
TableLimit <<= PAGE_SHIFT_X86;
|
||
}
|
||
}
|
||
|
||
Index = (USHORT)(pDescriptorTableEntry->Selector) & ~0x7;
|
||
// Irrelevant bits
|
||
//
|
||
// Check to make sure that the selector is within the table bounds
|
||
//
|
||
if (Index >= TableLimit) {
|
||
|
||
//
|
||
// Selector is out of table's bounds
|
||
//
|
||
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
ReadMemory((ULONG64) (LONG64) (LONG) TableBase+Index,
|
||
&(pDescriptorTableEntry->Descriptor),
|
||
sizeof(pDescriptorTableEntry->Descriptor),
|
||
&Result);
|
||
if(Result != sizeof(pDescriptorTableEntry->Descriptor)) {
|
||
return(STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
PutSelector(Processor, pDescriptorTableEntry);
|
||
return(STATUS_SUCCESS);
|
||
}
|