297 lines
7.2 KiB
C
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
|
|
|