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;
|
||
}
|