summaryrefslogtreecommitdiff
path: root/cpu/amd/geode_lx/gplvsa_ii/sysmgr/sysmgr.asm
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/amd/geode_lx/gplvsa_ii/sysmgr/sysmgr.asm')
-rwxr-xr-xcpu/amd/geode_lx/gplvsa_ii/sysmgr/sysmgr.asm804
1 files changed, 804 insertions, 0 deletions
diff --git a/cpu/amd/geode_lx/gplvsa_ii/sysmgr/sysmgr.asm b/cpu/amd/geode_lx/gplvsa_ii/sysmgr/sysmgr.asm
new file mode 100755
index 0000000..0a385df
--- /dev/null
+++ b/cpu/amd/geode_lx/gplvsa_ii/sysmgr/sysmgr.asm
@@ -0,0 +1,804 @@
+;
+; 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
+;
+;* Function: *
+;* This file contains the entry point to the SMM code. *
+;* This code performs the following: *
+;* 1) saves the processor state *
+;* 2) reads the top-level SMI source register(s) *
+;* 3) issues message(s) to the appropriate VSM(s) *
+;* 4) dispatches to VSM(s) until all messages are handled *
+;* 5) restores the processor state
+
+include SYSMGR.INC
+include VSA2.INC
+include PCI.INC
+include SMIMAC.MAC
+include CHIPSET.INC
+include CS5536.INC
+include GX2.INC
+
+.model tiny,c
+.586p
+
+.ALPHA
+DGROUP GROUP _CODE, _TEXT
+_CODE SEGMENT PUBLIC use16 'CODE'
+ ASSUME DS:_CODE
+
+
+BRACKETS equ 0
+
+public SysMgr_Entry
+public Nested_SMI
+public Saved_EAX, Saved_AX
+public Saved_EBX, Saved_ECX, Saved_EDX, Saved_PCI
+public Saved_ESI, Saved_EDI, Saved_EBP, Saved_ESP
+public Saved_SS, Saved_ES, Saved_DS, Saved_FS, Saved_GS
+public IDT_Selector, IDT_Base, IDT_Limit
+public VSMs_EAX
+public Nested_PCI, Nested_EDI, Nested_EAX, Nested_ES
+public StartSaveArea, EndSaveArea
+public SchedulerStack
+public Sys_Exit
+public VSM_ListHead
+public SMM_Header
+public SysMgr_VSM
+public Data_Descriptor
+public Flat_Descriptor
+public Current_VSM
+public Nested_Flag
+public HardwareInfo
+public SMI_Base
+public IRQ_Base, IRQ_Mask
+public Header_Addr
+public BracketFlag
+public ExitSysCall
+public EmptyMsgQueue
+public Dispatcher
+public Trap_Code
+
+externdef Trap_Common: proc
+externdef Trap7: proc
+externdef Get_SMI_Sources: proc
+externdef VSA_Entry: proc
+externdef VSA_Exit: proc
+externdef Show_SMI_Source: proc
+externdef Generate_IRQ: proc
+externdef pascal Hex_8: proc
+externdef pascal Hex_16: proc
+externdef pascal Hex_32: proc
+externdef pascal SMINT_Handler:proc
+
+externdef INT_Vectors: dword
+externdef SMI_Sources: dword
+externdef SynchEvents: dword
+externdef HiPrioritySMIs: dword
+externdef MSRs: dword
+
+externdef SysCall_Table: word
+
+externdef NumDescriptors: byte
+externdef Events: byte
+externdef MSRs: byte
+externdef _end: byte
+externdef edata: byte
+
+externdef Handler_Table: SMI_ENTRY
+
+
+
+
+
+
+
+
+; NOTE: "#define EXTRA_SAVE" in SYSMGR.H must match the number of bytes
+; of state (over and above the registers) that is saved by the
+; following two macros:
+SAVE_STATE macro
+ pushad ; Save general purpose registers
+ mov dx, PCI_CONFIG_ADDRESS ; Save PCI Configuration Address
+ in eax, dx
+ push eax
+
+ endm
+
+
+RESTORE_STATE macro
+ pop eax ; PCI Configuration Address
+ mov dx, PCI_CONFIG_ADDRESS
+ out dx, eax
+ popad ; Restore general purpose registers
+
+ endm
+
+
+
+
+Start:
+; NOTE: The VSA II installer patches a "JMP SysMgr_Entry" over the signature field
+ dd VSM_SIGNATURE ; VSM signature
+ db VSM_SYS_MGR ; VSM type
+ db 0FFh ; Any CPU
+ dw DEVICE_ID_5536 ; VSA for CS5536
+ dw VSA_VERSION ; System Manager version
+ dd OFFSET edata ; Size of System Manager
+ dw OFFSET SysMgr_Entry ; EntryPoint
+ dd OFFSET _end ; DS Limit
+ dw 0007h ; Requirements: 4096-byte boundary
+ dw VSA_VERSION ; VSA version
+
+Stack_Descriptor:
+ Descriptor {_end, 0000h, 00h, DATA_ATTR, 00h, 00h, 0000h}
+Data_Descriptor:
+ Descriptor {_end, 0000h, 00h, DATA_ATTR, 00h, 00h, 0000h}
+
+Flat_Descriptor:
+ Descriptor {0FFFFh, 0000h, 00h, DATA_ATTR, 8Fh, 00h, 0000h}
+
+
+ dw 0 ; .AlignSystem
+SMM_Header SmiHeader {} ; .State
+VSM_ListHead dd 0 ; .Flink (ptr to 1st VSM; zero if no VSMs)
+
+Trap macro Trap_Num
+ ORG Trap_Code + (Trap_Num * 8)
+ mov bx, Trap_Num
+ jmp Trap_Common
+ endm
+
+ ORG sizeof(VSM_Header)
+ align 16
+
+;***********************************************************************
+; Exception vectors
+;***********************************************************************
+Trap_Code:
+ Trap 0
+ Trap 1
+ Trap 2
+ Trap 3
+ Trap 4
+ Trap 5
+ Trap 6
+
+ ORG Trap_Code + (7 * 8)
+ jmp Trap7
+
+ Trap 8
+ Trap 9
+ Trap 0Ah
+ Trap 0Bh
+ Trap 0Ch
+ Trap 0Dh
+ Trap 0Eh
+ Trap 0Fh
+
+
+
+;***********************************************************************
+; Non-nested VSA entry point *
+;***********************************************************************
+SysMgr_Entry:
+
+ ;
+ ; Save state of interrupted task & initialize VSA environment
+ ;
+ svdc cs:[Saved_DS], ds ; Save DS descriptor & set to SysMgr segment
+ rsdc ds, cs:[Data_Descriptor]
+ ASSUME DS:_CODE
+
+ svdc [Saved_ES], es ; Save ES descriptor
+ svdc [Saved_FS], fs ; Save FS descriptor
+ svdc [Saved_GS], gs ; Save GS descriptor
+
+ svdc [Saved_SS], ss ; Save SS descriptor & set to SysMgr segment
+ rsdc ss, [Stack_Descriptor]
+ mov [Saved_ESP], esp ; Save ESP & set up SysMgr stack
+ mov esp, OFFSET SysMgrStack
+
+ SAVE_STATE ; Save the general purpose registers on SysMgr's stack
+
+
+ rdtsc ; Get start time of this SMI
+ mov (VSM_Header PTR ds:[0]).SysStuff.StartTime, eax
+ mov (VSM_Header PTR ds:[4]).SysStuff.StartTime, edx
+
+ rsdc fs, [Flat_Descriptor] ; Set FS descriptor to a 4 GB flat segment
+ rsdc es, [Flat_Descriptor] ; Set ES descriptor to a 4 GB flat segment
+
+if BRACKETS
+ cmp [BracketFlag], 0
+ je short NoBracket
+ mov dx, DBG_PORT
+ mov al, '['
+ out dx, al
+
+NoBracket:
+endif
+
+
+ call VSA_Entry ; Perform VSA entry setup
+
+ xor eax, eax
+ mov [Nested_Flag], eax
+
+ ;
+ ; Check for SMINT
+ ;
+ test [SMM_Header].SMI_Flags, 1000b
+ jz short Main_SMI_Loop
+
+ push word ptr [Saved_EAX]
+ call SMINT_Handler
+ jmp Dispatcher
+
+;***********************************************************************
+;***********************************************************************
+;***********************************************************************
+; *
+; Main SMI Loop *
+; *
+; 1) Read the top-level SMI sources. *
+; 2) If no SMIs are pending, exit SMM. *
+; 3) Call an SMI handler for each pending SMI source. *
+; 4) Dispatch to VSMs that have non-empty message queues. *
+; 5) Rinse and repeat. *
+; *
+;***********************************************************************
+;***********************************************************************
+;***********************************************************************
+Main_SMI_Loop:
+
+ call Get_SMI_Sources ; Get source(s) of external SMIs
+ test ebx, ebx ; If no SMIs pending, exit SMM
+ jz SMI_Resume
+
+
+ ;
+ ; Invoke the handler for each pending SMI source
+ ;
+ mov [SMI_Sources], ebx
+RunHandlers:
+ lea di, Handler_Table - sizeof (SMI_ENTRY)
+NextHandler:
+ add di, sizeof (SMI_ENTRY) ; Advance ptr to next handler entry
+
+ mov eax, (SMI_ENTRY PTR [di]).SMI_Mask
+ and eax, [SMI_Sources] ; Sources = TopLevelSources & Handler_Table.SMI_Mask
+ jz NextHandler
+
+ push eax ; call Handler_Table.Handler(Sources)
+ call (SMI_ENTRY PTR [di]).Handler
+ pop eax
+
+ not eax ; TopLevelSources &= ~Sources;
+ and [SMI_Sources], eax
+ jnz NextHandler ; if (!TopLevelSources) break;
+
+
+
+
+ ;
+ ; Dispatch to the VSM on top of the scheduler's stack
+ ;
+Dispatcher:
+ mov si, [SchedulerStack] ; Get scheduler's ptr
+ mov ebx, [si] ; Pop next VSM
+ sub si, 4
+
+ test ebx, 0FFFF0000h ; Is it a VSM ?
+ jnz RunTask
+ test bx, bx ; Callback routine ?
+ je Main_SMI_Loop
+ mov [SchedulerStack], si ; Yes, update scheduler ptr
+ call bx ; Go to callback routine
+ jmp Dispatcher
+
+
+RunTask:
+ mov [SchedulerStack], si ; Save scheduler's ptr
+ mov [Current_VSM], ebx ; Save ptr to the current VSM
+ExecuteTask:
+ ;
+ ; Point SMHR to the VSM's SMM header.
+ ;
+ lea eax, (VSM_Header PTR [ebx+sizeof(SmiHeader)]).SysStuff.State
+ mov ecx, MSR_SMM_HDR
+ wrmsr
+ ;
+ ; Restore the VSM's state
+ ;
+ rsdc ds, fs:(VSM_Header PTR [ebx])._DS
+
+ xor edi, edi
+ ASSUME di:PTR VSM_Header
+ rsdc gs, [di]._DS
+ rsdc ss, [di]._SS ; Restore VSM's SS:SP
+ lea bx, [di].SysStuff
+ ASSUME bx:PTR System
+ mov sp, word ptr [bx].SavedESP
+
+
+ ;
+ ; Update statistics
+ ;
+ rdtsc ; Record start time of the VSM
+ mov [bx+0].StartTime, eax
+ add [bx+0].NumSMIs, 1 ; Increment SMI count
+ adc [bx+4].NumSMIs, edi
+
+ ;
+ ; Mark VSM active unless it is sleeping
+ ;
+ mov al, RUN_FLAG_ACTIVE
+SetRunFlag:
+ xchg [bx].RunFlag, al
+ cmp al, RUN_FLAG_SLEEPING
+ je SetRunFlag
+
+ RESTORE_STATE ; No, restore registers
+
+ rsm ; Resume to the VSM
+
+
+ ASSUME DI: NOTHING
+ ASSUME BX: NOTHING
+
+
+
+
+
+
+;***********************************************************************
+; Restore state & resume to non-SMM code *
+;***********************************************************************
+ align 16
+SMI_Resume:
+
+
+ ; Generate internal IRQ(s)
+ xor ecx, ecx
+ xchg ecx, [IRQ_Mask]
+ jecxz NoIRQ
+ call Generate_IRQ
+NoIRQ:
+
+
+ call VSA_Exit ; Perform VSA exit
+ jc Main_SMI_Loop
+
+
+
+
+
+
+ ; Increment count of SMIs
+ mov si, OFFSET VSM_Header.SysStuff
+ ASSUME SI: PTR System
+ xor ecx, ecx
+ add [si+0].NumSMIs, 1
+ adc [si+4].NumSMIs, ecx
+
+ ; Compute total clocks for this SMI
+ rdtsc
+ sub eax, [si+0].StartTime
+ ; Accumulate total clocks spent executing VSA code
+ add [si+0].Clocks, eax
+ adc [si+4].Clocks, ecx
+
+ ASSUME SI:NOTHING
+
+
+
+
+if BRACKETS
+ cmp [BracketFlag], 0
+ je @f
+ mov dx, DBG_PORT
+ mov al, ']'
+ out dx, al
+@@:
+endif
+
+
+
+;***********************************************************************
+; Restore the state of the interrupted task *
+;***********************************************************************
+ RESTORE_STATE ; Restore GP registers & PCI addr
+
+ mov esp, [Saved_ESP] ; Restore ESP
+ rsdc ss, [Saved_SS] ; Restore descriptors
+ rsdc es, [Saved_ES]
+ rsdc fs, [Saved_FS]
+ rsdc gs, [Saved_GS]
+ rsdc ds, [Saved_DS] ; Must be restored last
+ rsm ; Resume to non-SMM thread
+
+
+
+
+
+
+;***********************************************************************
+; An SMI has occurred that is not a system call: *
+; *
+; If synchronous SMI: *
+; - Save the state of the interrupted VSM *
+; - Reschedule the interrupted VSM *
+; - Execute SMI handlers *
+; If asynchronous SMI: *
+; - If event is not high priority or VSM is marked no-preempt, *
+; return to interrupted VSM immediately. *
+; - Otherwise, execute SMI handlers *
+;***********************************************************************
+ align 16
+NotSysCall:
+
+ ;
+ ; Save VSM's state and set up SysMgr stack
+ ;
+ SAVE_STATE ; Save the VSM's state
+ mov word ptr gs:(VSM_Header).SysStuff.SavedESP, sp
+
+ rsdc ss, [Stack_Descriptor] ; Setup System Manager's stack
+ lea sp, [StartSaveArea]
+
+
+ call Get_SMI_Sources ; Get source(s) of nested SMIs
+
+ mov [SMI_Sources], ebx ; Record the pending SMI sources
+ test ebx, [SynchEvents] ; Is nested SMI a syncronous event ?
+ jz short AsyncSMI
+
+ ;
+ ; The SMI is synchronous (I/O or virtualized PCI trap)
+ ;
+ and ebx, [SynchEvents] ; Record the nested SMI source
+ or [Nested_Flag], ebx
+
+ ; It's a trapped or virtualized PCI.
+ ; Record some info about the event.
+ svdc [Nested_ES], gs ; Save GS descriptor
+ mov esi, gs:(VSM_Header).SysStuff.SavedESP
+ mov eax, gs:[si+0] ; Get VSM's PCI address
+ mov edi, gs:[si+4] ; Get VSM's EDI
+ mov [Nested_PCI], eax ; Required by PCI_Handler
+ mov [Nested_EDI], edi ; Required if INS
+ add esi, VSM_STACK_FRAME - 4
+ add esi, [Current_VSM] ; Ptr to EAX on VSM's stack
+ mov [Nested_EAX], esi
+
+ServiceNow:
+
+ mov gs:(VSM_Header).SysStuff.RunFlag, RUN_FLAG_READY
+Reschedule:
+ add [SchedulerStack], 4 ; Re-schedule the interrupted VSM
+
+ mov ebp, [SMI_Sources] ; Needed by RunHandlers
+
+ ; Update the clock count used by the VSM
+ rdtsc
+ sub eax, gs:(VSM_Header).SysStuff.StartTime
+ xor edx, edx
+ add gs:(VSM_Header).SysStuff.Clocks+0, eax
+ adc gs:(VSM_Header).SysStuff.Clocks+4, edx
+
+ jmp RunHandlers
+
+
+ ;
+ ; The SMI is asynchronous
+ ;
+AsyncSMI:
+ or ebx, ebx ; If null SMI, just return to VSM
+ jz short NoPreempt
+
+ cmp gs:(VSM_Header).SysStuff.RunFlag, RUN_FLAG_SLEEPING
+ je Reschedule
+
+ jmp ServiceNow
+
+ ; Is this a high priority SMI ?
+; test ebx, [HiPrioritySMIs]
+; jnz short ServiceNow ; Yes, execute SMI handlers
+
+
+ ;
+ ; Resumes to a VSM from an low-priority asynchronous SMI
+ ;
+NoPreempt:
+ ;
+ ; Resumes to a VSM from a system call
+ ;
+ExitSysCall: ; Return to caller
+ rsdc ss, gs:(VSM_Header)._SS
+ mov sp, word ptr gs:(VSM_Header).SysStuff.SavedESP
+ rsdc ds, gs:(VSM_Header)._DS
+ RESTORE_STATE
+ rsm
+
+
+
+
+
+
+
+;***********************************************************************
+; The current VSM has emptied its message queue. It will not be *
+; executed again until a new message is entered into its queue. *
+; NOTE: SysMgr will be using the last VSM's stack. *
+;***********************************************************************
+EmptyMsgQueue:
+
+
+ mov gs:(VSM_Header).SysStuff.RunFlag, RUN_FLAG_INACTIVE
+ jmp short UpdateClocks
+
+Sys_Exit:
+ ; System calls should not count as an SMI
+ sub gs:(VSM_Header).SysStuff.NumSMIs+0, 1 ; Decrement number of SMIs
+ sbb gs:(VSM_Header).SysStuff.NumSMIs+4, 0
+UpdateClocks:
+
+
+ ; Update the clock count used by the VSM
+ rdtsc
+ sub eax, gs:(VSM_Header).SysStuff.StartTime
+ xor edx, edx
+ add gs:(VSM_Header).SysStuff.Clocks+0, eax
+ adc gs:(VSM_Header).SysStuff.Clocks+4, edx
+
+ jmp Dispatcher
+
+
+
+;***********************************************************************
+; Schedules a VSM to execute
+;***********************************************************************
+Schedule_VSM proc pascal uses bx \
+ Vsm: DWORD
+
+ mov eax, [Vsm]
+ test eax, 0FFFF0000h ; Is it a callback ?
+ jz Schedule
+
+ ; Mark VSM ready, if not already on scheduler's stack
+ mov bl, RUN_FLAG_READY
+ xchg bl, fs:(VSM_Header PTR [eax]).SysStuff.RunFlag
+; cmp bl, RUN_FLAG_READY
+; je short Exit
+
+Schedule:
+ mov bx, [SchedulerStack] ; Get scheduler's ptr
+ add bx, 4 ; Push the VSM
+ mov [bx], eax
+ mov [SchedulerStack], bx ; Update scheduler's ptr
+Exit: ret
+
+Schedule_VSM endp
+
+
+
+
+
+
+;***********************************************************************
+;***********************************************************************
+;***********************************************************************
+;* *
+;* Nested SMI Entry Point *
+;* *
+;* A nested SMI can occur for one of four reasons: *
+;* 1) A system call *
+;* 2) An asynchronous event (timer, GPIO, etc.) *
+;* 3) A trapped I/O from a VSM (virtual register, PCI access) *
+;* 4) Return from a BIOS callback *
+;* *
+;***********************************************************************
+;***********************************************************************
+;***********************************************************************
+ align 16
+Nested_SMI:
+
+ ; Set DS descriptor to System Manager's
+ rsdc ds, cs:[Data_Descriptor]
+
+
+ ; Is it a system call (SMINT) ?
+ test byte ptr gs:(VSM_Header).SysStuff.State.SMI_Flags, 1000b
+ jz NotSysCall
+
+;*************************************************************************
+;*************************************************************************
+;*************************************************************************
+; *
+; SMI is a system call *
+; *
+; The VSM's registers are saved on the VSM's stack. *
+; DS: and SS:SP are initialized to SysMgr's environment. *
+; *
+; On Entry: *
+; AX = System call code *
+; Other registers, depending on the system call *
+; *
+;*************************************************************************
+;*************************************************************************
+;*************************************************************************
+SystemCall:
+ cmp ax, SYS_CODE_EXIT ; Check for valid system code
+ ja short IllegalSysCall ; If invalid, record an error
+
+
+ mov [VSMs_EAX], eax
+ SAVE_STATE ; Save the VSM's state
+ mov word ptr gs:(VSM_Header).SysStuff.SavedESP, sp
+
+ ; Setup System Manager's stack
+ rsdc ss, [Stack_Descriptor]
+ lea sp, [StartSaveArea]
+
+ ; Dispatch to system call routine
+ movzx eax, word ptr [VSMs_EAX]
+ jmp [SysCall_Table + eax*2]
+
+
+
+
+;***********************************************************************
+; An illegal system call was detected
+;***********************************************************************
+IllegalSysCall:
+ ; Is it ResumeFromRAM ?
+ cmp ax, SYS_RESUME_FROM_RAM
+ je ResumeFromRAM
+
+ mov di, ERR_UNDEF_SYS_CALL
+ mov ebx, eax ; Info1 = system call code
+ mov ecx, [Current_VSM] ; Info2 = offending VSM
+ mov ax, SYS_CODE_ERROR ; Fake a SYS_CODE_ERROR
+ jmp SystemCall
+
+
+
+;***********************************************************************
+ ; BIOS is resuming after a Save-to-RAM:
+ ; 1) Re-init VSA state
+ ; 2) Re-schedule the suspended VSM
+ ; 3) Go to VSM dispatcher
+;***********************************************************************
+ResumeFromRAM:
+ rsdc fs, [Flat_Descriptor] ; Set FS to a 4 GB flat segment
+ rsdc es, [Flat_Descriptor] ; Set ES to a 4 GB flat segment
+
+ mov ebx, [Current_VSM]
+ mov ax, fs:(VSM_Header PTR [ebx]).SysStuff.ResumeVector
+ mov fs:(VSM_Header PTR [ebx]).SysStuff.State.Next_IP, ax
+ mov fs:(VSM_Header PTR [ebx]).SysStuff.RunFlag, RUN_FLAG_READY
+ jmp ExecuteTask
+
+
+
+
+
+
+
+
+
+ align 4
+Current_VSM dd 0
+HardwareInfo Hardware { }
+BracketFlag db 0
+
+
+
+
+
+;*************************************************************************************
+;
+; IMPLEMENTATION NOTES:
+;
+; - The scheduler's stack and System Manager's stack grow toward each other.
+;
+; - The variables at StartSaveArea are grouped together because they, along with
+; the SMM header, represent the entire state of the interrupted task. This is
+; important since this state must be saved & restored across a BIOS callback.
+;
+;*************************************************************************************
+ align 2
+SchedulerStack dw OFFSET Scheduled_VSMs
+
+ align 4
+Scheduled_VSMs dd 0 ; Marks bottom of scheduler's stack
+
+
+
+ ORG SYSMGRS_STACK
+StartSaveArea:
+Saved_PCI dd ?
+
+; NOTE: the following 8 variables must be in the correct order for PUSHAD/POPAD
+Saved_EDI dd ?
+Saved_ESI dd ?
+Saved_EBP dd ?
+ dd ? ; ESP (not used)
+Saved_EBX dd ?
+Saved_EDX dd ?
+Saved_ECX dd ?
+Saved_AX:
+Saved_EAX dd ?
+SysMgrStack: ; <==== System Manager's stack begins here
+
+Saved_ESP dd OFFSET SysMgrStack ; DO NOT MOVE !!!
+
+
+;
+; NOTE: The SET_REGISTER, GET_REGISTER, GET_DESCRIPTOR, & SET_DESCRIPTOR
+; macros assume these are in this exact location and order:
+Saved_SS Descriptor { }
+Saved_DS Descriptor { }
+Saved_ES Descriptor { }
+Saved_FS Descriptor { }
+Saved_GS Descriptor { }
+
+Header_Addr dd 0 ; Ptr to end of SMM header
+
+IDT_Selector dd 0 ; Saved IDT state
+IDT_Base dd 0
+IDT_Limit dd 0
+
+
+
+ dw 0 ; Pad
+EndSaveArea label byte
+;
+; This table contains System Manager structures accesses by INIT.EXE and INFO.EXE.
+; Must match the InfoStuff structure in VSA2.H
+;
+ ORG SPECIAL_LOC
+
+ dw OFFSET Events
+ dw OFFSET MSRs
+ dw OFFSET INT_Vectors
+ dw OFFSET HardwareInfo
+IRQ_Base dd 0 ; Memory-mapped location of Internal IRQs
+IRQ_Mask dd 0 ; Mask of IRQs to be generated
+; NOTE: The following fields are not referenced by VSMs.
+; They are in this structure so INIT.ASM can initialize them.
+SysMgr_VSM dd 0 ; Logical address of System Manager
+SMI_Base dd 0 ; Memory-mapped location of SMI sources
+ dw OFFSET Header_Addr ; Offset of SysMgr.SysStuff.State
+ dw OFFSET StartSaveArea ; Initial value of SysMgr.SysStuff.SavedESP
+ dw OFFSET MSRs
+ dw OFFSET NumDescriptors
+
+Nested_EAX dd 0 ; Flat ptr to interrupted VSM's EAX
+Nested_EDI dd 0 ; Value of interrupted VSM's EDI
+Nested_PCI dd 0 ; PCI config address of interrupted VSM
+Nested_Flag dd 0
+
+VSMs_EAX dd 0
+Nested_ES Descriptor {}
+
+
+_CODE ENDS
+
+ END Start
+