465 lines
11 KiB
C
465 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1998 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
debugsup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains routines which provide support for the
|
|||
|
kernel debugger on 64-bit Alpha systems.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David N. Cutler (davec) 24-Feb-1998
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "mi.h"
|
|||
|
|
|||
|
PHARDWARE_PTE
|
|||
|
MiCheckAddress (
|
|||
|
IN PVOID VirtualAddress,
|
|||
|
OUT PVOID *AccessAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
This function checks the specified virtual address for accessibility
|
|||
|
and returns a pointer to the hardware PTE that maps the virtual address
|
|||
|
and a 43-bit superpage address at which the address can be accessed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Supplies the virtual address to check.
|
|||
|
|
|||
|
AccessAddress - Supplies a pointer to a variable that receives the
|
|||
|
43-bit superpage address at which the address can be accessed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A value of NULL is returned if the address is invalid or not accessible.
|
|||
|
Otherwise, a pointer to the PTE that maps the specified virtual address
|
|||
|
is returned as the function value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ULONG Index;
|
|||
|
PHARDWARE_PTE Pdr1;
|
|||
|
PHARDWARE_PTE Pdr2;
|
|||
|
PHARDWARE_PTE Ptp;
|
|||
|
|
|||
|
//
|
|||
|
// If the high order 21 bits of the virtual address are not all 1's or
|
|||
|
// 0's, then the address is invalid. Otherwise, attempt to tranverse
|
|||
|
// the page directory hierarchy.
|
|||
|
//
|
|||
|
|
|||
|
if ((ULONG_PTR)(((LONG_PTR)VirtualAddress >> 43) + 1) > 1) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Compute the 43-bit superpage address of the level one page
|
|||
|
// directory page and check to see if the level two page directory
|
|||
|
// page is valid.
|
|||
|
//
|
|||
|
|
|||
|
Pdr1 = (PHARDWARE_PTE)(KSEG43_BASE | (((PHARDWARE_PTE)PDE_SELFMAP)->PageFrameNumber << PAGE_SHIFT));
|
|||
|
Index = (ULONG)(((ULONG_PTR)VirtualAddress >> PDI1_SHIFT) & PDI_MASK);
|
|||
|
if (Pdr1[Index].Valid == 0) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Compute the 43-bit superpage address of the level two page
|
|||
|
// directory page and check to see if the page table page is
|
|||
|
// valid.
|
|||
|
//
|
|||
|
|
|||
|
Pdr2 = (PHARDWARE_PTE)(KSEG43_BASE | (Pdr1[Index].PageFrameNumber << PAGE_SHIFT));
|
|||
|
Index = (ULONG)(((ULONG_PTR)VirtualAddress >> PDI2_SHIFT) & PDI_MASK);
|
|||
|
if (Pdr2[Index].Valid == 0) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Compute the 43-bit superpage address of the page table page and
|
|||
|
// check to see if the data page is valid.
|
|||
|
|
|||
|
Ptp = (PHARDWARE_PTE)(KSEG43_BASE | (Pdr2[Index].PageFrameNumber << PAGE_SHIFT));
|
|||
|
Index = (ULONG)(((ULONG_PTR)VirtualAddress >> PTI_SHIFT) & PDI_MASK);
|
|||
|
if (Ptp[Index].Valid == 0) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Compute the 43-bit superpage address of the data page and return the
|
|||
|
// address of the PTE that maps the data page as the function value.
|
|||
|
//
|
|||
|
|
|||
|
*AccessAddress = (PVOID)(KSEG43_BASE |
|
|||
|
(Ptp[Index].PageFrameNumber << PAGE_SHIFT) |
|
|||
|
(ULONG_PTR)VirtualAddress & (PAGE_SIZE - 1));
|
|||
|
|
|||
|
return &Ptp[Index];
|
|||
|
}
|
|||
|
|
|||
|
PVOID
|
|||
|
MmDbgReadCheck (
|
|||
|
IN PVOID VirtualAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the 43-bit superpage address which corresponds
|
|||
|
to the specified virtual address if the specified virtual address
|
|||
|
is readable.
|
|||
|
|
|||
|
N.B. This function should only be called at IRQL DISPATCH_LEVEL or
|
|||
|
above.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Supplies the virtual address to check.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified virtual address is invalid or not readable, then a
|
|||
|
value of NULL is returned. Otherwise, the 43-bit superpage address
|
|||
|
which corresponds to the specified virtual address is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PVOID AccessAddress;
|
|||
|
|
|||
|
//
|
|||
|
// If the address is within the 32- or 43-bit superpage regions, then
|
|||
|
// the address is returned as the function value.
|
|||
|
//
|
|||
|
|
|||
|
if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) {
|
|||
|
return VirtualAddress;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if the specified virtual address if accessible. If the virtual
|
|||
|
// address is accessible, then return the 43-bit superpage address which
|
|||
|
// corresponds to the virtual address. Otherwise, return NULL.
|
|||
|
//
|
|||
|
|
|||
|
if (MiCheckAddress(VirtualAddress, &AccessAddress) == NULL) {
|
|||
|
return NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
return AccessAddress;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PVOID
|
|||
|
MmDbgWriteCheck (
|
|||
|
IN PVOID VirtualAddress,
|
|||
|
IN PHARDWARE_PTE Opaque
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the 43-bit superpage address which corresponds
|
|||
|
to the specified virtual address if the specified virtual address is
|
|||
|
writable.
|
|||
|
|
|||
|
N.B. This function should only be called at IRQL DISPATCH_LEVEL or
|
|||
|
above.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Supplies the virtual address to check.
|
|||
|
|
|||
|
Opaque - Supplies a pointer to fill with an opaque value.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified virtual address is invalid or not writable, then a
|
|||
|
value of NULL is returned. Otherwise, the 43-bit superpage address
|
|||
|
which corresponds to the specified virtual address is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
MMPTE PteContents;
|
|||
|
PVOID AccessAddress;
|
|||
|
PHARDWARE_PTE Pte;
|
|||
|
PMMPTE InputPte;
|
|||
|
|
|||
|
InputPte = (PMMPTE)Opaque;
|
|||
|
|
|||
|
InputPte->u.Long = 0;
|
|||
|
|
|||
|
//
|
|||
|
// If the address is within the 32- or 43-bit superpage regions, then
|
|||
|
// the address is returned as the function value.
|
|||
|
//
|
|||
|
|
|||
|
if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) {
|
|||
|
return VirtualAddress;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if the specified virtual address if accessible. If the virtual
|
|||
|
// address is accessible, then return the 43-bit superpage address which
|
|||
|
// corresponds to the virtual address. Otherwise, return NULL.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
Pte = MiCheckAddress(VirtualAddress, &AccessAddress);
|
|||
|
if (Pte == NULL) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (Pte->Write == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// PTE is not writable, make it so.
|
|||
|
//
|
|||
|
|
|||
|
PteContents = *(PMMPTE)Pte;
|
|||
|
|
|||
|
*InputPte = PteContents;
|
|||
|
|
|||
|
//
|
|||
|
// Modify the PTE to ensure write permissions :
|
|||
|
// turn on write and turn off fault on write.
|
|||
|
//
|
|||
|
|
|||
|
PteContents.u.Hard.Write = 1;
|
|||
|
PteContents.u.Hard.FaultOnWrite = 0;
|
|||
|
|
|||
|
*(PMMPTE)Pte = PteContents;
|
|||
|
|
|||
|
//
|
|||
|
// KeFillEntryTb is liable to IPI the other processors. This is
|
|||
|
// definitely NOT what we want as the other processors are frozen
|
|||
|
// in the debugger and we will deadlock if we try and IPI them.
|
|||
|
// Just flush the current processor instead.
|
|||
|
//
|
|||
|
// KeFillEntryTb ((PHARDWARE_PTE)PointerPte, VirtualAddress, TRUE);
|
|||
|
//
|
|||
|
|
|||
|
KiFlushSingleTb(TRUE, VirtualAddress);
|
|||
|
}
|
|||
|
else {
|
|||
|
return AccessAddress;
|
|||
|
}
|
|||
|
|
|||
|
return VirtualAddress;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
MmDbgReleaseAddress (
|
|||
|
IN PVOID VirtualAddress,
|
|||
|
IN PHARDWARE_PTE Opaque
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
i386/486 implementation specific:
|
|||
|
|
|||
|
This routine resets the specified virtual address access permissions
|
|||
|
to its original state.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Supplies the virtual address to check.
|
|||
|
|
|||
|
Opaque - Supplies an opaque pointer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode IRQL at DISPATCH_LEVEL or greater.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
MMPTE TempPte;
|
|||
|
PMMPTE PointerPte;
|
|||
|
PMMPTE InputPte;
|
|||
|
|
|||
|
InputPte = (PMMPTE)Opaque;
|
|||
|
|
|||
|
ASSERT (MmIsAddressValid (VirtualAddress));
|
|||
|
|
|||
|
if (InputPte->u.Long != 0) {
|
|||
|
|
|||
|
PointerPte = MiGetPteAddress (VirtualAddress);
|
|||
|
|
|||
|
TempPte = *InputPte;
|
|||
|
|
|||
|
*PointerPte = TempPte;
|
|||
|
|
|||
|
//
|
|||
|
// KeFillEntryTb is liable to IPI the other processors. This is
|
|||
|
// definitely NOT what we want as the other processors are frozen
|
|||
|
// in the debugger and we will deadlock if we try and IPI them.
|
|||
|
// Just flush the current processor instead.
|
|||
|
//
|
|||
|
// KeFillEntryTb ((PHARDWARE_PTE)PointerPte, VirtualAddress, TRUE);
|
|||
|
//
|
|||
|
|
|||
|
KiFlushSingleTb(TRUE, VirtualAddress);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
PVOID64
|
|||
|
MmDbgReadCheck64 (
|
|||
|
IN PVOID64 VirtualAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the 43-bit superpage address which corresponds
|
|||
|
to the specified virtual address if the specified virtual address
|
|||
|
is readable.
|
|||
|
|
|||
|
N.B. This function should only be called at IRQL DISPATCH_LEVEL or
|
|||
|
above.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Supplies the virtual address to check.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified virtual address is invalid or not readable, then a
|
|||
|
value of NULL is returned. Otherwise, the 43-bit superpage address
|
|||
|
which corresponds to the specified virtual address is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
return MmDbgReadCheck(VirtualAddress);
|
|||
|
}
|
|||
|
|
|||
|
PVOID64
|
|||
|
MmDbgWriteCheck64 (
|
|||
|
IN PVOID64 VirtualAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the 43-bit superpage address which corresponds
|
|||
|
to the specified virtual address if the specified virtual address is
|
|||
|
writable.
|
|||
|
|
|||
|
N.B. This function should only be called at IRQL DISPATCH_LEVEL or
|
|||
|
above.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Supplies the virtual address to check.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the specified virtual address is invalid or not writable, then a
|
|||
|
value of NULL is returned. Otherwise, the 43-bit superpage address
|
|||
|
which corresponds to the specified virtual address is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HARDWARE_PTE Opaque;
|
|||
|
|
|||
|
return MmDbgWriteCheck(VirtualAddress, &Opaque);
|
|||
|
}
|
|||
|
|
|||
|
PVOID64
|
|||
|
MmDbgTranslatePhysicalAddress64 (
|
|||
|
IN PHYSICAL_ADDRESS PhysicalAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
ALPHA implementation specific:
|
|||
|
|
|||
|
The Alpha processor provides a direct-mapped address space called
|
|||
|
the superpage. The entire physical address space can be
|
|||
|
addressed via the superpage. This routine translates a physical
|
|||
|
address to its corresponding superpage address. Unfortunately,
|
|||
|
the base superpage address is processor-dependent. Therefore, we
|
|||
|
have to compute it based on the processor level. As new processors are
|
|||
|
released, this routine will need to be updated.
|
|||
|
|
|||
|
This routine does not use PTEs.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PhysicalAddress - Supplies the physical address to translate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The virtual (superpage) address which corresponds to the physical address.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode IRQL at DISPATCH_LEVEL or greater.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
switch (KeProcessorLevel) {
|
|||
|
|
|||
|
case PROCESSOR_ALPHA_21064:
|
|||
|
case PROCESSOR_ALPHA_21066:
|
|||
|
case PROCESSOR_ALPHA_21068:
|
|||
|
PhysicalAddress.QuadPart &= 0x00000003ffffffff;
|
|||
|
PhysicalAddress.QuadPart |= 0xfffffc0000000000;
|
|||
|
break;
|
|||
|
|
|||
|
case PROCESSOR_ALPHA_21164:
|
|||
|
case PROCESSOR_ALPHA_21164PC:
|
|||
|
PhysicalAddress.QuadPart &= 0x000000ffffffffff;
|
|||
|
PhysicalAddress.QuadPart |= 0xfffffc0000000000;
|
|||
|
break;
|
|||
|
|
|||
|
case PROCESSOR_ALPHA_21264:
|
|||
|
PhysicalAddress.QuadPart &= 0x00000fffffffffff;
|
|||
|
PhysicalAddress.QuadPart |= 0xffff800000000000;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
return NULL64;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return (PVOID64)PhysicalAddress.QuadPart;
|
|||
|
}
|