Commit 9cf066e3 authored by Ulrich Weigand's avatar Ulrich Weigand Committed by Alexandre Julliard

Implemented KERNEL.621 (CBClientThunkSLEx).

parent 40c11ebf
......@@ -490,7 +490,7 @@ file krnl386.exe
618 pascal16 GetDialog32Size(ptr) GetDialog32Size
619 pascal16 RegisterCBClient(word ptr long) RegisterCBClient
620 register CBClientThunkSL() CBClientThunkSL
621 stub KERNEL_621 # (cbclient)
621 register CBClientThunkSLEx() CBClientThunkSLEx
622 pascal16 UnRegisterCBClient(word ptr long) UnRegisterCBClient
623 pascal16 InitCBClient(long) InitCBClient
624 pascal SetFastQueue(long long) SetFastQueue
......
......@@ -30,10 +30,12 @@ BOOL32 RELAY_Init(void)
extern void CALLTO16_Ret_word(), CALLTO16_Ret_long();
extern void CALLTO16_Ret_eax();
extern void CALL32_CBClient_Ret();
extern void CALL32_CBClientEx_Ret();
extern DWORD CALLTO16_RetAddr_word;
extern DWORD CALLTO16_RetAddr_long;
extern DWORD CALLTO16_RetAddr_eax;
extern DWORD CALL32_CBClient_RetAddr;
extern DWORD CALL32_CBClientEx_RetAddr;
codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)CALLTO16_Start,
(int)CALLTO16_End - (int)CALLTO16_Start,
......@@ -50,6 +52,8 @@ BOOL32 RELAY_Init(void)
codesel );
CALL32_CBClient_RetAddr =
MAKELONG( (int)CALL32_CBClient_Ret -(int)CALLTO16_Start, codesel );
CALL32_CBClientEx_RetAddr =
MAKELONG( (int)CALL32_CBClientEx_Ret -(int)CALLTO16_Start, codesel );
/* Create built-in modules */
if (!BUILTIN_Init()) return FALSE;
......
......@@ -1535,3 +1535,32 @@ void WINAPI CBClientThunkSL( CONTEXT *context )
EAX_reg(context) = CALL32_CBClient( proc, args );
}
/***********************************************************************
* CBClientThunkSLEx (KERNEL.621)
*/
void WINAPI CBClientThunkSLEx( CONTEXT *context )
{
/* Call 32-bit relay code */
extern DWORD WINAPI CALL32_CBClientEx( FARPROC32 proc,
LPWORD args, INT32 *nArgs );
LPWORD args = PTR_SEG_OFF_TO_LIN( SS_reg( context ), BP_reg( context ) );
FARPROC32 proc = CBClientRelay32[ args[2] ][ args[1] ];
INT32 nArgs;
LPWORD stackLin;
EAX_reg(context) = CALL32_CBClientEx( proc, args, &nArgs );
/* Restore registers saved by CBClientGlueSL */
stackLin = (LPWORD)((LPBYTE)CURRENT_STACK16 + sizeof(STACK16FRAME) - 4);
BP_reg( context ) = stackLin[3];
SI_reg( context ) = stackLin[2];
DI_reg( context ) = stackLin[1];
DS_reg( context ) = stackLin[0];
SP_reg( context ) += 16+nArgs;
/* Return to caller of CBClient thunklet */
CS_reg ( context ) = stackLin[9];
EIP_reg( context ) = stackLin[8];
}
......@@ -2150,7 +2150,7 @@ static void BuildRet16Func( FILE *outfile )
* and perform a far return to 16-bit code.
*
* To trick the relay stub into returning to us, we push a 16-bit
* cs:ip pair pointing to out return entry point onto the 16-bit stack,
* cs:ip pair pointing to our return entry point onto the 16-bit stack,
* followed by a ss:sp pair pointing to *that* cs:ip pair.
* Our return stub thus called will then reload the 32-bit ss:esp and
* return to 32-bit code (by using and ss:esp value that we have also
......@@ -2165,22 +2165,60 @@ static void BuildRet16Func( FILE *outfile )
* (ebx+2) 16-bit ss (16-bit stack segment)
* (ebx+0) 16-bit sp (points to ebx+4)
*
* The second variant of this routine, CALL32_CBClientEx, which is used
* to implement KERNEL.621, has to cope with yet another problem: Here,
* the 32-bit side directly returns to the caller of the CBClient thunklet,
* restoring registers saved by CBClientGlueSL and cleaning up the stack.
* As we have to return to our 32-bit code first, we have to adapt the
* layout of our temporary area so as to include values for the registers
* that are to be restored, and later (in the implementation of KERNEL.621)
* we *really* restore them. The return stub restores DS, DI, SI, and BP
* from the stack, skips the next 8 bytes (CBClient relay code / target),
* and then performs a lret NN, where NN is the number of arguments to be
* removed. Thus, we prepare our temporary area as follows:
*
* (ebx+22) 16-bit cs (this segment)
* (ebx+20) 16-bit ip ('16-bit' return entry point)
* (ebx+16) 32-bit ss (flat)
* (ebx+12) 32-bit sp (32-bit stack pointer)
* (ebx+10) 16-bit bp (points to ebx+24)
* (ebx+8) 16-bit si (ignored)
* (ebx+6) 16-bit di (ignored)
* (ebx+4) 16-bit ds (we actually use the flat DS here)
* (ebx+2) 16-bit ss (16-bit stack segment)
* (ebx+0) 16-bit sp (points to ebx+4)
*
* Note that we ensure that DS is not changed and remains the flat segment,
* and the 32-bit stack pointer our own return stub needs fits just
* perfectly into the 8 bytes that are skipped by the Windows stub.
* One problem is that we have to determine the number of removed arguments,
* as these have to be really removed in KERNEL.621. Thus, the BP value
* that we place in the temporary area to be restored, contains the value
* that SP would have if no arguments were removed. By comparing the actual
* value of SP with this value in our return stub we can compute the number
* of removed arguments. This is then returned to KERNEL.621.
*
* The stack layout of this function:
* (ebp+16) nArgs pointer to variable receiving nr. of args (Ex only)
* (ebp+12) arg ebp value to be set for relay stub
* (ebp+8) func CBClient relay stub address
* (ebp+4) ret addr
* (ebp) ebp
*/
static void BuildCallTo32CBClient( FILE *outfile )
static void BuildCallTo32CBClient( FILE *outfile, BOOL32 isEx )
{
char *name = isEx? "CBClientEx" : "CBClient";
int size = isEx? 24 : 16;
/* Function header */
fprintf( outfile, "\n\t.align 4\n" );
#ifdef USE_STABS
fprintf( outfile, ".stabs \"CALL32_CBClient:F1\",36,0,0," PREFIX "CALL32_CBClient\n" );
fprintf( outfile, ".stabs \"CALL32_%s:F1\",36,0,0," PREFIX "CALL32_%s\n",
name, name );
#endif
fprintf( outfile, "\t.globl " PREFIX "CALL32_CBClient\n" );
fprintf( outfile, PREFIX "CALL32_CBClient:\n" );
fprintf( outfile, "\t.globl " PREFIX "CALL32_%s\n", name );
fprintf( outfile, PREFIX "CALL32_%s:\n", name );
/* Entry code */
......@@ -2206,29 +2244,50 @@ static void BuildCallTo32CBClient( FILE *outfile )
fprintf( outfile, "\tpushf\n" );
fprintf( outfile, "\tcld\n" );
fprintf( outfile, "\tleal -16(%%esi), %%edi\n" );
fprintf( outfile, "\tleal -%d(%%esi), %%edi\n", size );
fprintf( outfile, "\tmovl $%d, %%ecx\n", sizeof(STACK16FRAME) );
fprintf( outfile, "\trep\n\tmovsb\n" );
fprintf( outfile, "\tpopf\n" );
fprintf( outfile, "\t.byte 0x64\n\tsubw $16,(%d)\n", STACKOFFSET );
fprintf( outfile, "\t.byte 0x64\n\tsubw $%d,(%d)\n", size, STACKOFFSET );
fprintf( outfile, "\tpushl %%edi\n" ); /* remember address */
/* Set up temporary area */
fprintf( outfile, "\taddl $%d, %%ebx\n", sizeof(STACK16FRAME)-16+4 );
fprintf( outfile, "\taddl $%d, %%ebx\n", sizeof(STACK16FRAME)-size+4 );
fprintf( outfile, "\tmovl %%ebx, (%%edi)\n" );
fprintf( outfile, "\tmovl " PREFIX "CALL32_CBClient_RetAddr, %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 4(%%edi)\n" );
if ( !isEx )
{
fprintf( outfile, "\tmovl " PREFIX "CALL32_%s_RetAddr, %%eax\n", name );
fprintf( outfile, "\tmovl %%eax, 4(%%edi)\n" );
fprintf( outfile, "\tleal -8(%%esp), %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 8(%%edi)\n" );
fprintf( outfile, "\tmovl %%ss, %%ax\n" );
fprintf( outfile, "\tandl $0x0000ffff, %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 12(%%edi)\n" );
}
else
{
fprintf( outfile, "\tmovl %%ds, %%ax\n" );
fprintf( outfile, "\tmovw %%ax, 4(%%edi)\n" );
fprintf( outfile, "\tleal -8(%%esp), %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 8(%%edi)\n" );
fprintf( outfile, "\taddl $20, %%ebx\n" );
fprintf( outfile, "\tmovw %%bx, 10(%%edi)\n" );
fprintf( outfile, "\tmovl %%ss, %%ax\n" );
fprintf( outfile, "\tandl $0x0000ffff, %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 12(%%edi)\n" );
fprintf( outfile, "\tleal -8(%%esp), %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 12(%%edi)\n" );
fprintf( outfile, "\tmovl %%ss, %%ax\n" );
fprintf( outfile, "\tandl $0x0000ffff, %%eax\n" );
fprintf( outfile, "\tmovl %%eax, 16(%%edi)\n" );
fprintf( outfile, "\tmovl " PREFIX "CALL32_%s_RetAddr, %%eax\n", name );
fprintf( outfile, "\tmovl %%eax, 20(%%edi)\n" );
}
/* Setup registers and call CBClient relay stub (simulating a far call) */
......@@ -2246,12 +2305,19 @@ static void BuildCallTo32CBClient( FILE *outfile )
fprintf( outfile, "\tpushf\n" );
fprintf( outfile, "\tstd\n" );
fprintf( outfile, "\tdec %%esi\n" );
fprintf( outfile, "\tleal 16(%%esi), %%edi\n" );
fprintf( outfile, "\tleal %d(%%esi), %%edi\n", size );
fprintf( outfile, "\tmovl $%d, %%ecx\n", sizeof(STACK16FRAME) );
fprintf( outfile, "\trep\n\tmovsb\n" );
fprintf( outfile, "\tpopf\n" );
fprintf( outfile, "\t.byte 0x64\n\taddw $16,(%d)\n", STACKOFFSET );
fprintf( outfile, "\t.byte 0x64\n\taddw $%d,(%d)\n", size, STACKOFFSET );
/* Return argument size to caller */
if ( isEx )
{
fprintf( outfile, "\tmovl 28(%%esp), %%ebx\n" );
fprintf( outfile, "\tmovl %%ebp, (%%ebx)\n" );
}
/* Restore registers and return */
......@@ -2263,18 +2329,28 @@ static void BuildCallTo32CBClient( FILE *outfile )
/* '16-bit' return stub */
fprintf( outfile, "\t.globl " PREFIX "CALL32_CBClient_Ret\n" );
fprintf( outfile, PREFIX "CALL32_CBClient_Ret:\n" );
fprintf( outfile, "\t.globl " PREFIX "CALL32_%s_Ret\n", name );
fprintf( outfile, PREFIX "CALL32_%s_Ret:\n", name );
fprintf( outfile, "\tmovzwl %%sp, %%ebx\n" );
fprintf( outfile, "\tlssl %%ss:(%%ebx), %%esp\n" );
if ( !isEx )
{
fprintf( outfile, "\tmovzwl %%sp, %%ebx\n" );
fprintf( outfile, "\tlssl %%ss:(%%ebx), %%esp\n" );
}
else
{
fprintf( outfile, "\tmovzwl %%bp, %%ebx\n" );
fprintf( outfile, "\tsubw %%bp, %%sp\n" );
fprintf( outfile, "\tmovzwl %%sp, %%ebp\n" );
fprintf( outfile, "\tlssl %%ss:-12(%%ebx), %%esp\n" );
}
fprintf( outfile, "\tlret\n" );
/* Declare the return address variable */
fprintf( outfile, "\t.data\n" );
fprintf( outfile, "\t.globl " PREFIX "CALL32_CBClient_RetAddr\n" );
fprintf( outfile, PREFIX "CALL32_CBClient_RetAddr:\t.long 0\n" );
fprintf( outfile, "\t.globl " PREFIX "CALL32_%s_RetAddr\n", name );
fprintf( outfile, PREFIX "CALL32_%s_RetAddr:\t.long 0\n", name );
fprintf( outfile, "\t.text\n" );
}
......@@ -2618,12 +2694,13 @@ static int BuildCallTo16( FILE *outfile, char * outname, int argc, char *argv[]
BuildRet16Func( outfile );
/* Output the CBClient callback function
/* Output the CBClient callback functions
* (while this does not really 'call to 16-bit' code, it is placed
* here so that its 16-bit return stub is defined within the CALLTO16
* 16-bit segment)
*/
BuildCallTo32CBClient( outfile );
BuildCallTo32CBClient( outfile, FALSE );
BuildCallTo32CBClient( outfile, TRUE );
fprintf( outfile, "\t.globl " PREFIX "CALLTO16_End\n" );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment