; ; 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 several system calls ;******************************************************************************* include SYSMGR.INC include VSA2.INC include PCI.INC include SMIMAC.MAC include CHIPSET.INC include VR.INC .model tiny,c .586p .CODE public SysCall_Table public ReturnULONG externdef Sys_SW_INT: proc externdef Sys_Broadcast: proc externdef Sys_PassEvent: proc externdef Sys_State: proc externdef EmptyMsgQueue: proc externdef ExitSysCall: proc externdef Dispatcher: proc externdef Sys_Exit: proc externdef Record_VSM_Locations: proc externdef pascal Lookup_PCI: proc externdef pascal Lookup_IO: proc externdef pascal Find_MBus_ID: proc externdef pascal Send_Event: proc externdef pascal Schedule_VSM: proc externdef pascal Allocate_BAR: proc externdef pascal Register_Event: proc externdef pascal Report_VSM_Error: proc externdef pascal Allocate_Resource: proc externdef pascal Set_Address_Decode: proc externdef pascal Enable_PCI_Trapping: proc externdef pascal Unregister_VSM_Events: proc externdef pascal IRQY_Mapper: proc externdef pascal Return_Virtual_Value: proc externdef SysMgr_VSM: dword externdef VSM_ListHead: dword externdef Current_VSM: dword externdef MsgPacket: dword externdef SMI_Base: dword externdef IRQ_Base: dword externdef VSM_Ptrs: dword externdef Events: EVENT_ENTRY externdef HardwareInfo: Hardware align 2 SysCall_Table: dw OFFSET Sys_Register ; 00 - SYS_CODE_EVENT dw OFFSET Sys_Yield ; 01 - SYS_CODE_YIELD dw OFFSET Sys_SW_INT ; 02 - SYS_CODE_SW_INT dw OFFSET Sys_PassEvent ; 03 - SYS_CODE_PASS_EVENT dw OFFSET Sys_Unload ; 04 - SYS_CODE_UNLOAD dw OFFSET Sys_Registers ; 05 - SYS_CODE_REGISTER dw OFFSET Sys_RdWrPCI ; 06 - SYS_CODE_PCI_ACCESS dw OFFSET Sys_SetVirtual ; 07 - SYS_CODE_SET_VIRTUAL dw OFFSET Sys_GetVirtual ; 08 - SYS_CODE_GET_VIRTUAL dw OFFSET Sys_Broadcast ; 09 - SYS_CODE_BROADCAST dw OFFSET Sys_State ; 0A - SYS_CODE_STATE dw OFFSET Sys_Report_Error ; 0B - SYS_CODE_ERROR dw OFFSET Sys_Resource ; 0C - SYS_CODE_RESOURCE dw OFFSET Sys_Decode ; 0D - SYS_CODE_DECODE dw OFFSET Sys_GetDescr ; 0E - SYS_CODE_DESCRIPTOR dw OFFSET Sys_Lookup ; 0F - SYS_CODE_LOOKUP dw OFFSET Sys_IRQ_Mapper ; 10 - SYS_CODE_IRQ_MAPPER dw OFFSET Sys_Result ; 11 - SYS_CODE_RESULT dw OFFSET Sys_Duplicate ; 12 - SYS_CODE_DUPLICATE dw OFFSET EmptyMsgQueue ; 13 - SYS_CODE_EXIT ;************************************************************************ ; Implements the WRITE_PCI_NO_TRAP macros ; ; On Entry: ; SI = data size (bit 7 = 1 if I/O write); ; EBX = PCI configuration address ; ECX = data (if write) ;************************************************************************ Sys_RdWrPCI proc push ebx ; Save PCI address push ecx ; Save data ; Disable trapping of PCI address push bx ; PCI_Address push word ptr 0000 call Enable_PCI_Trapping movzx bp, al ; Save previous trap setting pop ecx ; Restore data pop ebx ; Restore PCI address ; Write the PCI address mov dx, PCI_CONFIG_ADDRESS mov eax, ebx out dx, eax add dl, 4 and al, 3 add dl, al btr si, 7 ; Read or write ? jc PCI_Write ; Jmp if write cmp si, BYTE_IO ; Byte, Word, or Dword ? je Read_Byte cmp si, WORD_IO je Read_Word Read_Dword: db 66h ; Force next instruction to be IN EAX,DX Read_Word: in ax, dx jmp short ReturnValue Read_Byte: in al, dx ReturnValue: push eax ; Save return value call Restore_Trapping ; Re-enable PCI trapping pop ax ; Restore return value pop dx ReturnULONG:: mov bx, word ptr gs:(VSM_Header).SysStuff.SavedESP mov word ptr gs:[bx+8*4], ax mov word ptr gs:[bx+6*4], dx jmp ExitSysCall ;************************************************************************ PCI_Write: mov eax, ecx ; Get data to be written cmp si, WORD_IO ; Byte, Word, or Dword ? je short Write_Word cmp si, DWORD_IO je short Write_Dword cmp si, BYTE_IO jne short Ignore ; Ignore if error in parameter Write_Byte: out dx, al jmp short Restore_PCI_Trap Write_Dword: db 66h ; Force next instruction to be OUT DX,EAX Write_Word: out dx, ax Restore_PCI_Trap: call Restore_Trapping ; Re-enable PCI trapping Ignore: jmp ExitSysCall Sys_RdWrPCI endp ;*********************************************************************** ; Restores PCI trapping ; On entry: ; BP = 1 means re-enable PCI trapping ;*********************************************************************** Restore_Trapping proc ; Is trapping to be re-enabled ? cmp bp, 1 jne short Exit ; Yes, restore PCI trapping on this address ; Enable_PCI_Trapping(PCI_Address, EnableFlag); push bx ; PCI address push bp ; EnableFlag call Enable_PCI_Trapping Exit: ret Restore_Trapping endp ;*********************************************************************** ; ; Register an event to the calling VSM ; ; On entry: ; EBX = Event::Priority ; ECX = Parameter 1 ; EDI = Parameter 2 ;*********************************************************************** Sys_Register proc ; Register_Event(Event, Priority, VSM, Param1, Param2); push ebx ; Event::Priority push [Current_VSM] ; VSM ptr push ecx ; Param1 push edi ; Param2 call Register_Event jmp ExitSysCall Sys_Register endp ;*********************************************************************** ; Input: ; BX = Virtual register index ; Output: ; AX = returned data ;*********************************************************************** Sys_GetVirtual proc xor cx, cx ; Data = 0000 xor di, di ; 0 = read jmp VirtualCommon Sys_GetVirtual endp ;*********************************************************************** ; Input: ; BX = Virtual register index ; CX = Data ;*********************************************************************** Sys_SetVirtual proc call Handle_PM mov di, 1 ; 1 = write VirtualCommon:: cmp bh, VRC_KEYBOARD ; Allow VRC_KEYBOARD to pass 32-bits je Reschedule movzx ecx, cx Reschedule: mov edx, [Current_VSM] ; Re-schedule calling VSM push edx call Schedule_VSM call VirtualRegisterEvent mov ax, 0FFFFh ; Value of an undefined virtual register mov bx, word ptr gs:(VSM_Header).SysStuff.SavedESP mov word ptr gs:[bx+8*4], ax jmp Dispatcher Sys_SetVirtual endp Handle_PM proc if 0;SUPPORT_PM ; requires 78 bytes ; If OHCI VSM is sending a USB event to KBD VSM, send an EVENT_IO_TRAP ; to the PM VSM so system will exit DOZE mode. cmp bh, VRC_KEYBOARD jne short Exit mov eax, [VSM_Ptrs+4*VSM_PM]; Is PM installed ? or eax, eax jz short Exit ; Is PM VSM registered for the I/O trap ? mov al, EVENT_IO_TRAP FindPM: mov ah, sizeof(EVENT_ENTRY) mul ah mov si, ax mov eax, (EVENT_ENTRY PTR [Events+si]).Vsm or eax, eax jz short Exit cmp eax, edi ; Is it the PM VSM ? jne short Next_VSM cmp (EVENT_ENTRY PTR [Events+si]).Param1, 0060h je short PM_Is_Dozing Next_VSM: mov al, (EVENT_ENTRY PTR [Events+si]).Link or al, al jnz FindPM jmp short Exit PM_Is_Dozing: push bx ; Yes, save virtual register info push cx mov eax, MSG_EVENT ; Send the PM VSM an EVENT_IO_TRAP[0x60] message mov ebx, [SysMgr_VSM] lea si, [PM_Packet] call Insert_Msg pop cx ; Restore virtual register info pop bx endif Exit: ret PM_Packet dd EVENT_IO_TRAP, 0, 0060h Handle_PM endp ;*********************************************************************** ; Sends an EVENT_VIRTUAL_REGISTER to VSM(s) ; On entry: ; BX = Class::Index ; CX = write data ; DI = 0 (read) or 1 (write) ; EDX = From_VSM ;*********************************************************************** VirtualRegisterEvent proc lea si, [MsgPacket] ; Fill the message packet movzx eax, bx mov [si+1*4], eax ; MsgPacket[1] : virtual register index mov ax, di mov [si+2*4], eax ; MsgPacket[2] : 0=read 1=write mov [si+3*4], ecx ; MsgPacket[3] : write data mov ax, EVENT_VIRTUAL_REGISTER ; No, so it's a VR access push ax ; Event push edx ; From_VSM call Send_Event ret VirtualRegisterEvent endp ;*********************************************************************** ; Implements the SYS_UNLOAD_VSM macro ;*********************************************************************** Sys_Unload proc ; Find prior VSM to current VSM mov eax, [Current_VSM] or eax, eax jz short Exit ; Remove current VSM from linked list mov ebx, (VSM_Header PTR fs:[eax]).SysStuff.Blink mov ecx, (VSM_Header PTR fs:[eax]).SysStuff.Flink or ebx, ebx ; Is there a previous VSM ? jnz short IsBackLink mov [VSM_ListHead], ecx ; No, update VSM_ListHead with VSM at Flink jmp short FixupBlink IsBackLink: mov (VSM_Header PTR fs:[ebx]).SysStuff.Flink, ecx FixupBlink: or ecx, ecx jz short Unregister mov (VSM_Header PTR fs:[ecx]).SysStuff.Blink, ebx ; Unregister events registered to this VSM Unregister: push eax call Unregister_VSM_Events call Record_VSM_Locations Exit: jmp Sys_Exit ; Exit to SysMgr Sys_Unload endp ;*********************************************************************** ; Implements the SYS_ALLOCATE_RESOURCE macro ; Input: ; BL - Resource type ; Other registers - various parameters ;*********************************************************************** Sys_Resource proc ; Only BAR types are implemented at this time cmp bl, RESOURCE_MEMORY je short BAR_Resource cmp bl, RESOURCE_MMIO je short BAR_Resource cmp bl, RESOURCE_IO je short BAR_Resource cmp bl, RESOURCE_SCIO je short BAR_Resource ; Not a BAR resource push bx ; Resource push ecx ; Param call Allocate_Resource jmp ExitSysCall BAR_Resource: push bx ; BAR type push si ; BAR offset push ecx ; Range ror edi, 16 push di ; MBus_ID ror edi, 16 push di ; PCI Device_ID call Allocate_BAR jmp ReturnULONG Sys_Resource endp ;*********************************************************************** ; Implements the SYS_REPORT_ERROR macro ; DI = Error code ; EBX = Info1 ; ECX = Info2 ;*********************************************************************** Sys_Report_Error proc push di push ebx push ecx call Report_VSM_Error jmp ExitSysCall Sys_Report_Error endp YIELD_HANDLE equ (ONE_SHOT OR SYS_YIELD OR 0000BEEFh) ;*********************************************************************** ; Implements the SYS_YIELD macro ; ; Input: ; ECX = milliseconds to suspend the VSM ;*********************************************************************** Sys_Yield proc mov eax, [Current_VSM] ; VSM that is yielding control mov fs:(VSM_Header PTR [eax]).SysStuff.RunFlag, RUN_FLAG_WAITING push word ptr EVENT_TIMER ; Event push word ptr 0000 ; Priority push eax ; Vsm push ecx ; Param1 (ms) push dword ptr YIELD_HANDLE ; Param2 (handle) call Register_Event jmp Sys_Exit ; Exit to SysMgr. Don't return to VSM Sys_Yield endp ;*********************************************************************** ; This system call is obsolete ; Input: ; BH = 0 for Set, 1 for Get ; BL = register definition ; ECX = data if Set ;*********************************************************************** Sys_Registers proc jmp ExitSysCall Sys_Registers endp ;*********************************************************************** ; Implements the SYS_MAP_IRQ macro ; Maps IRQ source to specified IRQ ; Input: ; BL = Unrestricted Y source (0x00-0x0F) ; CL = IRQ setting ;*********************************************************************** Sys_IRQ_Mapper proc push bx push cx call IRQY_Mapper jmp ExitSysCall Sys_IRQ_Mapper endp ;*********************************************************************** ; Input: ; BX = Address ; CX = Decode flag ;*********************************************************************** Sys_Decode proc push bx ; Address push cx ; Decode (POSITIVE_DECODE or SUBTRACTIVE_DECODE) call Set_Address_Decode jmp ExitSysCall Sys_Decode endp ;*********************************************************************** ; Implements the SYS_MBUS_DESCRIPTOR & SYS_IO_DESCRIPTOR macros ; ; On entry: ; BX = Address ; CX = 0 if PCI else I/O ; Returns: ; MSR address of corresponding resource ;*********************************************************************** Sys_GetDescr proc jcxz PCI ; MSR_Address = Lookup_IO(Address); push bx call Lookup_IO mov bl, 2 ; Restore IO_Flag jmp Common ; MSR_Address = Lookup_PCI(Address); PCI: push bx call Lookup_PCI xor bx, bx Common: mov cx, dx ; Was resource found ? shl ecx, 16 mov cx, ax xor eax, eax ; EDX:EAX = 00000000:00000000 xor edx, edx jecxz ReturnMSRInfo rdmsr ; Yes, read MSR test bl, 2 ; Set MSR to default ? jz ReturnMSRInfo push edx ; Yes, save current value push eax test eax, 000F0000h ; IOD_BM or IOD_SC ? mov eax, 00000000h ; Default for IOD_SC mov edx, eax jz SetDefault mov eax, 0FFF00000h ; Default for IOD_BM mov edx, 0000000FFh SetDefault: wrmsr ; Set MSR to default value pop eax ; Restore original MSR value pop edx ; Return MSR address in ECX and MSR value in EDX:EAX ReturnMSRInfo: mov bx, word ptr gs:(VSM_Header).SysStuff.SavedESP mov gs:[bx+7*4], ecx ; Return MSR address in ECX mov gs:[bx+8*4], eax ; Return MSR value in EDX:EAX mov gs:[bx+6*4], edx jmp ExitSysCall Sys_GetDescr endp ;*********************************************************************** ; Implements the SYS_LOOKUP_DEVICE macro ; ; On entry: ; BX = MBus Device_ID ; CX = Instance ; Returns: ; DX:AX = MSR routing address to MBus device ;*********************************************************************** Sys_Lookup proc ; Find_MBus_ID(USHORT MBus_ID, UCHAR Instance); push bx push cx call Find_MBus_ID xor ax, ax jmp ReturnULONG Sys_Lookup endp ;*********************************************************************** ; Implements the SYS_RETURN_RESULT macro ; Returns a byte/word/dword result to the correct context. ; Input: ; EBX = Result to be returned ;*********************************************************************** Sys_Result proc push OFFSET VSM_Header.SysStuff.State push ebx ; Value call Return_Virtual_Value jmp ExitSysCall Sys_Result endp ;*********************************************************************** ; Implements the SYS_DUPLICATE_VSM macro ; On entry: BX = memory model ; Legend: (C=copy of parent VSM) (N=new copy) ; CS DS SS ; 0: N N N ; 1: C N N ;*********************************************************************** Sys_Duplicate proc ; mov [MemoryModel], bx ; Ignore parameter for new ; Find end of VSMs in memory mov esi, [Current_VSM] mov ebx, esi FindLastVSM: mov edi, ebx mov ebx, (VSM_Header PTR fs:[ebx]).SysStuff.Flink or ebx, ebx jnz FindLastVSM ; EDI points to last VSM in memory. Find end of last VSM. mov edx, edi add edi, (VSM_Header PTR fs:[edi]).DS_Limit ; Copy this VSM's image mov ecx, (VSM_Header PTR fs:[esi]).DS_Limit cmp [MemoryModel], 0 ; Use same Code segment ? je short CopyImage mov ecx, sizeof(VSM_Header) + VSM_STACK_SIZE CopyImage: push edi push esi push ecx shr ecx, 2 ; Convert BYTE count to DWORDs rep movsd [edi], es:[esi] pop ecx pop esi pop edi ; Patch descriptors mov (VSM_Header PTR fs:[edi])._DS.base_15_0, di mov (VSM_Header PTR fs:[edi])._SS.base_15_0, di mov eax, edi shr eax, 16 mov (VSM_Header PTR fs:[edi])._DS.base_31_24, ah mov (VSM_Header PTR fs:[edi])._DS.base_23_16, al mov (VSM_Header PTR fs:[edi])._SS.base_31_24, ah mov (VSM_Header PTR fs:[edi])._SS.base_23_16, al mov (VSM_Header PTR fs:[edi])._DS.limit_15_0, cx mov (VSM_Header PTR fs:[edi])._SS.limit_15_0, cx ; Required for segments > 64K ; shr ecx, 16 ; mov (VSM_Header PTR fs:[edi])._DS.limit_19_16, cl ; mov (VSM_Header PTR fs:[edi])._SS.limit_19_16, cl cmp [MemoryModel], 0 ; Use same Code segment ? jne short LinkNewVSM mov (VSM_Header PTR fs:[edi]).SysStuff.State._CS.base, edi LinkNewVSM: ; Link the new VSM into the VSM list mov (VSM_Header PTR fs:[edx]).SysStuff.Flink, edi mov (VSM_Header PTR fs:[edi]).SysStuff.Blink, edx mov (VSM_Header PTR fs:[edi]).SysStuff.Flink, 0 ; Init EIP movzx eax, (VSM_Header PTR fs:[edi]).EntryPoint mov (VSM_Header PTR fs:[edi]).SysStuff.State.Next_EIP, eax ; Init ESP & create the initial stack frame mov eax, (VSM_Header PTR fs:[edi]).DS_Limit sub ax, VSM_STACK_FRAME mov (VSM_Header PTR fs:[edi]).SysStuff.SavedESP, eax ; Schedule the new VSM push edi call Schedule_VSM jmp ExitSysCall ret ; Gets rid of assembler warning ; Warning: don't make MemoryModel a variable on the stack ; The JMP ExitSysCall bypasses the LEAVE instruction and BP is trashed MemoryModel dw 0 Sys_Duplicate endp ;*********************************************************************** ; Returns TRUE if the VSM is currently yielded ;*********************************************************************** VSM_Is_Yielded proc Vsm: dword mov ebx, [Vsm] mov al, 0 ; return FALSE cmp fs:(VSM_Header PTR [ebx]).SysStuff.RunFlag, RUN_FLAG_WAITING jne short Exit mov al, 1 ; return TRUE Exit: ret VSM_Is_Yielded endp END