2020-09-30 17:17:25 +02:00

297 lines
7.2 KiB
C

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
animate.c
Abstract:
Startup animation implementation.
--*/
#include <stddef.h>
#pragma code_seg("INIT")
#pragma data_seg("INIT_RW")
#pragma const_seg("INIT_RD")
#include "ntos.h"
#include "stdio.h"
#include "stdlib.h"
#include "wtypes.h"
#include "ani.h"
// Tell linker to put startup animation code and data into INIT section
#pragma comment(linker, "/merge:INIT_RD=INIT")
#pragma comment(linker, "/merge:INIT_RW=INIT")
#pragma comment(linker, "/merge:D3D=INIT")
#pragma comment(linker, "/merge:D3D_RD=INIT")
#pragma comment(linker, "/merge:D3D_RW=INIT")
#pragma comment(linker, "/merge:XGRPH=INIT")
#pragma comment(linker, "/merge:XGRPH_RD=INIT")
// We always want to link with the animation code, so that we can
// keep the build from breaking. Thats why we use a global to
// decide whether to run the animation or not. The global tricks
// the linker into linking in all the code the animation uses.
#ifdef NOANI
BOOL gBootAnimation_DoAnimation = FALSE;
#else
BOOL gBootAnimation_DoAnimation = TRUE;
#endif
#ifdef BOOTSOUND
BOOL gBootAnimation_DoSound = TRUE;
#else
BOOL gBootAnimation_DoSound = FALSE;
#endif
// Background animation thread.
HANDLE g_hThread;
// Entrypoing into the animation thread.
VOID AnipStartAnimationThread(PKSTART_ROUTINE StartRoutine, PVOID StartContext);
// Main animation routine as defined in the animation library.
VOID AnipRunAnimation();
#define CONTIGUOUS_BLOCK_SIZE (5 * 1024 * 1024 / 2)
#define AGP_APERTURE_BYTES (64*1024*1024)
#define INSTANCE_MEM_MAXSIZE (20*1024)
#define NV_INSTANCE_SIZE (INSTANCE_MEM_MAXSIZE)
//------------------------------------------------------------------------
// Starts the animation which will run on a background thread. This API
// returns immediately.
//
BOOL g_bShortVersion;
void AniStartAnimation(BOOLEAN fShort)
{
NTSTATUS Status;
if (gBootAnimation_DoAnimation){
g_bShortVersion = fShort;
Status = PsCreateSystemThreadEx(&g_hThread,
0,
0x4000, // Stack size, 16K
0,
NULL,
NULL,
NULL,
FALSE,
FALSE,
AnipStartAnimationThread);
if (!NT_SUCCESS(Status))
{
// RIP(("AniStartAnimation - Unable to create thread."));
g_hThread = NULL;
}
}
}
//------------------------------------------------------------------------
// Shut down the animation. This will block until the animation finishes.
//
void AniTerminateAnimation()
{
if (g_hThread)
{
NTSTATUS Status;
#if DBG
int start = NtGetTickCount();
#endif
// Wait for it to go away.
Status = NtWaitForSingleObjectEx(g_hThread, KernelMode, FALSE, NULL);
#if DBG
DbgPrint("Boot animation wait %d\n", NtGetTickCount() - start);
if (Status == STATUS_TIMEOUT)
{
//RIP(("AniTerminateAnimation - Animation is stuck!"));
}
#endif
NtClose(g_hThread);
g_hThread = NULL;
}
}
void AnipBreak()
{
#if DBG
_asm int 3;
#endif
}
#if DBG
int gcMemAllocsContiguous = 0;
#endif
//------------------------------------------------------------------------
// Blocks until the animation has completed (until the animation is ready
// to display the Microsoft logo).
//
void AniBlockOnAnimation(void)
{
extern KEVENT g_EventLogoWaiting;
NTSTATUS status;
PETHREAD ThreadObject;
PVOID WaitObjects[2];
KWAIT_BLOCK WaitBlocks[2];
if (g_hThread)
{
status = ObReferenceObjectByHandle(g_hThread, &PsThreadObjectType,
(PVOID*)&ThreadObject);
if (NT_SUCCESS(status))
{
WaitObjects[0] = ThreadObject;
WaitObjects[1] = &g_EventLogoWaiting;
KeWaitForMultipleObjects(2, WaitObjects, WaitAny, Executive,
KernelMode, FALSE, NULL, WaitBlocks);
ObDereferenceObject(ThreadObject);
}
}
}
//------------------------------------------------------------------------
// MemAllocContiguous
//
void *MemAllocContiguous(size_t Size, DWORD Alignment)
{
#if DBG
gcMemAllocsContiguous++;
#endif
return MmAllocateContiguousMemoryEx(
Size,
0,
AGP_APERTURE_BYTES - NV_INSTANCE_SIZE,
Alignment,
PAGE_READWRITE | PAGE_WRITECOMBINE);
}
//------------------------------------------------------------------------
// MemFreeContiguous
//
void MemFreeContiguous(void *pv)
{
#if DBG
if (gcMemAllocsContiguous <= 0)
{
AnipBreak();
}
gcMemAllocsContiguous--;
#endif
MmFreeContiguousMemory(pv);
}
//------------------------------------------------------------------------
// Main animation procedure. Defers to the startup animation library.
//
VOID AnipStartAnimationThread(
PKSTART_ROUTINE StartRoutine,
PVOID StartContext
)
{
AnipRunAnimation();
// Make this thread go away.
PsTerminateSystemThread(0);
}
///////////////////////////////////////////////////////////////////////////////
// Defined so we don't have to pull libc in
typedef void (__cdecl *_PVFV)(void);
int __cdecl atexit(_PVFV func)
{
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Define a couple of debug-only methods used in XGRAPHICS that normally
// are implemented in XTL.
#ifdef STARTUPANIMATION
long __cdecl _ftol2(float x)
{
DWORD result[2];
unsigned short oldcw;
unsigned short newcw;
_asm
{
fstcw [oldcw] ; get control word
fwait ; synchronize
mov ax, [oldcw] ; round mode saved
or ah, 0ch ; set chop rounding mode
mov [newcw], ax ; back to memory
fldcw [newcw] ; reset rounding
fistp qword ptr [result] ; store chopped integer
fldcw [oldcw] ; restore rounding
mov eax, dword ptr [result]
mov edx, dword ptr [result+4]
}
}
#define D_EXP(x) ((unsigned short *)&(x)+3)
#define D_HI(x) ((unsigned long *)&(x)+1)
#define D_LO(x) ((unsigned long *)&(x))
#define IS_D_QNAN(x) ((*D_EXP(x) & 0x7ff8) == 0x7ff8)
#define IS_D_SNAN(x) ((*D_EXP(x) & 0x7ff8) == 0x7ff0 && \
(*D_HI(x) << 13 || *D_LO(x)))
int __cdecl _isnan(double x)
{
if (IS_D_SNAN(x) || IS_D_QNAN(x)) {
return 1;
}
return 0;
}
VOID
XDebugError(PCHAR Module, PCHAR Format, ...)
{
_asm int 3;
}
void Sleep(DWORD Milliseconds)
{
_asm int 3;
}
VOID
OutputDebugStringA(
IN LPCSTR lpOutputString
)
{
DbgPrint((PSTR)lpOutputString);
}
#endif