|
|
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
bios.c
Abstract:
This module implements code to make SMI BIOS calls
Author:
Todd Carpenter (7/20/00) - create file
Environment:
Kernel mode
Notes:
Revision History:
--*/ #include <ntddk.h>
#include <ntacpi.h>
#include "amdk6.h"
LEGACY_GEMINI_SMI LegacyInterface;
#if DBG
VOID DisplayGBDT ( IN PGBDT GBDT ); #else
#define DisplayGBDT(_x_)
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FindGBDT)
#pragma alloc_text(PAGE, InitializeLegacyInterface)
#pragma alloc_text(PAGE, IsGeminiSupported)
#endif
NTSTATUS FindGBDT ( OUT PPGBDT GeminiInfo ) /*++
Description:
This routine looks in the BIOS memory area for the Gemini BIOS Descriptor Table. The signature will be located on a 16-byte bountry in the area from 0C0000h to 0FFFFFh or within the first 1K of the Extended BIOS Data Area. Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PVOID baseAddress; PGBDT newGBDTTable; ULONG_PTR address; ULONG_PTR limit; ULONG tableLength; PHYSICAL_ADDRESS PhysAddress; DebugEnter(); PAGED_CODE();
PhysAddress.HighPart = 0; PhysAddress.LowPart = GBDT_SEARCH_RANGE_BEGIN;
//
// Map memory to search for Gemini Bios table
//
baseAddress = MmMapIoSpace(PhysAddress, GBDT_SEARCH_RANGE_LENGTH, 0);
if (!baseAddress) { status = STATUS_INSUFFICIENT_RESOURCES; goto FindGBDTExit; }
//
// Compute limit for the for loop. Do not start a scan within 16 bytes of
// physical address 0xFFFFF
//
address = (ULONG_PTR) baseAddress; limit = address + GBDT_SEARCH_RANGE_LENGTH - GBDT_SEARCH_INTERVAL; for (; address <= limit; address += GBDT_SEARCH_INTERVAL) {
if ((((PGBDT)address)->Signature == GBDT_SIGNATURE) && (GetCheckSum((PUCHAR)address, ((PGBDT)address)->Length) == 0)) { //
// We found Gemini BIOS Descriptor Table
//
DebugPrint((TRACE, "GBDT Pointer found at: %x\n", address)); newGBDTTable = ExAllocatePoolWithTag(NonPagedPool, ((PGBDT)address)->Length, PROCESSOR_POOL_TAG);
if (!newGBDTTable) { status = STATUS_INSUFFICIENT_RESOURCES; goto FindGBDTExit; }
//
// Copy the Gemini BIOS Descriptor Table
//
RtlCopyMemory(newGBDTTable, (PVOID) address, ((PGBDT)address)->Length);
//
// Unmap mapped memory
//
MmUnmapIoSpace(baseAddress, GBDT_SEARCH_RANGE_LENGTH);
if (ARGUMENT_PRESENT(GeminiInfo)) { *GeminiInfo = newGBDTTable; }
status = STATUS_SUCCESS; goto FindGBDTExit; } }
FindGBDTExit:
DebugExitStatus(status); return status; }
NTSTATUS InitializeLegacyInterface ( VOID ) /*++
Description:
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status; ULONG currentState; ULONG platform = 0; DebugEnter(); PAGED_CODE(); status = FindGBDT(&LegacyInterface.GBDT);
if (!NT_SUCCESS(status)) { goto InitializeLegacyInterfaceExit; }
DisplayGBDT(LegacyInterface.GBDT); //
// Setup LegacyInterface structure
//
LegacyInterface.SmiAccessType = LegacyInterface.GBDT->SmiCommandPortType & 0x1; LegacyInterface.SmiAccessSize = (LegacyInterface.GBDT->SmiCommandPortType >> 0x4) & 0x3; LegacyInterface.SmiAddress = LegacyInterface.GBDT->SmiCommandPortAddress; LegacyInterface.GeminiCode = LegacyInterface.GBDT->GeminiSmiCode; LegacyInterface.MaxSupportedStates = LegacyInterface.GBDT->MaxStateSupported + 1; LegacyInterface.CurrentlyAvailableStates = LegacyInterface.GBDT->MaxStateSupported + 1;
//
// No perf states, we bail
//
if (LegacyInterface.CurrentlyAvailableStates == 0) { status = STATUS_UNSUCCESSFUL; goto InitializeLegacyInterfaceExit; }
status = IsGeminiSupported(&platform);
//
// if this is not a Gemini System or not of the K6 family, fail.
//
if (!NT_SUCCESS(status) || (platform != PLATFORM_AMDK6)) {
status = STATUS_UNSUCCESSFUL; goto InitializeLegacyInterfaceExit; }
status = GetCurrentStateSmm(¤tState);
if (!NT_SUCCESS(status)) { goto InitializeLegacyInterfaceExit; }
DebugAssert(currentState <= LegacyInterface.GBDT->MaxStateSupported); LegacyInterface.CurrentState = CONVERT_PERF_STATE_INDEX(currentState);
//
// Use direct transition method instead of SMI method
//
EnableGeminiTransitionsMSR(&LegacyInterface.EpmIoAddress);
InitializeLegacyInterfaceExit:
DebugExitStatus(status); return status; }
NTSTATUS IsGeminiSupported ( PULONG Results ) /*++
Description:
Input:
CX = 0000h ESI = Gemini_Code
Output:
ESI = 0 SMI was entered successfully ESI <> 0 SMI was entered, but function failed. ESI = Gemini Code, SMI was never entered CF = 0 SMM Function Successful CF = 1 SMM Function Failed, ESI = error code (see below) 0x90 requested Gemini State change not supported by hardware 0x91 the attempted State change failed upon read-back 0x92 function not supported in current implementation 0x94 the input parameters were erroneous/invalid AL = 6 (K6 Gemini platform), 7 (K7 Mustang platform)
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned; UCHAR platform;
PAGED_CODE(); //
// need to check whether type is I/O or memory mapped
// need to check access type size
//
_asm {
mov ecx, IS_GEMINI_SUPPORTED mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed
mov platform, al }
if (ARGUMENT_PRESENT(Results)) { ASSERT((platform == PLATFORM_AMDK6) || (platform == PLATFORM_AMDK7)); *Results = (ULONG) platform; } return STATUS_SUCCESS; SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "IsGeminiSupported() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
#if 0
NTSTATUS GetAvailableStatesSmm ( PULONG Results ) /*++
Description:
Input:
CX = 0001h ESI = Gemini_Code
Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code. BX = # of vaild entries
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned, bufferSize; USHORT stateEntries; PHYSICAL_ADDRESS stateBuffer; static AVAILABLE_STATE_INFO AvailableStates[16] = {0}; TRAP(); PAGED_CODE();
//
// Allocate buffer to hold state information for each state
// LegacyInterface.GBDT->CurrentlyAvailableStates * sizeof(AVAILABLE_STATE_INFO)
// For now we will just use a global array set to hold max size
//
bufferSize = sizeof(AvailableStates); stateBuffer = MmGetPhysicalAddress((PVOID)AvailableStates); ASSERT(stateBuffer.QuadPart);
_asm {
mov ecx, GET_GEMINI_STATES mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode mov eax, stateBuffer.LowPart mov ebx, bufferSize out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed
mov stateEntries, bx }
if (ARGUMENT_PRESENT(Results)) {
ASSERT((stateEntries > 0) || (stateEntries <= 16)); *Results = (ULONG) stateEntries;
}
return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "GetAvailableStatesSmm() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
NTSTATUS GetMaxStateSmm ( PULONG Results ) /*++
Description:
Input:
CX = 0002h ESI = Gemini_Code
Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code. AH = BF AL = VID BL = Gemini State number
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned; UCHAR state;
TRAP(); PAGED_CODE();
_asm {
mov ecx, GET_MAX_GEMINI_STATE mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed
mov state, bl }
//
// NOTE: currently we don't do use the VID and BF data returned in
// AX as it is a bit redundant because we should already have
// that data from the Gemini Bios Descriptor Table.
//
if (ARGUMENT_PRESENT(Results)) { *Results = (ULONG) state; }
return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "GetMaxStateSmm() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
NTSTATUS SetMaxStateSmm ( VOID ) /*++
Description:
Input:
CX = 0003h ESI = Gemini_Code
Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code.
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned; UCHAR maxState;
TRAP(); PAGED_CODE();
_asm {
mov ecx, SET_MAX_GEMINI_STATE mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed } return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "SetMaxStateSmm() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
NTSTATUS GetMinStateSmm ( PULONG Results ) /*++
Description:
Input:
CX = 0004h ESI = Gemini_Code
Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code. AH = BF AL = VID BL = Gemini State number
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned; UCHAR state;
TRAP(); PAGED_CODE();
_asm {
mov ecx, GET_MIN_GEMINI_STATE mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed
mov state, bl }
//
// NOTE: currently we don't do use the VID and BF data returned in
// AX as it is a bit redundant because we should already have
// that data from the Gemini Bios Descriptor Table.
//
if (ARGUMENT_PRESENT(Results)) { *Results = (ULONG) state; }
return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "GetMinStateSmm() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
NTSTATUS SetMinStateSmm ( VOID ) /*++
Description:
Input:
CX = 0005h ESI = Gemini_Code
Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code.
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned; UCHAR maxState;
TRAP(); PAGED_CODE();
_asm {
mov ecx, SET_MIN_GEMINI_STATE mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed
} return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "SetMinStateSmm() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
NTSTATUS SetCurrentStateSmm ( ULONG State ) /*++
Description:
Input:
CX = 0007h ESI = Gemini_Code AL = Gemini State Number
Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code.
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned, geminiState; UCHAR vidANDbf;
//
// Convert to Gemini State
//
geminiState = CONVERT_PERF_STATE_INDEX(State);
//
// Lookup VID and BF values for geminiState
//
vidANDbf = (LegacyInterface.GBDT->State[geminiState].Vid) | ((LegacyInterface.GBDT->State[geminiState].Bf) << 5);
_asm { mov ecx, SET_CURRENT_GEMINI_STATE mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode mov al, vidANDbf out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed
} return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "SetCurrentStateSmm() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
NTSTATUS ConnectDisconnectGeminiInterface ( BOOLEAN Connect ) /*++
Description:
Input:
CX = 0200h connect, 0201h disconnect ESI = Gemini_Code Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code.
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned, function;
TRAP(); PAGED_CODE();
function = Connect ? GEMINI_CONNECT : GEMINI_DISCONNECT;
_asm {
mov ecx, function mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed
}
return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "ConnectDisconnectGeminiInterface() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; } #endif
NTSTATUS GetCurrentStateSmm ( PULONG Results ) /*++
Description:
Input:
CX = 0006h ESI = Gemini_Code
Output:
ESI = 0 SMI was entered successfully ESI = Gemini Code, SMI was never entered CF = 0 SMM Operation Successful CF = 1 SMM Operation Failed, ESI = error code. AH = BF value AL = VID value BL = Gemini State number BH[0] = 0 (DC power) BH[0] = 1 (AC power)
Arguments:
Return Value:
NTSTATUS
--*/ { NTSTATUS status = STATUS_NOT_SUPPORTED; ULONG esiReturned, state; UCHAR vidANDbf;
PAGED_CODE();
_asm {
xor ebx, ebx xor eax, eax mov ecx, GET_CURRENT_GEMINI_STATE mov edx, LegacyInterface.SmiAddress mov esi, LegacyInterface.GeminiCode out dx, al mov esiReturned, esi test esi, esi jnz SmmFailed mov vidANDbf, al }
//
// NOTE: currently we don't do use the VID and BF data returned in
// AX as it is a bit redundant because we should already have
// that data from the Gemini Bios Descriptor Table.
//
// we are not currentingly using the AC / DC indicator either.
// this information is returned in BH [0 ].
//
//
// Lookup VID and BF values for geminiState
//
status = ConvertVidBfValueToGeminiState(vidANDbf, &state); DebugAssert(status == STATUS_SUCCESS); if (ARGUMENT_PRESENT(Results)) { *Results = (ULONG) state; } return STATUS_SUCCESS;
SmmFailed:
if (esiReturned == LegacyInterface.GeminiCode) {
//
// SMI failed, SMM was never entered.
//
} else {
//
// SMI was successful, but SMM operation failed (esi == failure)
//
}
DebugPrint((ERROR, "GetCurrentStateSmm() Failed: ESI = 0x%x\n", esiReturned)); return STATUS_UNSUCCESSFUL; }
NTSTATUS GetCpuFrequency ( IN ULONG State, OUT PULONG CpuSpeed ) /*++
Routine Description: Arguments: Return Value:
--*/ { ULONG geminiState; ASSERT(LegacyInterface.GBDT);
geminiState = CONVERT_PERF_STATE_INDEX(State); if (ARGUMENT_PRESENT(CpuSpeed)) { *CpuSpeed = LegacyInterface.GBDT->State[geminiState].CpuFrequency; }
return STATUS_SUCCESS;
}
NTSTATUS GetCpuVoltage ( IN ULONG State, OUT PULONG Voltage ) /*++
Routine Description: Arguments: Return Value:
--*/ { ULONG geminiState; USHORT bcdVoltage; ULONG intVoltage;
DebugAssert(LegacyInterface.GBDT);
geminiState = CONVERT_PERF_STATE_INDEX(State); bcdVoltage = LegacyInterface.GBDT->State[geminiState].CpuVoltage; intVoltage = Bcd8ToUlong(bcdVoltage);
if (ARGUMENT_PRESENT(Voltage)) { *Voltage = intVoltage; }
return STATUS_SUCCESS;
}
NTSTATUS GetLegacyMaxProcFrequency ( OUT PULONG CpuSpeed ) /*++
Description:
Arguments: Return Value:
NTSTATUS
--*/ { DebugAssert(CpuSpeed); if (LegacyInterface.GBDT) { *CpuSpeed = LegacyInterface.GBDT->MaxCpuSpeed; return STATUS_SUCCESS; }
return STATUS_UNSUCCESSFUL; }
NTSTATUS ConvertVidBfValueToGeminiState ( IN UCHAR VidBfValue, OUT PULONG State ) /*++
Routine Description: Arguments: Return Value:
--*/ { NTSTATUS status; ULONG state, x; UCHAR vid, bf;
vid = VidBfValue & 0x1f; // vid[4:0]
bf = VidBfValue >> 5; // bf[7:5]
for (x = 0; x < LegacyInterface.CurrentlyAvailableStates; x++) {
if ((LegacyInterface.GBDT->State[x].Vid == vid) && (LegacyInterface.GBDT->State[x].Bf == bf)) {
if (ARGUMENT_PRESENT(State)) { *State = x; }
return STATUS_SUCCESS; }
}
DebugPrint((ERROR, "Couldn't find a match for vid=0x%x and bf=0x%x\n", vid, bf)); return STATUS_UNSUCCESSFUL; }
#if DBG
VOID DisplayGBDT ( IN PGBDT GBDT ) {
ULONG x; DebugPrint((MAXTRACE, "\n")); DebugPrint((MAXTRACE, "Gemini BIOS Descriptor Table:\n")); DebugPrint((MAXTRACE, " Signature = %.4s\n", &GBDT->Signature)); // ULONG
DebugPrint((MAXTRACE, " Length = 0x%x\n", GBDT->Length)); // UCHAR
DebugPrint((MAXTRACE, " Bios Revision = 0x%x\n", GBDT->Revsion)); // UCHAR
DebugPrint((MAXTRACE, " Checksum = 0x%x\n", GBDT->Checksum)); // UCHAR
DebugPrint((MAXTRACE, " Capabilities = 0x%x\n", GBDT->Capabilities));// UCHAR
DebugPrint((MAXTRACE, " - TALERT is %ssupported\n", (GBDT->Capabilities & 0x1) ? "" : "NOT ")); DebugPrint((MAXTRACE, " - TPANIC is %ssupported\n", (GBDT->Capabilities & 0x2) ? "" : "NOT ")); DebugPrint((MAXTRACE, " Bus Speed = %u mhz\n", GBDT->BusSpeed)); // USHORT
DebugPrint((MAXTRACE, " Max CPU Speed = %u mhz\n", GBDT->MaxCpuSpeed));// USHORT
DebugPrint((MAXTRACE, " Max CPU State = %u\n", GBDT->MaxStateSupported)); // UCHAR
DebugPrint((MAXTRACE, " SMI Port Type = 0x%x\n", GBDT->SmiCommandPortType)); // UCHAR
DebugPrint((MAXTRACE, " - %s address\n", (GBDT->SmiCommandPortType & 0x1) ? "memory mapped" : "x86 I/O")); DebugPrint((MAXTRACE, " - Data Size = %u bits\n", ((GBDT->SmiCommandPortType >> 0x4) & 0x3) * 8)); DebugPrint((MAXTRACE, " SMI Port Address = 0x%x\n", GBDT->SmiCommandPortAddress)); // ULONG
DebugPrint((MAXTRACE, " Gemini Code = 0x%x\n", GBDT->GeminiSmiCode)); // ULONG
DebugPrint((MAXTRACE, " Perf States:\n"));
for (x=0; x <= GBDT->MaxStateSupported; x++) {
DebugPrint((MAXTRACE, " State %u:\n", x)); DebugPrint((MAXTRACE, " - Voltage = 0x%x\n", GBDT->State[x].CpuVoltage)); DebugPrint((MAXTRACE, " - Frequency = %u%\n", GBDT->State[x].CpuFrequency)); DebugPrint((MAXTRACE, " - VID = 0x%x\n", GBDT->State[x].Vid)); DebugPrint((MAXTRACE, " - BF = 0x%x\n", GBDT->State[x].Bf)); } DebugPrint((MAXTRACE, "\n")); } #endif
|