| /** |
| @file |
| Display the memory type range registers |
| |
| Copyright (c) 2012, Intel Corporation |
| All rights reserved. This program and the accompanying materials |
| are licensed and made available under the terms and conditions of the BSD License |
| which accompanies this distribution. The full text of the license may be found at |
| http://opensource.org/licenses/bsd-license.php |
| |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
| |
| **/ |
| |
| #include <WebServer.h> |
| #include <Library/MtrrLib.h> |
| |
| #define VARIABLE_MTRR_VALID 0x800 |
| |
| CONST char * mMemoryType [ ] = { |
| "Uncached", |
| "Write Combining", |
| "Reserved", |
| "Reserved", |
| "Write Through", |
| "Write Protected", |
| "Writeback" |
| }; |
| |
| |
| /** |
| Display a fixed MTRR row |
| |
| @param [in] SocketFD The socket's file descriptor to add to the list. |
| @param [in] pPort The WSDT_PORT structure address |
| @param [in] Start Start address for the region |
| @param [in] End End address for the region |
| @param [in] Type Memory type |
| |
| @retval EFI_SUCCESS The request was successfully processed |
| |
| **/ |
| EFI_STATUS |
| MtrrDisplayFixedRow ( |
| IN int SocketFD, |
| IN WSDT_PORT * pPort, |
| IN UINT64 Start, |
| IN UINT64 End, |
| IN UINT64 Type |
| ) |
| { |
| EFI_STATUS Status; |
| |
| // |
| // Use break instead of goto |
| // |
| for ( ; ; ) { |
| // |
| // Start the row |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| " <tr><td align=\"right\"><code>0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Start |
| // |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| Start ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td><td align=\"right\"><code>0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| End - 1 ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Type |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td><td>" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Type &= 0xff; |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ( DIM ( mMemoryType ) > Type ) |
| ? mMemoryType [ Type ] |
| : "Reserved" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End of row |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</td></tr>\r\n" ); |
| break; |
| } |
| |
| // |
| // Return the final status |
| // |
| return Status; |
| } |
| |
| |
| /** |
| Display the memory type registers |
| |
| @param [in] SocketFD The socket's file descriptor to add to the list. |
| @param [in] pPort The WSDT_PORT structure address |
| @param [out] pbDone Address to receive the request completion status |
| |
| @retval EFI_SUCCESS The request was successfully processed |
| |
| **/ |
| EFI_STATUS |
| MemoryTypeRegistersPage ( |
| IN int SocketFD, |
| IN WSDT_PORT * pPort, |
| OUT BOOLEAN * pbDone |
| ) |
| { |
| UINT64 Addr; |
| BOOLEAN bValid; |
| UINT64 Capabilities; |
| UINTN Count; |
| UINT64 DefType; |
| UINTN Index; |
| UINT64 Mask; |
| UINT64 MaxMtrrs; |
| CONST UINT64 mFixedAddresses [( 8 * MTRR_NUMBER_OF_FIXED_MTRR ) + 1 ] = { |
| 0ULL, |
| 0x10000ULL, |
| 0x20000ULL, |
| 0x30000ULL, |
| 0x40000ULL, |
| 0x50000ULL, |
| 0x60000ULL, |
| 0x70000ULL, |
| |
| 0x80000ULL, |
| 0x84000ULL, |
| 0x88000ULL, |
| 0x8c000ULL, |
| 0x90000ULL, |
| 0x94000ULL, |
| 0x98000ULL, |
| 0x9c000ULL, |
| |
| 0xa0000ULL, |
| 0xa4000ULL, |
| 0xa8000ULL, |
| 0xac000ULL, |
| 0xb0000ULL, |
| 0xb4000ULL, |
| 0xb8000ULL, |
| 0xbc000ULL, |
| |
| 0xc0000ULL, |
| 0xc1000ULL, |
| 0xc2000ULL, |
| 0xc3000ULL, |
| 0xc4000ULL, |
| 0xc5000ULL, |
| 0xc6000ULL, |
| 0xc7000ULL, |
| |
| 0xc8000ULL, |
| 0xc9000ULL, |
| 0xca000ULL, |
| 0xcb000ULL, |
| 0xcc000ULL, |
| 0xcd000ULL, |
| 0xce000ULL, |
| 0xcf000ULL, |
| |
| 0xd0000ULL, |
| 0xd1000ULL, |
| 0xd2000ULL, |
| 0xd3000ULL, |
| 0xd4000ULL, |
| 0xd5000ULL, |
| 0xd6000ULL, |
| 0xd7000ULL, |
| |
| 0xd8000ULL, |
| 0xd9000ULL, |
| 0xda000ULL, |
| 0xdb000ULL, |
| 0xdc000ULL, |
| 0xdd000ULL, |
| 0xde000ULL, |
| 0xdf000ULL, |
| |
| 0xe0000ULL, |
| 0xe1000ULL, |
| 0xe2000ULL, |
| 0xe3000ULL, |
| 0xe4000ULL, |
| 0xe5000ULL, |
| 0xe6000ULL, |
| 0xe7000ULL, |
| |
| 0xe8000ULL, |
| 0xe9000ULL, |
| 0xea000ULL, |
| 0xeb000ULL, |
| 0xec000ULL, |
| 0xed000ULL, |
| 0xee000ULL, |
| 0xef000ULL, |
| |
| 0xf0000ULL, |
| 0xf1000ULL, |
| 0xf2000ULL, |
| 0xf3000ULL, |
| 0xf4000ULL, |
| 0xf5000ULL, |
| 0xf6000ULL, |
| 0xf7000ULL, |
| |
| 0xf8000ULL, |
| 0xf9000ULL, |
| 0xfa000ULL, |
| 0xfb000ULL, |
| 0xfc000ULL, |
| 0xfd000ULL, |
| 0xfe000ULL, |
| 0xff000ULL, |
| |
| 0x100000ULL |
| }; |
| MTRR_SETTINGS Mtrr; |
| CONST UINT64 * pMemEnd; |
| CONST UINT64 * pMemStart; |
| UINT64 PreviousType; |
| UINT64 ShiftCount; |
| EFI_STATUS Status; |
| UINT64 Type; |
| INT64 Value; |
| |
| DBG_ENTER ( ); |
| |
| // |
| // Send the Memory Type Registers page |
| // |
| for ( ; ; ) { |
| // |
| // Send the page header |
| // |
| Status = HttpPageHeader ( SocketFD, pPort, L"Memory Type Range Registers" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Send the header |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<h1>Memory Type Range Registers</h1>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Determine if MTRRs are supported |
| // |
| if ( !IsMtrrSupported ( )) { |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<p>Memory Type Range Registers are not supported!\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| } |
| else { |
| // |
| // Get the capabilities |
| // |
| Capabilities = AsmReadMsr64 ( MTRR_LIB_IA32_MTRR_CAP ); |
| DefType = AsmReadMsr64 ( MTRR_LIB_IA32_MTRR_DEF_TYPE ); |
| |
| // |
| // Display the capabilities |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<p>Capabilities: " ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| Capabilities ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<br>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Display the default type |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "Def Type: " ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| DefType ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ", MTRRs " ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ( 0 != ( DefType & MTRR_LIB_CACHE_MTRR_ENABLED )) |
| ? "Enabled" |
| : "Disabled" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ", Fixed MTRRs " ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ( 0 != ( DefType & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED )) |
| ? "Enabled" |
| : "Disabled" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ", " ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Type = DefType & 0xff; |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ( DIM ( mMemoryType ) > Type ) |
| ? mMemoryType [ Type ] |
| : "Reserved" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</p>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Determine if MTRRs are enabled |
| // |
| if ( 0 == ( DefType & MTRR_LIB_CACHE_MTRR_ENABLED )) { |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<p>All memory is uncached!</p>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| } |
| else { |
| // |
| // Get the MTRRs |
| // |
| MtrrGetAllMtrrs ( &Mtrr ); |
| |
| // |
| // Determine if the fixed MTRRs are supported |
| // |
| if (( 0 != ( Capabilities & 0x100 )) |
| && ( 0 != ( DefType & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED ))) { |
| |
| // |
| // Beginning of table |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<h2>Fixed MTRRs</h2>\r\n" |
| "<table>\r\n" |
| " <tr><th>Index</th><th align=\"right\">Value</th><th align=\"right\">Start</th><th align=\"right\">End</th></tr>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Display the fixed MTRRs |
| // |
| pMemStart = &mFixedAddresses[ 0 ]; |
| for ( Count = 0; DIM ( Mtrr.Fixed.Mtrr ) > Count; Count++ ) { |
| // |
| // Start the row |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| " <tr><td>" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Index |
| // |
| Status = HttpSendValue ( SocketFD, |
| pPort, |
| Count ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Value |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</td><td align=\"right\"><code>0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| Mtrr.Fixed.Mtrr[ Count ]); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Start |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td><td align=\"right\"><code>0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| *pMemStart ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| pMemStart += 8; |
| |
| // |
| // Value |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td><td align=\"right\"><code>0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| *pMemStart - 1 ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End of row |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td></tr>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| } |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End of table |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</table>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Beginning of table |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<table>\r\n" |
| " <tr><th align=\"right\">Start</th><th align=\"right\">End</th><th align=\"left\">Type</th></tr>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Decode the fixed MTRRs |
| // |
| PreviousType = Mtrr.Fixed.Mtrr[ 0 ] & 0xff; |
| pMemStart = &mFixedAddresses[ 0 ]; |
| pMemEnd = pMemStart; |
| for ( Count = 0; DIM ( Mtrr.Fixed.Mtrr ) > Count; Count++ ) { |
| // |
| // Get the memory types |
| // |
| Type = Mtrr.Fixed.Mtrr[ Count ]; |
| |
| // |
| // Walk the memory range |
| // |
| for ( Index = 0; 8 > Index; Index++ ) { |
| // |
| // Determine if this is the same memory type |
| // |
| if ( PreviousType != ( Type & 0xff )) { |
| // |
| // Display the row |
| // |
| Status = MtrrDisplayFixedRow ( SocketFD, |
| pPort, |
| *pMemStart, |
| *pMemEnd, |
| PreviousType ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Start the next range of addresses |
| // |
| pMemStart = pMemEnd; |
| PreviousType = Type & 0xff; |
| } |
| |
| // |
| // Set the next memory range and type |
| // |
| Type >>= 8; |
| pMemEnd += 1; |
| } |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| } |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Display the final row |
| // |
| Status = MtrrDisplayFixedRow ( SocketFD, |
| pPort, |
| *pMemStart, |
| *pMemEnd, |
| PreviousType ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End of table |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</table>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| } |
| |
| // |
| // Determine if the variable MTRRs are supported |
| // |
| MaxMtrrs = Capabilities & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK; |
| if ( 0 < MaxMtrrs ) { |
| // |
| // Beginning of table |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "<h2>Variable MTRRs</h2>\r\n" |
| "<table>\r\n" |
| " <tr><th>Index</th><th align=\"right\">Base</th><th align=\"right\">Mask</th><th align=\"right\">Start</th><th align=\"right\">End</th></tr>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Display the variable MTRRs |
| // |
| for ( Count = 0; MaxMtrrs > Count; Count++ ) { |
| // |
| // Start the row |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| " <tr><td>" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Index |
| // |
| Status = HttpSendValue ( SocketFD, |
| pPort, |
| Count ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Base |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</td><td align=\"right\"><code>0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| Mtrr.Variables.Mtrr[ Count ].Base ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Mask |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</td><td align=\"right\"><code>0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| Mtrr.Variables.Mtrr[ Count ].Mask ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Determine if the entry is valid |
| // |
| bValid = ( Mtrr.Variables.Mtrr[ Count ].Mask & VARIABLE_MTRR_VALID ) ? TRUE : FALSE; |
| |
| // |
| // Start |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td><td align=\"right\"><code>" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Addr = Mtrr.Variables.Mtrr[ Count ].Base & 0xfffffffffffff000ULL; |
| if ( bValid ) { |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| Addr ); |
| } |
| else { |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "Invalid" ); |
| } |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td><td align=\"right\"><code>" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| if ( bValid ) { |
| // |
| // Determine the end address |
| // |
| Mask = Mtrr.Variables.Mtrr[ Count ].Mask; |
| Value = Mask; |
| ShiftCount = 0; |
| while ( 0 < Value ) { |
| Value <<= 1; |
| ShiftCount += 1; |
| } |
| Value = 1; |
| Value <<= 64 - ShiftCount; |
| Value -= 1; |
| Value = ~Value; |
| Value |= Mask; |
| Value &= ~VARIABLE_MTRR_VALID; |
| Value = ~Value; |
| |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "0x" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| Status = HttpSendHexValue ( SocketFD, |
| pPort, |
| Addr + Value ); |
| } |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // Type |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</code></td><td>" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| if ( bValid ) { |
| Type = Mtrr.Variables.Mtrr[ Count ].Base & 0xFF; |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| ( DIM ( mMemoryType ) > Type ) |
| ? mMemoryType [ Type ] |
| : "Reserved" ); |
| } |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End of row |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</td></tr>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| } |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| |
| // |
| // End of table |
| // |
| Status = HttpSendAnsiString ( SocketFD, |
| pPort, |
| "</table>\r\n" ); |
| if ( EFI_ERROR ( Status )) { |
| break; |
| } |
| } |
| } |
| } |
| |
| // |
| // Send the page trailer |
| // |
| Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); |
| break; |
| } |
| |
| // |
| // Return the operation status |
| // |
| DBG_EXIT_STATUS ( Status ); |
| return Status; |
| } |