| ;; ----------------------------------------------------------------------- |
| ;; |
| ;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved |
| ;; Copyright 2009 Intel Corporation; author: H. Peter Anvin |
| ;; |
| ;; This program is free software; you can redistribute it and/or modify |
| ;; it under the terms of the GNU General Public License as published by |
| ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330, |
| ;; Boston MA 02111-1307, USA; either version 2 of the License, or |
| ;; (at your option) any later version; incorporated herein by reference. |
| ;; |
| ;; ----------------------------------------------------------------------- |
| |
| ;; |
| ;; callback.inc |
| ;; |
| ;; Callbacks from 32-bit mode to 16-bit mode |
| ;; |
| |
| ; |
| ; 16-bit intcall/farcall handling code |
| ; |
| |
| ; |
| ; 32-bit support code |
| ; |
| bits 32 |
| section .text |
| |
| ; |
| ; Intcall/farcall invocation. We manifest a structure on the real-mode stack, |
| ; containing the com32sys_t structure from <com32.h> as well as |
| ; the following entries (from low to high address): |
| ; - Target offset |
| ; - Target segment |
| ; - Return offset |
| ; - Return segment (== real mode cs == 0) |
| ; - Return flags |
| ; |
| global core_farcall:function hidden |
| core_farcall: |
| mov eax,[esp+1*4] ; CS:IP |
| jmp core_syscall |
| |
| global core_intcall:function hidden |
| core_intcall: |
| movzx eax,byte [esp+1*4] ; INT number |
| mov eax,[eax*4] ; Get CS:IP from low memory |
| |
| core_syscall: |
| pushfd ; Save IF among other things... |
| inc dword [CallbackCtr] |
| push ebx |
| push ebp |
| push esi |
| push edi |
| push dword [CallbackSP] |
| |
| cld |
| |
| movzx edi,word [word RealModeSSSP] |
| movzx ebx,word [word RealModeSSSP+2] |
| sub edi,54 ; Allocate 54 bytes |
| mov [word RealModeSSSP],di |
| shl ebx,4 |
| add edi,ebx ; Create linear address |
| |
| mov esi,[esp+8*4] ; Source regs |
| xor ecx,ecx |
| mov cl,11 ; 44 bytes to copy |
| rep movsd |
| |
| ; EAX is already set up to be CS:IP |
| stosd ; Save in stack frame |
| mov eax,.rm_return ; Return seg:offs |
| stosd ; Save in stack frame |
| mov eax,[edi-12] ; Return flags |
| and eax,0x200ed7 ; Mask (potentially) unsafe flags |
| mov [edi-12],eax ; Primary flags entry |
| stosw ; Return flags |
| |
| mov bx,.rm |
| jmp enter_rm ; Go to real mode |
| |
| bits 16 |
| section .text16 |
| .rm: |
| mov ax,sp |
| add ax,9*4+4*2 |
| mov [CallbackSP],ax |
| pop gs |
| pop fs |
| pop es |
| pop ds |
| popad |
| popfd |
| retf ; Invoke routine |
| |
| .rm_return: |
| ; We clean up SP here because we don't know if the |
| ; routine returned with RET, RETF or IRET |
| mov sp,[cs:CallbackSP] |
| pushfd |
| pushad |
| push ds |
| push es |
| push fs |
| push gs |
| mov ebx,.pm_return |
| jmp enter_pm |
| |
| ; On return, the 44-byte return structure is on the |
| ; real-mode stack, plus the 10 additional bytes used |
| ; by the target address (see above.) |
| bits 32 |
| section .text |
| .pm_return: |
| movzx esi,word [word RealModeSSSP] |
| movzx eax,word [word RealModeSSSP+2] |
| mov edi,[esp+9*4] ; Dest regs |
| shl eax,4 |
| add esi,eax ; Create linear address |
| and edi,edi ; NULL pointer? |
| jnz .do_copy |
| .no_copy: mov edi,esi ; Do a dummy copy-to-self |
| .do_copy: xor ecx,ecx |
| mov cl,11 ; 44 bytes |
| rep movsd ; Copy register block |
| |
| add dword [word RealModeSSSP],54 |
| ; Remove from stack |
| |
| pop dword [CallbackSP] |
| dec dword [CallbackCtr] |
| jnz .skip |
| call [core_pm_hook] |
| .skip: |
| pop edi |
| pop esi |
| pop ebp |
| pop ebx |
| popfd |
| ret ; Return to 32-bit program |
| |
| ; |
| ; Cfarcall invocation. We copy the stack frame to the real-mode stack, |
| ; followed by the return CS:IP and the CS:IP of the target function. |
| ; The value of IF is copied from the calling routine. |
| ; |
| global core_cfarcall:function hidden |
| core_cfarcall: |
| pushfd ; Save IF among other things... |
| inc dword [CallbackCtr] |
| push ebx |
| push ebp |
| push esi |
| push edi |
| push dword [CallbackSP] |
| |
| cld |
| mov ecx,[esp+9*4] ; Size of stack frame |
| |
| movzx edi,word [word RealModeSSSP] |
| movzx ebx,word [word RealModeSSSP+2] |
| mov [word CallbackSP],di |
| sub edi,ecx ; Allocate space for stack frame |
| and edi,~3 ; Round |
| sub edi,4*3 ; Return pointer, return value, EFLAGS |
| mov [word RealModeSSSP],di |
| shl ebx,4 |
| add edi,ebx ; Create linear address |
| |
| mov eax,[esp+5*4] ; EFLAGS from entry |
| and eax,0x202 ; IF only |
| stosd |
| mov eax,[esp+7*4] ; CS:IP |
| stosd ; Save to stack frame |
| mov eax,.rm_return ; Return seg:off |
| stosd |
| mov esi,[esp+8*4] ; Stack frame |
| mov eax,ecx ; Copy the stack frame |
| shr ecx,2 |
| rep movsd |
| mov ecx,eax |
| and ecx,3 |
| rep movsb |
| |
| mov bx,.rm |
| jmp enter_rm |
| |
| bits 16 |
| section .text16 |
| .rm: |
| popfd |
| retf |
| .rm_return: |
| mov sp,[cs:CallbackSP] |
| mov esi,eax |
| mov ebx,.pm_return |
| jmp enter_pm |
| |
| bits 32 |
| section .text |
| .pm_return: |
| mov eax,esi |
| ; EDX already set up to be the RM return value |
| pop dword [CallbackSP] |
| dec dword [CallbackCtr] |
| jnz .skip |
| call [core_pm_hook] |
| .skip: |
| pop ebx |
| pop ebp |
| pop esi |
| pop edi |
| popfd |
| ret |
| |
| section .bss16 |
| alignb 4 |
| global core_pm_hook |
| CallbackSP resd 1 ; SP saved during callback |
| CallbackCtr resd 1 |
| |
| bits 16 |
| section .text16 |