From c75d0e16bd046872dfef0601ca972b745a336a1d Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Sun, 1 Nov 1998 17:59:35 +0000 Subject: [PATCH] Implemented new Wine startup sequence, separating startup into KERNEL/USER/GDI related parts, allowing native replacement. Implemented initial 'kernel' task. --- if1632/builtin.c | 50 +----------- include/main.h | 4 +- loader/main.c | 181 ++++++++++++++++++++++++++++++++++++------ loader/task.c | 52 +++++++++--- miscemu/main.c | 54 +++++++++++-- relay32/gdi32.spec | 1 + relay32/kernel32.spec | 1 + relay32/user32.spec | 1 + scheduler/process.c | 8 +- 9 files changed, 260 insertions(+), 92 deletions(-) diff --git a/if1632/builtin.c b/if1632/builtin.c index af3996b4c6..df96d3ac66 100644 --- a/if1632/builtin.c +++ b/if1632/builtin.c @@ -93,9 +93,9 @@ extern const WIN16_DESCRIPTOR WPROCS_Descriptor; static BUILTIN16_DLL BuiltinDLLs[] = { - { &KERNEL_Descriptor, DLL_FLAG_ALWAYS_USED }, - { &USER_Descriptor, DLL_FLAG_ALWAYS_USED }, - { &GDI_Descriptor, DLL_FLAG_ALWAYS_USED }, + { &KERNEL_Descriptor, 0 }, + { &USER_Descriptor, 0 }, + { &GDI_Descriptor, 0 }, { &SYSTEM_Descriptor, DLL_FLAG_ALWAYS_USED }, { &DISPLAY_Descriptor, DLL_FLAG_ALWAYS_USED }, { &WPROCS_Descriptor, DLL_FLAG_ALWAYS_USED }, @@ -202,10 +202,8 @@ static HMODULE16 BUILTIN_DoLoadModule16( const WIN16_DESCRIPTOR *descr ) BOOL32 BUILTIN_Init(void) { BUILTIN16_DLL *dll; - NE_MODULE *pModule; WORD vector; HMODULE16 hModule; - WORD cs, ds; fnBUILTIN_LoadModule = BUILTIN_LoadModule; @@ -215,48 +213,6 @@ BOOL32 BUILTIN_Init(void) if (!BUILTIN_DoLoadModule16( dll->descr )) return FALSE; } - /* Set the USER and GDI heap selectors */ - - pModule = NE_GetPtr( GetModuleHandle16( "USER" )); - USER_HeapSel = pModule ? GlobalHandleToSel((NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->hSeg) : 0; - pModule = NE_GetPtr( GetModuleHandle16( "GDI" )); - GDI_HeapSel = pModule ? GlobalHandleToSel((NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->hSeg) : 0; - - /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */ - - hModule = GetModuleHandle16( "KERNEL" ); - NE_SetEntryPoint( hModule, 178, GetWinFlags() ); - - /* Initialize KERNEL.454/455 (__FLATCS/__FLATDS) */ - - GET_CS(cs); GET_DS(ds); - NE_SetEntryPoint( hModule, 454, cs ); - NE_SetEntryPoint( hModule, 455, ds ); - - /* Initialize KERNEL.THHOOK */ - - TASK_InstallTHHook((THHOOK *)PTR_SEG_TO_LIN( - (SEGPTR)NE_GetEntryPoint( hModule, 332 ))); - - /* Initialize the real-mode selector entry points */ - -#define SET_ENTRY_POINT( num, addr ) \ - NE_SetEntryPoint( hModule, (num), GLOBAL_CreateBlock( GMEM_FIXED, \ - DOSMEM_MapDosToLinear(addr), 0x10000, hModule, \ - FALSE, FALSE, FALSE, NULL )) - - SET_ENTRY_POINT( 183, 0x00000 ); /* KERNEL.183: __0000H */ - SET_ENTRY_POINT( 174, 0xa0000 ); /* KERNEL.174: __A000H */ - SET_ENTRY_POINT( 181, 0xb0000 ); /* KERNEL.181: __B000H */ - SET_ENTRY_POINT( 182, 0xb8000 ); /* KERNEL.182: __B800H */ - SET_ENTRY_POINT( 195, 0xc0000 ); /* KERNEL.195: __C000H */ - SET_ENTRY_POINT( 179, 0xd0000 ); /* KERNEL.179: __D000H */ - SET_ENTRY_POINT( 190, 0xe0000 ); /* KERNEL.190: __E000H */ - SET_ENTRY_POINT( 173, 0xf0000 ); /* KERNEL.173: __ROMBIOS */ - SET_ENTRY_POINT( 194, 0xf0000 ); /* KERNEL.194: __F000H */ - NE_SetEntryPoint( hModule, 193, DOSMEM_BiosSeg ); /* KERNEL.193: __0040H */ -#undef SET_ENTRY_POINT - /* Set interrupt vectors from entry points in WPROCS.DLL */ hModule = GetModuleHandle16( "WPROCS" ); diff --git a/include/main.h b/include/main.h index 2a484b2190..dc0762a5c4 100644 --- a/include/main.h +++ b/include/main.h @@ -5,10 +5,10 @@ #ifndef __WINE_MAIN_H #define __WINE_MAIN_H -extern BOOL32 MAIN_KernelInit(void); extern void MAIN_Usage(char*); -extern BOOL32 MAIN_UserInit(void); +extern BOOL32 MAIN_MainInit(void); extern BOOL32 MAIN_WineInit( int *argc, char *argv[] ); +extern HINSTANCE32 MAIN_WinelibInit( int *argc, char *argv[] ); extern int MAIN_GetLanguageID(char*lang, char*country, char*charset, char*dialect); extern BOOL32 RELAY_Init(void); diff --git a/loader/main.c b/loader/main.c index d859bfd5fe..7b1e84630b 100644 --- a/loader/main.c +++ b/loader/main.c @@ -32,19 +32,22 @@ #include "spy.h" #include "tweak.h" #include "user.h" +#include "global.h" #include "dce.h" #include "shell.h" #include "winproc.h" #include "syslevel.h" +#include "thread.h" +#include "task.h" #include "debug.h" int __winelib = 1; /* Winelib run-time flag */ /*********************************************************************** - * Kernel initialisation routine + * Main initialisation routine */ -BOOL32 MAIN_KernelInit(void) +BOOL32 MAIN_MainInit(void) { /* Initialize syslevel handling */ SYSLEVEL_Init(); @@ -73,43 +76,133 @@ BOOL32 MAIN_KernelInit(void) /* Initialize IO-port permissions */ IO_port_init(); + /* registry initialisation */ + SHELL_LoadRegistry(); + return TRUE; } +/*********************************************************************** + * KERNEL initialisation routine + */ +BOOL32 WINAPI MAIN_KernelInit(HINSTANCE32 hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + static BOOL32 initDone = FALSE; + + NE_MODULE *pModule; + HMODULE16 hModule; + + if ( initDone ) return TRUE; + initDone = TRUE; + + /* Create and switch to initial task */ + pModule = NE_GetPtr( GetModuleHandle16( "KERNEL32" ) ); + if ( pModule ) + { + THDB *thdb = THREAD_Current(); + HINSTANCE16 hInstance = NE_CreateInstance( pModule, NULL, TRUE ); + thdb->process->task = TASK_Create( thdb, pModule, hInstance, 0, FALSE ); + + TASK_StartTask( thdb->process->task ); + } + + /* Initialize special KERNEL entry points */ + hModule = GetModuleHandle16( "KERNEL" ); + if ( hModule ) + { + WORD cs, ds; + + /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */ + NE_SetEntryPoint( hModule, 178, GetWinFlags() ); + + /* Initialize KERNEL.454/455 (__FLATCS/__FLATDS) */ + GET_CS(cs); GET_DS(ds); + NE_SetEntryPoint( hModule, 454, cs ); + NE_SetEntryPoint( hModule, 455, ds ); + + /* Initialize KERNEL.THHOOK */ + TASK_InstallTHHook((THHOOK *)PTR_SEG_TO_LIN( + (SEGPTR)NE_GetEntryPoint( hModule, 332 ))); + + /* Initialize the real-mode selector entry points */ +#define SET_ENTRY_POINT( num, addr ) \ + NE_SetEntryPoint( hModule, (num), GLOBAL_CreateBlock( GMEM_FIXED, \ + DOSMEM_MapDosToLinear(addr), 0x10000, hModule, \ + FALSE, FALSE, FALSE, NULL )) + + SET_ENTRY_POINT( 183, 0x00000 ); /* KERNEL.183: __0000H */ + SET_ENTRY_POINT( 174, 0xa0000 ); /* KERNEL.174: __A000H */ + SET_ENTRY_POINT( 181, 0xb0000 ); /* KERNEL.181: __B000H */ + SET_ENTRY_POINT( 182, 0xb8000 ); /* KERNEL.182: __B800H */ + SET_ENTRY_POINT( 195, 0xc0000 ); /* KERNEL.195: __C000H */ + SET_ENTRY_POINT( 179, 0xd0000 ); /* KERNEL.179: __D000H */ + SET_ENTRY_POINT( 190, 0xe0000 ); /* KERNEL.190: __E000H */ + SET_ENTRY_POINT( 173, 0xf0000 ); /* KERNEL.173: __ROMBIOS */ + SET_ENTRY_POINT( 194, 0xf0000 ); /* KERNEL.194: __F000H */ + NE_SetEntryPoint( hModule, 193, DOSMEM_BiosSeg ); /* KERNEL.193: __0040H */ +#undef SET_ENTRY_POINT + } + + return TRUE; +} /*********************************************************************** - * USER (and GDI) initialisation routine + * GDI initialisation routine */ -BOOL32 MAIN_UserInit(void) +BOOL32 WINAPI MAIN_GdiInit(HINSTANCE32 hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - int queueSize; + NE_MODULE *pModule; + + if ( GDI_HeapSel ) return TRUE; - /* Create USER and GDI heap */ - if (!USER_HeapSel) + /* Create GDI heap */ + pModule = NE_GetPtr( GetModuleHandle16( "GDI" ) ); + if ( pModule ) { - USER_HeapSel = GlobalAlloc16( GMEM_FIXED, 0x10000 ); - LocalInit( USER_HeapSel, 0, 0xffff ); + GDI_HeapSel = GlobalHandleToSel( (NE_SEG_TABLE( pModule ) + + pModule->dgroup - 1)->hSeg ); } - if (!GDI_HeapSel) + else { - GDI_HeapSel = GlobalAlloc16( GMEM_FIXED, GDI_HEAP_SIZE ); + GDI_HeapSel = GlobalAlloc16( GMEM_FIXED, GDI_HEAP_SIZE ); LocalInit( GDI_HeapSel, 0, GDI_HEAP_SIZE-1 ); } + /* GDI initialisation */ + return GDI_Init(); +} + +/*********************************************************************** + * USER initialisation routine + */ +BOOL32 WINAPI MAIN_UserInit(HINSTANCE32 hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + NE_MODULE *pModule; + int queueSize; + + if ( USER_HeapSel ) return TRUE; + + /* Create USER heap */ + pModule = NE_GetPtr( GetModuleHandle16( "USER" ) ); + if ( pModule ) + { + USER_HeapSel = GlobalHandleToSel( (NE_SEG_TABLE( pModule ) + + pModule->dgroup - 1)->hSeg ); + } + else + { + USER_HeapSel = GlobalAlloc16( GMEM_FIXED, 0x10000 ); + LocalInit( USER_HeapSel, 0, 0xffff ); + } + /* Initialize Wine tweaks */ if (!TWEAK_Init()) return FALSE; /* Initialize OEM Bitmaps */ if (!OBM_Init()) return FALSE; - /* registry initialisation */ - SHELL_LoadRegistry(); - /* Global atom table initialisation */ - if (!ATOM_Init()) return FALSE; - - /* GDI initialisation */ - if (!GDI_Init()) return FALSE; + if (!ATOM_Init( USER_HeapSel )) return FALSE; /* Initialize system colors and metrics*/ SYSMETRICS_Init(); @@ -152,6 +245,13 @@ BOOL32 MAIN_UserInit(void) /* Set double click time */ SetDoubleClickTime32( GetProfileInt32A("windows","DoubleClickSpeed",452) ); + /* Create task message queue for the initial task */ + if ( GetCurrentTask() ) + { + queueSize = GetProfileInt32A( "windows", "DefaultQueueSize", 8 ); + if (!SetMessageQueue32( queueSize )) return FALSE; + } + return TRUE; } @@ -159,19 +259,50 @@ BOOL32 MAIN_UserInit(void) /*********************************************************************** * Winelib initialisation routine */ -BOOL32 MAIN_WinelibInit( int *argc, char *argv[] ) +HINSTANCE32 MAIN_WinelibInit( int *argc, char *argv[] ) { + WINE_MODREF *wm; + NE_MODULE *pModule; + OFSTRUCT ofs; + HMODULE16 hModule; + HINSTANCE16 hInstance; + /* Create the initial process */ - if (!PROCESS_Init()) return FALSE; + if (!PROCESS_Init()) return 0; /* Parse command line arguments */ MAIN_WineInit( argc, argv ); - /* Initialize the kernel */ - if (!MAIN_KernelInit()) return FALSE; + /* Main initialization */ + if (!MAIN_MainInit()) return 0; - /* Initialize all the USER stuff */ - if (!MAIN_UserInit()) return FALSE; + /* Initialize KERNEL */ + if (!MAIN_KernelInit(0, 0, NULL)) return 0; - return TRUE; + /* Initialize GDI */ + if (!MAIN_GdiInit(0, 0, NULL)) return 0; + + /* Initialize USER */ + if (!MAIN_UserInit(0, 0, NULL)) return 0; + + /* Create and switch to initial task */ + if (!(wm = ELF_CreateDummyModule( argv[0], argv[0], PROCESS_Current() ))) + return 0; + PROCESS_Current()->exe_modref = wm; + + strcpy( ofs.szPathName, wm->modname ); + if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) return 0; + pModule = (NE_MODULE *)GlobalLock16( hModule ); + pModule->flags = NE_FFLAGS_WIN32; + pModule->module32 = wm->module; + + hInstance = NE_CreateInstance( pModule, NULL, TRUE ); + PROCESS_Current()->task = TASK_Create( THREAD_Current(), pModule, hInstance, 0, FALSE ); + + TASK_StartTask( PROCESS_Current()->task ); + + InitApp( hInstance ); + + return wm->module; } + diff --git a/loader/task.c b/loader/task.c index 509ee87c18..1bdca43668 100644 --- a/loader/task.c +++ b/loader/task.c @@ -425,9 +425,8 @@ HTASK16 TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance, if (!(sp = pModule->sp)) sp = pSegTable[pModule->ss-1].minsize + pModule->stack_size; - sp &= ~1; + sp &= ~1; sp -= 2*sizeof(STACK16FRAME); pTask->thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( pTask->hInstance, sp ); - pTask->thdb->cur_stack -= 2*sizeof(STACK16FRAME); frame16 = (STACK16FRAME *)PTR_SEG_TO_LIN( pTask->thdb->cur_stack ); frame16->ebp = sp + (int)&((STACK16FRAME *)0)->bp; frame16->bp = LOWORD(frame16->ebp); @@ -451,9 +450,6 @@ HTASK16 TASK_Create( THDB *thdb, NE_MODULE *pModule, HINSTANCE16 hInstance, frame32->retaddr = (DWORD)TASK_CallToStart; /* The remaining fields will be initialized in TASK_Reschedule */ - if (!THREAD_Current()->cur_stack) - THREAD_Current()->cur_stack = pTask->thdb->cur_stack; - TRACE(task, "module='%s' cmdline='%s' task=%04x\n", name, cmd_line, hTask ); @@ -483,11 +479,10 @@ void TASK_StartTask( HTASK16 hTask ) we simply Yield(). If we are 32-bit however, we need to signal the main process somehow (NOT YET IMPLEMENTED!) */ - if ( GetCurrentTask() ) - if ( THREAD_IsWin16( THREAD_Current() ) ) - Yield16(); - else - FIXME(task, "Don't know how to start 16-bit task from 32-bit thread. Move the mouse!\n"); + if ( THREAD_IsWin16( THREAD_Current() ) ) + OldYield(); + else + FIXME(task, "Don't know how to start 16-bit task from 32-bit thread. Move the mouse!\n"); } @@ -584,7 +579,7 @@ void TASK_KillCurrentTask( INT16 exitCode ) TASK_DeleteTask( hTaskToKill ); } - if (nTaskCount <= 1) + if (nTaskCount <= 2) /* FIXME */ { TRACE(task, "this is the last task, exiting\n" ); USER_ExitWindows(); @@ -630,6 +625,34 @@ void TASK_Reschedule(void) HTASK16 hTask = 0; STACK16FRAME *newframe16; + /* Get the initial task up and running */ + if (!hCurrentTask && GetCurrentTask()) + { + /* We need to remove one pair of stackframes (exept for Winelib) */ + STACK16FRAME *oldframe16 = CURRENT_STACK16; + STACK32FRAME *oldframe32 = oldframe16->frame32; + STACK16FRAME *newframe16 = PTR_SEG_TO_LIN( oldframe32->frame16 ); + STACK32FRAME *newframe32 = newframe16->frame32; + if (newframe32) + { + newframe16->entry_ip = oldframe16->entry_ip; + newframe16->entry_cs = oldframe16->entry_cs; + newframe16->ip = oldframe16->ip; + newframe16->cs = oldframe16->cs; + newframe32->ebp = oldframe32->ebp; + newframe32->restore_addr = oldframe32->restore_addr; + newframe32->codeselector = oldframe32->codeselector; + newframe32->retaddr = oldframe32->retaddr; /* don't call TASK_CallToStart */ + + THREAD_Current()->cur_stack = oldframe32->frame16; + } + + hCurrentTask = GetCurrentTask(); + pNewTask = (TDB *)GlobalLock16( hCurrentTask ); + pNewTask->ss_sp = pNewTask->thdb->cur_stack; + return; + } + /* NOTE: As we are entered from 16-bit code, we hold the Win16Lock. We hang onto it thoughout most of this routine, so that accesses to global variables (most notably the task list) are protected. */ @@ -1228,6 +1251,13 @@ HANDLE32 WINAPI GetFastQueue( void ) THDB *thdb = THREAD_Current(); if (!thdb) return 0; + if (!(thdb->teb.queue)) + { + HMODULE16 hModule = GetModuleHandle16( "USER" ); + FARPROC16 proc = WIN32_GetProcAddress16( hModule, "InitThreadInput" ); + Callbacks->CallBootAppProc( proc, 0, 4 ); /* FIXME! */ + } + if (!(thdb->teb.queue)) FIXME( task, "(): should initialize thread-local queue, expect failure!\n" ); diff --git a/miscemu/main.c b/miscemu/main.c index 82b2e5ff23..e28d8e8e8a 100644 --- a/miscemu/main.c +++ b/miscemu/main.c @@ -3,6 +3,7 @@ * */ +#include #include "callback.h" #include "debug.h" #include "debugger.h" @@ -13,6 +14,7 @@ #include "process.h" #include "win16drv.h" #include "psdrv.h" +#include "thread.h" #include "windows.h" @@ -21,13 +23,13 @@ */ BOOL32 MAIN_EmulatorInit(void) { - /* Initialize the kernel */ - if (!MAIN_KernelInit()) return FALSE; + /* Main initialization */ + if (!MAIN_MainInit()) return FALSE; /* Initialize relay code */ if (!RELAY_Init()) return FALSE; - /* Initialize signal handling */ + /* Initialize signal handling */ if (!SIGNAL_InitEmulator()) return FALSE; /* Create the Win16 printer driver */ @@ -36,8 +38,46 @@ BOOL32 MAIN_EmulatorInit(void) /* Create the Postscript printer driver (FIXME: should be in Winelib) */ if (!PSDRV_Init()) return FALSE; - /* Initialize all the USER stuff */ - return MAIN_UserInit(); + /* Load system DLLs into the initial process (and initialize them) */ + if (!LoadLibrary16( "KERNEL" )) return FALSE; /* always built-in */ + if (!LoadLibrary32A( "KERNEL32" )) return FALSE; /* always built-in */ + + if (!LoadLibrary16( "GDI.EXE" )) return FALSE; + if (!LoadLibrary32A( "GDI32.DLL" )) return FALSE; + + if (!LoadLibrary16( "USER.EXE" )) return FALSE; + if (!LoadLibrary32A( "USER32.DLL" )) return FALSE; + + return TRUE; +} + + +/*********************************************************************** + * Main loop of initial task + */ +void MAIN_EmulatorRun( void ) +{ + BOOL32 (*WINAPI pGetMessage)(MSG32* lpmsg,HWND32 hwnd,UINT32 min,UINT32 max); + BOOL32 (*WINAPI pTranslateMessage)( const MSG32* msg ); + LONG (*WINAPI pDispatchMessage)( const MSG32* msg ); + MSG32 msg; + + HMODULE32 hModule = GetModuleHandle32A( "USER32" ); + pGetMessage = GetProcAddress32( hModule, "GetMessageA" ); + pTranslateMessage = GetProcAddress32( hModule, "TranslateMessage" ); + pDispatchMessage = GetProcAddress32( hModule, "DispatchMessageA" ); + + assert( pGetMessage ); + assert( pTranslateMessage ); + assert( pDispatchMessage ); + + while ( GetNumTasks() > 1 && pGetMessage( &msg, 0, 0, 0 ) ) + { + pTranslateMessage( &msg ); + pDispatchMessage( &msg ); + } + + ExitProcess( 0 ); } @@ -131,8 +171,10 @@ int main( int argc, char *argv[] ) if (Options.debug) DEBUG_AddModuleBreakpoints(); ctx_debug_call = ctx_debug; +#if 0 /* FIXME!! */ IF1632_CallLargeStack = (int (*)(int (*func)(), void *arg))CALL32_Init(); - Yield16(); /* Start the first task */ +#endif + MAIN_EmulatorRun(); MSG("WinMain: Should never happen: returned from Yield16()\n" ); return 0; } diff --git a/relay32/gdi32.spec b/relay32/gdi32.spec index d17da44b0e..114356f4ee 100644 --- a/relay32/gdi32.spec +++ b/relay32/gdi32.spec @@ -1,5 +1,6 @@ name gdi32 type win32 +init MAIN_GdiInit 0 stub AbortDoc 1 stdcall AbortPath(long) AbortPath32 diff --git a/relay32/kernel32.spec b/relay32/kernel32.spec index aedf5275fc..c5e80a8754 100644 --- a/relay32/kernel32.spec +++ b/relay32/kernel32.spec @@ -1,5 +1,6 @@ name kernel32 type win32 +init MAIN_KernelInit # Functions exported by the Win95 kernel32.dll # (these need to have these exact ordinals, for some win95 dlls diff --git a/relay32/user32.spec b/relay32/user32.spec index c3d6f63cb4..6ccffbe0ba 100644 --- a/relay32/user32.spec +++ b/relay32/user32.spec @@ -1,5 +1,6 @@ name user32 type win32 +init MAIN_UserInit 1 stub ActivateKeyboardLayout 2 stdcall AdjustWindowRect(ptr long long) AdjustWindowRect32 diff --git a/scheduler/process.c b/scheduler/process.c index cc3dc64c83..09407302b8 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -254,7 +254,7 @@ BOOL32 PROCESS_Init(void) /* Create the initial process and thread structures */ if (!(pdb = PROCESS_CreatePDB( NULL ))) return FALSE; - if (!(thdb = THREAD_Create( pdb, 0, TRUE, NULL, NULL, NULL, NULL ))) return FALSE; + if (!(thdb = THREAD_Create( pdb, 0, FALSE, NULL, NULL, NULL, NULL ))) return FALSE; thdb->unix_pid = getpid(); PROCESS_InitialProcessID = PDB_TO_PROCESS_ID(pdb); @@ -346,6 +346,12 @@ PDB32 *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env, pdb->task = TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow); if (!pdb->task) goto error; + + /* Map system DLLs into this process (from initial process) */ + /* FIXME: this is a hack */ + pdb->modref_list = PROCESS_Initial()->modref_list; + + return pdb; error: -- 2.32.0.93.g670b81a890