/*++ 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; }