summaryrefslogtreecommitdiff
path: root/cpu/amd/geode_lx/gplvsa_ii/sysmgr/vr_misc.asm
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/amd/geode_lx/gplvsa_ii/sysmgr/vr_misc.asm')
-rwxr-xr-xcpu/amd/geode_lx/gplvsa_ii/sysmgr/vr_misc.asm1161
1 files changed, 1161 insertions, 0 deletions
diff --git a/cpu/amd/geode_lx/gplvsa_ii/sysmgr/vr_misc.asm b/cpu/amd/geode_lx/gplvsa_ii/sysmgr/vr_misc.asm
new file mode 100755
index 0000000..f6b94af
--- /dev/null
+++ b/cpu/amd/geode_lx/gplvsa_ii/sysmgr/vr_misc.asm
@@ -0,0 +1,1161 @@
+;
+; Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
+;
+; This library is free software; you can redistribute it and/or modify
+; it under the terms of the GNU Lesser General Public License as
+; published by the Free Software Foundation; either version 2.1 of the
+; License, or (at your option) any later version.
+;
+; This code is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General
+; Public License along with this library; if not, write to the
+; Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+; Boston, MA 02111-1307 USA
+;
+;******************************************************************************
+;* Implements the virtual register VR_MISCELLANEOUS.
+;******************************************************************************
+
+
+.model tiny,c
+.586
+.CODE
+
+include VSA2.INC
+include SYSMGR.INC
+include VR.INC
+include CHIPSET.INC
+include GX2.INC
+
+externdef MsgPacket: byte
+externdef HistoryStart: word
+externdef HistoryEnd: word
+externdef HistoryWrap: word
+externdef SysMgr_VSM: dword
+externdef VSM_Ptrs: dword
+externdef Saved_EAX: dword
+externdef Saved_EBX: dword
+externdef Saved_ECX: dword
+externdef Saved_EDX: dword
+externdef Saved_ESI: dword
+externdef Saved_EDI: dword
+externdef Saved_EBP: dword
+externdef Saved_DS: dword
+externdef Saved_ES: dword
+externdef Saved_FS: dword
+externdef Saved_GS: dword
+externdef Saved_SS: dword
+externdef IDT_Selector: dword
+externdef IDT_Base: dword
+externdef IDT_Limit: dword
+externdef VSM_ListHead: dword
+
+externdef pascal Get_MSR_Linkage: proc
+externdef pascal Broadcast_Message: proc
+externdef pascal Register_Event: proc
+externdef Get_Errors: proc
+externdef VirtualRegisterEvent: proc
+externdef HardwareInfo: Hardware
+externdef History: EVENT_HISTORY
+externdef Events: EVENT_ENTRY
+externdef SMM_Header: SmiHeader
+
+; Required for OHCI h/w bugs
+externdef OHCI1_Hdr: dword
+externdef OHCI2_Hdr: dword
+externdef OHCI1_Smi: dword
+externdef OHCI2_Smi: dword
+
+;******************************************************************************
+ align 2
+
+public VSM_Filter
+VSM_Filter db VSM_ANY
+ db 0 ; Pad for alignment
+Next_VSM dd 0
+
+
+
+ReadMiscTable:
+ dw OFFSET Get_VSA_Version ; 0
+ dw OFFSET Read_High_Memory ; 1
+ dw OFFSET Get_VSM_Info ; 2
+ dw OFFSET Signature ; 3
+ dw OFFSET Get_HW_Info ; 4
+ dw OFFSET Get_VSM_Version ; 5
+ dw OFFSET JustReturn ; 6
+ dw OFFSET MSR_Read ; 7
+ dw OFFSET JustReturn ; 8
+MAX_READ equ ($-ReadMiscTable)/2
+
+WriteMiscTable:
+ dw OFFSET JustReturn ; 0
+ dw OFFSET Write_High_Memory ; 1
+ dw OFFSET JustReturn ; 2
+ dw OFFSET JustReturn ; 3
+ dw OFFSET Select_HW_Info ; 4
+ dw OFFSET JustReturn ; 5
+ dw OFFSET Warm_Boot ; 6
+ dw OFFSET MSR_Write ; 7
+ dw OFFSET Do_WBINVD ; 8
+MAX_WRITE equ ($-WriteMiscTable)/2
+
+
+VSM_Info_Table:
+ dw OFFSET Get_VSM_Basics
+ dw OFFSET Get_VSM_Events
+ dw OFFSET Get_VSM_Statistics
+ dw OFFSET Get_VSM_History
+ dw OFFSET Get_VSM_Hardware
+ dw OFFSET Get_Errors
+ dw OFFSET Set_VSM_Type
+ dw OFFSET Get_Linkage
+MAX_INFO equ ($-VSM_Info_Table)/2
+
+
+
+;***************************************************************************
+; Handler for reads from a VRC_MISCELLANEOUS register
+; Returns ULONG with value read
+;***************************************************************************
+VR_Miscellaneous_Read proc pascal uses si di \
+ Index: BYTE
+
+ mov al, [Index]
+ cmp al, MAX_READ
+ mov di, 0 ; Read
+ jae short VRC_Common
+
+ lea bx, [ReadMiscTable]
+ call Dispatch
+ ret
+
+VR_Miscellaneous_Read endp
+
+
+;***************************************************************************
+; Handler for writes to a VRC_MISCELLANEOUS register
+;***************************************************************************
+VR_Miscellaneous_Write proc pascal uses si di \
+ Index: BYTE
+
+ mov al, [Index]
+ cmp al, MAX_WRITE
+ jb short UseTable
+ mov di, 1 ; Write
+VRC_Common::
+ mov bh, VRC_MISCELLANEOUS
+ mov bl, al
+ mov edx, [SysMgr_VSM] ; From_VSM
+ mov cx, word ptr [Saved_EAX]
+ call VirtualRegisterEvent
+ jmp short Exit
+
+UseTable:
+ lea bx, [WriteMiscTable]
+ call Dispatch
+Exit: ret
+
+VR_Miscellaneous_Write endp
+
+;***************************************************************************
+; Dispatches to routine defined by table at BX[AL]
+;***************************************************************************
+Dispatch proc
+
+ xor ah, ah
+ add ax, ax
+ add bx, ax
+ call word ptr [bx]
+JustReturn::
+ ret
+Dispatch endp
+
+
+
+
+;***************************************************************************
+; Dispatches to sub-function of GET_VSM_INFO (determined by caller's BL)
+;***************************************************************************
+Get_VSM_Info proc
+
+ mov al, byte ptr [Saved_EBX]
+ cmp al, MAX_INFO
+ jae short Exit
+ lea bx, [VSM_Info_Table]
+ call Dispatch
+Exit: ret
+
+Get_VSM_Info endp
+
+
+;***************************************************************************
+; SI = PCI address
+;***************************************************************************
+Get_Linkage proc
+
+
+ push word ptr [Saved_ESI]
+ call Get_MSR_Linkage
+
+ mov word ptr [Saved_ECX], ax ; Return MSR address in caller's ECX
+ mov word ptr [Saved_ECX+2], dx
+
+ ret
+
+Get_Linkage endp
+
+
+;***************************************************************************
+; Returns in EAX the location by EBX.
+; CF is toggled
+;***************************************************************************
+Read_High_Memory proc
+
+ mov ebx, [Saved_EBX]
+ mov eax, fs:[ebx]
+ mov [Saved_EAX], eax
+ mov edx, eax
+ shr edx, 16
+
+ ; Toggle the caller's carry flag
+ xor byte ptr ([SMM_Header]).EFLAGS, EFLAGS_CF
+ ret
+
+Read_High_Memory endp
+
+;***************************************************************************
+; Modifies a memory location according to:
+; *EBX = *EBX & ESI | EDI;
+; CF is toggled
+;***************************************************************************
+Write_High_Memory proc
+
+ mov ebx, [Saved_EBX] ; Address
+ mov edx, [Saved_ESI] ; AND mask
+ mov eax, [Saved_EDI] ; OR mask
+ or edx, edx
+ jz short WriteBack
+
+ mov ecx, fs:[ebx]
+ and ecx, edx
+ or eax, ecx
+WriteBack:
+ mov fs:[ebx], eax
+ ; Toggle the caller's carry flag
+ xor byte ptr ([SMM_Header]).EFLAGS, EFLAGS_CF
+ ret
+
+Write_High_Memory endp
+
+
+
+
+;***************************************************************************
+; Modifies an MSR
+; On entry:
+; ECX = MSR address
+; ESI:EDI = AND mask
+; EBX:EAX = OR mask
+; On exit:
+; CF is toggled
+;***************************************************************************
+MSR_Write proc
+
+ mov ecx, [Saved_ECX] ; Get MSR address
+ call Read_MSR
+
+ and edx, [Saved_ESI] ; Apply AND mask
+ and eax, [Saved_EDI]
+ or edx, [Saved_EBX] ; Apply OR mask
+ or eax, [Saved_EAX]
+
+ test ecx, 0E0000000h
+ jnz Not_CPU_MSR
+ stc ; Indicate this is a WRMSR
+ call MSR_Handler ; Update the MSR
+ jmp short Exit
+
+Not_CPU_MSR:
+ wrmsr
+ ; Toggle the caller's carry flag
+Exit: xor byte ptr ([SMM_Header]).EFLAGS, EFLAGS_CF
+ ret
+
+MSR_Write endp
+
+
+
+
+
+
+;***************************************************************************
+; Reads an MSR
+; On entry:
+; ECX = MSR address
+; On exit:
+; EDX:EAX = MSR data
+; CF is toggled
+;***************************************************************************
+MSR_Read proc
+
+ mov ecx, [Saved_ECX] ; Get MSR address
+
+ call Read_MSR ; Handle special MSRs
+
+ mov [Saved_EAX], eax ; Return results
+ mov [Saved_EDX], edx
+
+ ; Toggle the caller's carry flag
+ xor byte ptr ([SMM_Header]).EFLAGS, EFLAGS_CF
+ ret
+
+MSR_Read endp
+
+
+;***************************************************************************
+; Input:
+; ECX = MSR address
+; Output:
+; EBX = OHCI BAR for multiplexer workaround (0 if not applicable)
+; EDX:EAX = MSR contents
+;***************************************************************************
+Read_MSR proc
+
+ test ecx, 0E0000000h ; Is the MSR in the CPU ?
+ jnz Not_CPU_MSR
+ xor edx, edx ; Yes, then possibly requires special handling
+ clc ; Indicate this is a RDMSR
+ call MSR_Handler ; Read the MSR
+ ret
+
+Not_CPU_MSR:
+ rdmsr
+ ret
+
+Read_MSR endp
+
+
+
+
+
+
+
+;***************************************************************************
+; Reads/writes MSRs that require special handling
+; a) those modified by SysMgr
+; b) those located in the SMM header
+; c) those that are SMM-related are not allowed to be written
+; On entry:
+; CF = 0 for MSR read
+; 1 for MSR write
+;***************************************************************************
+
+MSR_Handler proc
+ ASSUME BX: PTR SpecialMSR
+ lea bx, [Special_MSRs]
+ mov di, [SpecialMSR.RdHandler]
+ jnc MSR_Loop
+ mov di, [SpecialMSR.WrHandler]
+MSR_Loop:
+ cmp cx, [bx].MSR_Addr ; Does MSR match ?
+ je Match
+ add bx, sizeof(SpecialMSR) ; Advance table ptr
+ cmp [bx].MSR_Addr, 0000h ; End of table ?
+ jne MSR_Loop
+NotSpecial:
+ cmp di, [SpecialMSR.WrHandler] ; Read or Write ?
+ je short WriteMSR
+ rdmsr
+ jmp short Exit
+
+WriteMSR:
+ wrmsr
+ jmp short Exit
+
+
+Match: mov si, [bx].DataOffset
+ call word ptr [bx+di] ; Jump to MSR handler
+Exit: ret
+
+ ASSUME BX: NOTHING
+
+SpecialMSR struc
+ MSR_Addr dw ?
+ RdHandler dw ?
+ WrHandler dw ?
+ DataOffset dw ?
+SpecialMSR ends
+
+
+Special_MSRs:
+ ; MSR_Addr Rd_Handler Wr_Handler DataOffset
+ SpecialMSR {MSR_EFLAGS, Get_Header, Set_Header, (SMM_Header[0]).EFLAGS}
+ SpecialMSR {MSR_CR0, Get_Header, Set_CR0, (SMM_Header[0]).r_CR0}
+ SpecialMSR {MSR_DR7, Get_DR7, Set_DR7, (SMM_Header[0]).r_DR7}
+ SpecialMSR {1321h, Get_CS_Sel, Set_CS_Sel, (SMM_Header[0])}
+ SpecialMSR {1331h, Get_CS_Base, Set_CS_Base, (SMM_Header[0])}
+
+ SpecialMSR {1320h, Get_Selector, Set_Selector, Saved_ES}
+ SpecialMSR {1322h, Get_Selector, Set_Selector, Saved_SS}
+ SpecialMSR {1323h, Get_Selector, Set_Selector, Saved_DS}
+ SpecialMSR {1324h, Get_Selector, Set_Selector, Saved_FS}
+ SpecialMSR {1325h, Get_Selector, Set_Selector, Saved_GS}
+
+ SpecialMSR {1330h, Get_Base, Set_Base, Saved_ES}
+ SpecialMSR {1332h, Get_Base, Set_Base, Saved_SS}
+ SpecialMSR {1333h, Get_Base, Set_Base, Saved_DS}
+ SpecialMSR {1334h, Get_Base, Set_Base, Saved_FS}
+ SpecialMSR {1335h, Get_Base, Set_Base, Saved_GS}
+
+ SpecialMSR {1329h, Get_IDT_Sel, Set_IDT_Sel, IDT_Selector}
+ SpecialMSR {1339h, Get_IDT_Base, Set_IDT_Base, IDT_Base}
+
+ ; SMM related MSRs: don't allow these to be written
+ SpecialMSR {MSR_SMM_CTRL, NotSpecial, Exit}
+ SpecialMSR {MSR_SMM_HDR, NotSpecial, Exit}
+ SpecialMSR {MSR_SMM_LOC, NotSpecial, Exit}
+ SpecialMSR {MSR_RCONF_SMM, NotSpecial, Exit}
+
+ dw 0 ; End of table
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; Get MSR value from SMM Header
+Get_Header proc
+ mov eax, [si]
+ ret
+Get_Header endp
+
+
+ ; Store MSR value into SMM Header
+Set_Header proc
+ mov [si], eax
+ ret
+Set_Header endp
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; Segment selector & attributes
+ ASSUME SI: PTR Descriptor
+Get_Selector proc
+ mov ax, word ptr [si].attr
+ and ah, 0F0h ; Mask Limit 19:16
+ shl eax, 16
+ mov ax, [si].selector
+ ret
+Get_Selector endp
+
+Set_Selector proc
+ mov [si].selector, ax
+ shr eax, 16
+ and ah, 0F0h ; Mask Limit 19:16
+ and word ptr [si].attr, 0F00h ; Preserve Limit 19:16
+ or word ptr [si].attr, ax
+ ret
+Set_Selector endp
+
+
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; Segment base & limit
+Get_Base proc
+ mov ah, [si].base_31_24 ; Get base
+ mov al, [si].base_23_16
+ shl eax, 16
+ mov ax, [si].base_15_0
+
+ movzx dx, [si].limit_19_16 ; Get limit
+ mov bh, dl
+ and dl, 0Fh ; Preserve only limit
+ shl edx, 16
+ mov dx, [si].limit_15_0
+ test bh, G_BIT ; Handle page granular bit
+ jz short Exit
+ shl edx, 12
+ or dx, 0FFFh
+Exit: ret
+Get_Base endp
+
+
+Set_Base proc
+ mov [si].base_15_0, ax ; Set base in [Saved_?S]
+ ror eax, 16
+ mov [si].base_31_24, ah
+ mov [si].base_23_16, al
+ rol eax, 16 ; Restore base
+ and [si].limit_19_16, NOT G_BIT ; Clear Granularity bit
+
+ test edx, 0FFF00000h ; 32-bit limit ?
+ jz short Limit16
+
+ or [si].limit_19_16, G_BIT ; Set Granularity bit
+ shr edx, 12
+Limit16:
+ mov [si].limit_15_0, dx
+ shr edx, 16
+ and [si].limit_19_16, 0F0h
+ and dl, 0Fh
+ or [si].limit_19_16, dl
+ ret
+Set_Base endp
+
+ ASSUME SI: PTR SmiHeader
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; CS selector & attributes
+Get_CS_Sel proc
+ mov eax, dword ptr [si]._CS.selector
+ ret
+Get_CS_Sel endp
+
+Set_CS_Sel proc
+ mov dword ptr [si]._CS.selector, eax
+ ret
+Set_CS_Sel endp
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; CS base & limit
+Get_CS_Base proc
+ mov eax, [si]._CS.base
+ mov edx, [si]._CS.limit
+ ret
+Get_CS_Base endp
+
+Set_CS_Base proc
+ mov [si]._CS.base, eax
+ mov [si]._CS.limit, edx
+ ret
+Set_CS_Base endp
+
+
+
+ ASSUME SI: NOTHING
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+; CR0
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+Set_CR0 proc
+
+CD equ 40000000h
+NW equ 20000000h
+ mov ebx, (CD+NW)
+ mov edi, ebx
+ not edi
+ and ebx, eax ; Extract CD and NW
+ cmp ebx, NW ; Don't allow CD=0 & NW=1
+ je Exit
+ mov [si], eax ; Write new CR0 to the SMM header
+
+ ; 1) Update VSA's CR0
+ ; 2) Update SMM RCONF cache bits
+ ; 3) Update all VSM's CR0[CD] and CR0[NW]
+ ; 4) Flush the cache
+ wbinvd
+ mov esi, CR0
+ and esi, edi
+ or esi, ebx
+ mov CR0, esi
+
+ push bx
+ mov ecx, MSR_RCONF_DEFAULT ; Re-synch MSR_RCONF_SMM with MSR_RCONF_DEFAULT
+ rdmsr
+ mov bl, al
+ mov ecx, MSR_RCONF_SMM ; Update MSR_RCONF_SMM
+ rdmsr
+ mov al, REGION_WP ; Write-protect SMM region in non-SMM
+ mov dl, bl
+ wrmsr
+ wbinvd
+ pop bx
+
+ ; Update all VSM's CR0
+ mov ecx, [VSM_ListHead]
+VSM_Loop:
+ jecxz Exit
+ and fs:(VSM_Header PTR [ecx]).SysStuff.State.r_CR0, edi
+ or fs:(VSM_Header PTR [ecx]).SysStuff.State.r_CR0, ebx
+ mov ecx, fs:(VSM_Header PTR [ecx]).SysStuff.Flink
+ jmp VSM_Loop
+
+Exit: ret
+Set_CR0 endp
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; DR7
+Get_DR7 proc
+ mov edx, [si] ; Get DR7 in SMM header
+ mov eax, DR6
+Exit: ret
+Get_DR7 endp
+
+Set_DR7 proc
+ xchg [si], edx ; Set DR7 field in SMM header
+ mov eax, DR6 ; EAX = current DR7
+ wrmsr ; Update DR6
+ ret
+Set_DR7 endp
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; IDT selector & attributes
+Get_IDT_Sel proc
+ mov eax, [si]
+ ret
+Get_IDT_Sel endp
+
+Set_IDT_Sel proc
+ mov [si], eax
+ ret
+Set_IDT_Sel endp
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ ; IDT base & limit
+Set_IDT_Base proc
+ mov [si], eax
+ mov [IDT_Limit], edx
+ ret
+Set_IDT_Base endp
+
+Get_IDT_Base proc
+ mov eax, [si]
+ mov edx, [IDT_Limit]
+ ret
+Get_IDT_Base endp
+
+MSR_Handler endp
+
+
+
+
+
+;***************************************************************************
+; Sets the VSM type for filtering events kept in the History buffer.
+;***************************************************************************
+Set_VSM_Type proc
+
+ mov al, byte ptr [Saved_EBX+1]
+ mov [VSM_Filter], al
+ ret
+
+Set_VSM_Type endp
+
+;***************************************************************************
+; SYS_BROADCAST_MSG(MSG_WARM_BOOT, &Param, VSM_ANY);
+;***************************************************************************
+Warm_Boot proc
+
+ xor eax, eax
+ lea bx, [MsgPacket]
+ mov [bx+0], eax
+ mov [bx+4], eax
+ mov [bx+8], eax
+
+ push word ptr MSG_WARM_BOOT ; Message code
+ push word ptr VSM_ANY ; To VSMs
+ push eax ; From_VSM
+ call Broadcast_Message
+ ret
+
+Warm_Boot endp
+
+
+
+
+;***************************************************************************
+; Returns VSA II signature in caller's EAX
+;***************************************************************************
+Signature proc
+
+ mov ax, VSA2_SIGNATURE AND 0FFFFh
+ mov dx, VSA2_SIGNATURE SHR 16
+ ret
+
+Signature endp
+
+
+;***************************************************************************
+; Returns version of VSA II in caller's AX
+;***************************************************************************
+Get_VSA_Version proc
+
+ mov ax, VSA_VERSION
+ ret
+
+Get_VSA_Version endp
+
+
+
+
+;***************************************************************************
+; Returns the version # of the specified VSM type
+;***************************************************************************
+Get_VSM_Version proc
+
+ ; Get caller's BL
+ mov dl, byte ptr [Saved_EBX]
+Find_VSM::
+ mov ecx, [SysMgr_VSM]
+ mov ax, 0FFFFh ; Not found
+VSM_Loop:
+ jecxz Exit
+ cmp dl, fs:(VSM_Header PTR [ecx]).VSM_Type
+ je Found
+ mov ecx, fs:(VSM_Header PTR [ecx]).SysStuff.Flink
+ jmp VSM_Loop
+
+Found: mov ax, fs:(VSM_Header PTR [ecx]).VSM_Version
+Exit: mov word ptr [Saved_EAX], ax
+ ret
+
+
+Get_VSM_Version endp
+
+
+
+
+
+
+
+;***************************************************************************
+; Helper routine
+; On Entry:
+; Caller's BH - VSM type to process
+; On Exit:
+; ECX - ptr to the next VSM to be processed
+;***************************************************************************
+Common_Entry proc
+
+ mov ecx, [Next_VSM]
+ mov dl, byte ptr [Saved_EBX+1] ; Caller's BH
+ cmp dl, 0FFh ; Next VSM ?
+ je Exit
+
+ call Find_VSM
+ cmp ax, 0FFFFh
+ stc
+ jz Return
+
+Exit: clc
+Return:ret
+
+Common_Entry endp
+
+;***************************************************************************
+; Updates Next_VSM with the Flink field of the current VSM
+;***************************************************************************
+Common_Exit proc
+
+ ; Get ptr to next VSM
+ mov ecx, fs:(VSM_Header PTR [ecx]).SysStuff.Flink
+ mov [Next_VSM], ecx
+ ret
+
+Common_Exit endp
+
+
+
+
+
+;***************************************************************************
+; Return's to caller's registers:
+; EAX - VSM_Version::VSM_Type (0xFFFF if no more)
+; EBX - Base of VSM
+; ECX - IP::SP
+; DX - VSM_Length
+;***************************************************************************
+Get_VSM_Basics proc
+
+ call Common_Entry
+ jc short Exit
+
+ ; Put info into caller's registers
+ mov [Saved_EBX], ecx
+
+ mov ax, fs:(VSM_Header PTR [ecx]).VSM_Version
+ shl eax, 16
+ movzx ax, fs:(VSM_Header PTR [ecx]).VSM_Type
+ mov [Saved_EAX], eax
+
+ mov ax, word ptr fs:(VSM_Header PTR [ecx]).SysStuff.State.Next_EIP
+ shl eax, 16
+ mov ax, word ptr fs:(VSM_Header PTR [ecx]).SysStuff.SavedESP
+ mov [Saved_ECX], eax
+
+ mov ax, word ptr fs:(VSM_Header PTR [ecx]).DS_Limit
+ mov word ptr [Saved_EDX], ax
+
+ call Common_Exit
+
+Exit: ret
+
+Get_VSM_Basics endp
+
+
+;***************************************************************************
+; Entry:
+; CL - History entry # (0-based)
+; CH - 1 to clear history buffer
+; Exit:
+; AL - VSM type
+; AH - Event
+; EBX - Count
+; ECX - Param1
+; EDX - Param2
+; EDI:ESI - TimeStamp
+;***************************************************************************
+Get_VSM_History proc
+
+if HISTORY
+
+ ; Get starting index
+ mov ax, [HistoryStart]
+ mov cx, [HistoryEnd]
+ cmp ax, cx
+ je NoHistory
+
+ movzx dx, byte ptr [Saved_ECX]
+ add ax, dx
+ mov dl, HISTORY ; Index = (HistoryStart+CX) % HISTORY
+ div dl
+ movzx ax, ah
+
+ cmp ax, cx ; if (Index < HistoryEnd)
+ jb short GetItem ; goto GetItem
+ mov dx, ax
+ cmp dx, cx
+ jne short GetItem
+
+ cmp byte ptr [Saved_ECX+1], 1
+ jne NoHistory
+ xor ax, ax
+ mov [HistoryStart], ax
+ mov [HistoryEnd], ax
+ mov [HistoryWrap], ax
+ jmp NoHistory
+
+GetItem:
+
+
+ ; Get ptr to History[] entry
+ lea bx, History
+ ASSUME BX: PTR EVENT_HISTORY
+ mov dl, sizeof(EVENT_HISTORY)
+ mul dl
+ add bx, ax
+
+ ; Get info about the event
+ mov ah, byte ptr [bx].Event
+ mov ecx, [bx].Vsm
+ mov al, fs:(VSM_Header PTR [ecx]).VSM_Type
+ mov word ptr [Saved_EAX], ax
+
+ mov eax, [bx].Count
+ mov [Saved_EBX], eax
+
+ mov eax, [bx].Param1
+ mov [Saved_ECX], eax
+
+ mov eax, [bx].Param2
+ mov [Saved_EDX], eax
+
+ mov eax, [bx].TimeStamp
+ mov [Saved_ESI], eax
+ mov eax, [bx].TimeStamp+4
+ mov [Saved_EDI], eax
+ ret
+
+endif
+
+
+NoHistory:
+ xor eax, eax
+ mov [Saved_EAX], eax
+ ret
+
+
+Get_VSM_History endp
+
+
+;***************************************************************************
+; Returns:
+; AX = Chipset ID
+; BX = CPU ID
+; CX = CPU MHz
+; EDX = PCI address of Southbridge
+;***************************************************************************
+Get_VSM_Hardware proc
+
+ ; Get ptr to Hardware structure
+ lea bx, [HardwareInfo]
+ ASSUME BX: PTR Hardware
+
+ mov ax, [bx].Chipset_ID
+ mov word ptr [Saved_EAX], ax
+
+ mov ax, [bx].CPU_ID
+ mov word ptr [Saved_EBX], ax
+
+ mov ax, [bx].CPU_MHz
+ mov word ptr [Saved_ECX], ax
+
+ mov eax, [bx].Chipset_Base
+ mov [Saved_EDX], eax
+
+ ret
+
+ ASSUME BX: NOTHING
+
+Get_VSM_Hardware endp
+
+
+;***************************************************************************
+; Returns:
+; AX = Chipset ID
+;***************************************************************************
+Get_HW_Info proc
+
+ mov ax, 0FFFFh ; Value for illegal index
+ movzx bx, [HW_Index]
+ cmp bl, MAX_HW_INFO
+ ja short Exit
+
+ add bx, bx
+ mov bx, [HW_Offsets+bx]
+ mov ax, [bx]
+Exit:
+ mov word ptr [Saved_EAX], ax
+ ret
+
+Get_HW_Info endp
+
+HW_Index db 0
+
+HW_Offsets:
+ dw OFFSET HardwareInfo.Chipset_ID
+ dw OFFSET HardwareInfo.Chipset_Rev
+ dw OFFSET HardwareInfo.Chipset_Base
+ dw OFFSET HardwareInfo.CPU_ID
+ dw OFFSET HardwareInfo.CPU_Revision
+ dw OFFSET HardwareInfo.CPU_MHz
+ dw OFFSET HardwareInfo.PCI_MHz
+MAX_HW_INFO equ ($-HW_Offsets)/2-1
+
+
+
+;***************************************************************************
+; Entry:
+; AL - Hardware item to be returned by Select_HW_Info
+; 0 = Southbridge ID
+; 1 = Southbridge Revision
+; 2 = Southbridge PCI address
+; 3 = CPU ID
+; 4 = CPU Revision
+; 5 = CPU MHz
+; 6 = PCI MHz
+;***************************************************************************
+Select_HW_Info proc
+
+ mov al, byte ptr [Saved_EAX]
+ mov [HW_Index], al
+ ret
+
+Select_HW_Info endp
+
+;***************************************************************************
+; Entry:
+; ESI - VSM of interest
+; Exit:
+; EAX - Priority::Event
+; ECX - Param1
+; EDX - Param2
+;***************************************************************************
+Get_VSM_Events proc
+
+ mov esi, [Saved_ESI] ; Get the VSM of interest
+ mov cx, word ptr [CurrentIndex]
+EventIndex:
+ mov al, sizeof(EVENT_ENTRY)
+ mul cl
+ lea bx, [Events]
+ add bx, ax
+ ASSUME BX: PTR EVENT_ENTRY
+ cmp esi, [bx].Vsm ; Is it the VSM of interest ?
+ je FoundEvent
+
+ mov cl, [bx].Link ; Get link to next event
+ or cl, cl
+ jnz EventIndex
+
+ ; Increment Event
+ inc ch ; Increment event index
+ mov cl, ch
+ cmp ch, MAX_EVENT ; Last event ?
+ jbe EventIndex
+ xor cx, cx ; Yes, reset variables
+
+ ; Set the caller's carry flag
+ or byte ptr ([SMM_Header]).EFLAGS, EFLAGS_CF
+ jmp short Exit
+
+
+FoundEvent:
+ mov eax, [bx].Param1 ; Return Param1 in ECX
+ mov [Saved_ECX], eax
+ mov eax, [bx].Param2 ; Return Param2 in EDX
+ mov [Saved_EDX], eax
+
+ mov ax, [bx].Priority ; Return Priority::Event in EAX
+ shl eax, 16
+ movzx ax, ch
+ mov [Saved_EAX], eax
+
+ mov cl, [bx].Link ; Get link to next event
+
+Exit: mov word ptr [CurrentIndex], cx
+ ret
+
+ ASSUME BX:NOTHING
+
+
+CurrentIndex db 0
+CurrentEvent db 0
+
+Get_VSM_Events endp
+
+
+
+;***************************************************************************
+; Entry:
+; Caller's BH - VSM to report (0FFh for next)
+; Caller's CL - clear statistics flag (1=clear)
+; Exit:
+; EDX:EAX - # SMIs
+; EBX:ECX - # clocks
+; BP - VSM Type
+; If SysMgr:
+; EDI:ESI - start time
+; 16 MSBs BP - clock adjustment
+; Carry Flag set if no more VSMs
+;
+;***************************************************************************
+Get_VSM_Statistics proc
+
+ call Common_Entry
+ jc Exit
+ or ecx, ecx
+ jz NoMoreVSMs
+
+
+ mov dl, byte ptr [Saved_ECX] ; Get /S flag
+ cld
+
+
+ ; If SysMgr, freeze statistics & return extra information
+ cmp fs:(VSM_Header PTR [ecx]).VSM_Type, VSM_SYS_MGR
+ jne ReturnInfo
+
+ mov bx, OFFSET VSM_Header.SysStuff
+ ASSUME BX: PTR System
+
+ ; EDI:ESI - start time
+ ; 16 MSBs EBP - adjustment (clocks/SMI)
+ mov ax, word ptr [bx].Adjustment
+ mov word ptr [Saved_EBP+2], ax
+
+ mov eax, [bx+0].StartClocks
+ mov [Saved_ESI], eax
+ mov eax, [bx+4].StartClocks
+ mov [Saved_EDI], eax
+
+ ; Clear statistics ?
+ cmp dl, 1
+ jne short FreezeStats
+
+ ; Yes, record a new start time
+ push dx
+ rdtsc
+ mov [bx+0].StartClocks, eax
+ mov [bx+4].StartClocks, edx
+ pop dx
+
+ ASSUME BX:NOTHING
+
+
+
+ ; Freeze statistics of all VSMs
+FreezeStats:
+ push ecx
+ mov ebx, ecx
+ xor eax, eax
+VSM_Loop:
+ lea esi, (VSM_Header PTR [ebx]).SysStuff.Clocks
+ lea edi, (VSM_Header PTR [ebx]).SysStuff.FrozenClocks
+ mov ecx, 4
+ rep movsd [edi], es:[esi]
+
+ ; Clear statistics ?
+ cmp dl, 1
+ jne short NextVSM
+ lea edi, (VSM_Header PTR [ebx]).SysStuff.Clocks
+ mov cl, 4
+ rep stosd [edi]
+
+NextVSM:
+ mov ebx, es:(VSM_Header PTR [ebx]).SysStuff.Flink
+ or ebx, ebx
+ jnz VSM_Loop
+
+ pop ecx
+
+
+ ; Put info into caller's registers
+ReturnInfo:
+ movzx ax, es:(VSM_Header PTR [ecx]).VSM_Type
+ mov word ptr [Saved_EBP], ax
+
+ lea esi, (VSM_Header PTR [ecx]).SysStuff.FrozenClocks
+ lodsd es:[esi]
+ mov [Saved_EAX], eax
+ lodsd es:[esi]
+ mov [Saved_EDX], eax
+ lodsd es:[esi]
+ mov [Saved_ECX], eax
+ lodsd es:[esi]
+ mov [Saved_EBX], eax
+
+ call Common_Exit
+ ret
+
+NoMoreVSMs:
+ ; Set caller's CF
+ or byte ptr ([SMM_Header]).EFLAGS, EFLAGS_CF
+Exit: ret
+
+Get_VSM_Statistics endp
+
+
+;***************************************************************************
+; Invalidates the cache(s)
+;***************************************************************************
+Do_WBINVD proc
+
+ wbinvd
+ ret
+
+Do_WBINVD endp
+
+
+;***************************************************************************
+; Updates the CR0 field of each VSM with the current non-VSA CR0
+;***************************************************************************
+Update_VSMs_CR0 proc
+
+ mov si, OFFSET [SMM_Header[0].r_CR0]
+ mov eax, [si] ; Get current CR0
+ call Set_CR0
+ ret
+
+Update_VSMs_CR0 endp
+
+ END