Windows Research Kernel 1.2 source code

This commit is contained in:
Михаил Агарков 2025-09-13 19:04:39 +03:00
commit d2d851979c

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.vs/

12
Build.bat Normal file
View File

@ -0,0 +1,12 @@
@ECHO OFF
IF [%2] EQU [] goto setenv
set path=%2\tools\%1;%path%
set wrkarch=%1
goto dothejob
:setenv
call WRKEnv.bat %1
:dothejob
cd base\ntos\
nmake -nologo %wrkarch%=
cd ..\..

11
Clean.bat Normal file
View File

@ -0,0 +1,11 @@
IF [%2] EQU [] goto setenv
set path=%2\tools\%1;%path%
set wrkarch=%1
goto dothejob
:setenv
call WRKEnv.bat %1
:dothejob
cd base\ntos\
nmake %wrkarch%= clean
cd ..\..

View File

@ -0,0 +1,339 @@
Getting Started with the Windows Research Kernel (WRK)
Version 1.23 Thursday April 23, 2009
Marty Humphrey, Associate Professor, Department of Computer Science,
University of Virginia
Brian Burns, Program Manager, Microsoft
Serge Lidin, Software Design Engineer, Microsoft
The purpose of this document is to illustrate how to compile, modify, and
use the Windows Research Kernel (WRK). The basic idea is that you will edit
and recompile the WRK on a Windows computer, and then run it on a virtual
machine running Windows Server 2003. The virtual machine will run in the
Virtual PC 2007 environment, which in turn runs under the host Windows OS.
The host OS may be Windows Server 2003 or later, or Windows XP or later.
This document contains the steps you can take to install everything you
need to edit, compile, and run the WRK. The final section of this document
describes how to modify the WRK source code, recompile your kernel, and
confirm that your changes are executed by attaching a kernel debugger to
the virtual machine. Throughout this document, there are nine self-study
questions.
The intended audience of this document are new users to the WRK with
limited knowledge of the Windows operating system. No special knowledge of
operating system design and/or implementation is necessary to perform the
steps in this document. Editing the WRK can be accomplished by any text
editor, and compilation of the WRK utilizes the nmake utility that is
installed with the WRK sources.
General Information
1. You will need to work rather extensively with the console (Windows
Command Prompt) windows. To start a fresh console window, use
selections (Start ( All Programs ( Accessories ( Command Prompt) OR
(Start ( Run), then type “cmd” and click OK or press Enter.
2. To execute a command in the console window, type this command and
press Enter.
3. There are four components you need to have installed on your machine:
Windows Debugger, Virtual PC 2007, virtual machine image of Windows
Server 2003 SP1 (with virtual hard drive image), and the WRK itself
including source code, tools and binaries. Installation of virtual
machine with its hard drive image and of WRK boils down to simple
copying them to specified directories.
4. You can install all the components separately from respective entries
on the DVD or you can install everything using file
WRKCompleteInstall.bat residing in the root of the DVD.
Working with WRKCompleteInstall.bat
The WRKCompleteInstall.bat takes four parameters specifying destination
directories of the components being installed:
/i <virtual_machine_directory>
/w <WRK_directory>
/d <debugger_directory>
/v <Virtual_PC_directory>
The default destination directories are as follows:
WRK: C:\WRK-v1.2\
Virtual machine: C:\WRK-v1.2\Win2k3SP1 Image\
Debugger: C:\Program Files\Debugging Tools for Windows\
Virtual PC: C:\Program Files\Microsoft Virtual PC\
If you dont mind the components to be installed to their default
destinations, invoke WRKCompleteInstall.bat without parameters by opening
Windows Explorer (double-click on “Computer” icon on your desktop),
selecting the DVD drive, and double-clicking on WRKCompleteInstall.bat
entry.
Alternatively, you can run WRKCompleteInstall.bat from a console window,
with or without parameters:
1. Open Windows Explorer and find out what is the letter of your DVD
drive (let it be, say, F).
2. Open console window, type F: and press Enter; you have switched to
your DVD drive.
3. Now type WRKCompleteInstall and press Enter to install the components
to default destinations
4. OR specify the destinations, for example:
WRKCompleteInstall /i C:\WRK_VM /w C:\WRK /d C:\WinDbg /v C:\VPC
If the full name (path) of a destination directory contains space symbol,
the whole path should be enclosed in double quotes, for example: /d
“C:\Program Files\WinDbg”
The destination directories should not yet exist on your drive. If the
batch file detects that a destination directory already exists, it skips
installation of respective component.
This is done to enable the batch file to perform partial installations. For
example, if you already have Virtual PC 2007 installed on your computer,
specify its installation directory in /v parameter, and installation of
Virtual PC 2007 will be skipped.
Copying WRK Separately
To copy the WRK (presuming you have the other three components already
installed) to your machine, follow these steps:
- open a console window;
- switch to DVD drive;
- execute command cd \Resources\Windows_Research_Kernel\Get_WRK
- execute command WRKCopy /w <destination_directory>
(if you run WRKCopy.bat without parameters, WRK will be copied to C:\WRK-
v1.2\);
ALTERNATIVELY
- open Windows Explorer;
- create the destination directory on your hard drive;
- switch to DVD drive;
- navigate to \Resources\Windows_Research_Kernel\Get_WRK\WRK-v1.2\;
- select all files and subdirectories, drag and drop them to the
destination directory.
Exercise #1: Building the WRK
Windows Research Kernel can be built from Visual Studio 2008 environment or
from a console window.
To build WRK from command line:
- open console window;
- switch to the directory WRK was copied to (for example, cd \WRK-v1.2);
- execute Build <arch> (or Rebuild <arch> or Clean <arch>), see note about
<arch> below;
OR
- open console window;
- switch to the directory WRK was copied to;
- execute WRKEnv <arch>, see note about <arch> below;
- execute cd base\ntos
- execute nmake %wrkarch%=
To build WRK in VS2008 environment:
- start VS2008;
- open solution <WRK_DIR>\WRK.sln, where <WRK_DIR> is the directory WRK was
copied to;
- make sure the Configuration is amd64/Win32 or x86/Win32, as is
appropriate;
- select Build/Build Solution (or Rebuild Solution, or Clean Solution).
NOTE: dont start the build before looking at question #Q-1, below!
The built kernel is located in c:\WRK-v1.2\base\ntos\BUILD\EXE as
wrkx86.exe .
NOTE ABOUT <arch>
Batch files Build.bat, Rebuild.bat, Clean.bat, WRKEnv.bat and WRKDebug.bat
take one parameter target architecture, which is x86 or amd64.
For the first use of either of these batch files, default target
architecture is x86.
Once the target architecture was defined (explicitly or by default), it
cannot be changed for current console window, and <arch> parameter of the
batch files is ignored.
The title of the window where the WRK environment has been set to some
target architecture changes to “WRK x86” or “WRK amd64”.
To work with different target architecture, open another console window.
Questions for this exercise:
1. How long did it take to compile your kernel the first time? If you run
the same command a second time (step #5, above), how long does it take?
(It is sufficient in this case to “eye-ball” it seconds resolution is
fine).
Exercise #2: Running Windows Server 2003 inside Virtual PC 2007
1. A fully configured Virtual PC 2007 virtual machine has been provided on
this DVD for you to run the WRK. If the default installation options were
used, it is located in the directory
C:\WRK-v1.2\Win2k3SP1 Image\
2. Start Virtual PC 2007 (Start ( All Programs ( Microsoft Virtual PC).
This will start the “New Virtual Machine Wizard”:
a. “Add an existing virtual machine”
b. Browse to c:\WRK-v1.2\Win2k3SP1 Image\ (or whatever directory you
chose with WRKCompleteInstall.bat) and choose the file “Win2k3 SP1
WRK.vmc”
c. Click Next ( Finish, making sure the “When I click Finish, open
Settings” box is checked.
3. The settings windows for “Win2k3 SP1 WRK” should now be open. Please
note the following:
a. “Undo Disks” is disabled. Any changes you make to the virtual
machine will be written to the hard disk. If you want the option of
throwing out any changes you make when you turn off the virtual
machine, enable this option.
b. The named pipe \\.\pipe\debug is configured on COM1. This allows
WinDbg to connect to the WRK within the Virtual PC 2007
environment.
c. “Virtual Machine Additions” are installed, enabling “pointer
integration”. “Virtual Machine Additions” allow a tighter
connection between the host machine and the Virtual Machine (for
example, the performance of the virtual machine will be better, you
can resize the Virtual Machine window, and you will be able to drag-
and-drop from the physical machine to the virtual machine).
i. Note: upon rebooting the Virtual Machine, the way to get
“Ctrl-Alt-Delete” to the Virtual Machine is via the Virtual
Machines “Action” menu.
d. The “Shared Folder” c:\ ( z:\ is enabled. This option maps the c:\
root directory on the host machine to the z:\ drive on the virtual
machine for easy file sharing between the systems.
4. Start the “Win2k3 SP1 WRK” virtual machine from within the Virtual PC
Console window.
5. At the boot prompt, select “Windows Server 2003, Standard”. This option
boots the original Windows Server 2003 SP1 kernel. The other options boot
the WRK with and without debugging enabled.
a. Note: To help people keep track of kernel versions being run, the
virtual machine desktop wallpaper has been preconfigured to show
the kernel build number.
6. The virtual machine has been preconfigured to automatically login to the
administrator account without user interaction. If you prefer to use
another account or require user login, please use the information
provided in SetAutoAdministratorLogon.zip on the virtual machine desktop
to modify this behavior.
7. Give your physical machine a name unique to you to prevent any domain
naming conflicts.
a. Right click on My Computer ( Properties (Computer Name (Change
b. You can also add the virtual machine to a domain if you wish. It is
preconfigured to be part of the generic workgroup “WORKGROUP”
8. Note: Windows update is turned “off” to prevent SP2 from being installed
in the virtual machine. SP2 is not compatible with the WRK at this time
and installing SP2 into the virtual machine can only be reversed if the
“Undo Disks” setting is enabled.
Questions for this exercise:
2. How big is the physical file that contains your virtual disk? (Right
click on the .vhd file and get “Properties” not the .vmc file)
Exercise #3: Monitor the invocation of “QuerySystemInformation”
In this portion of the lab you will modify the WRK kernel to print out some
debugging information to keep track of the number of times
“QuerySystemInformation” is invoked (sometimes a developer may wish the
kernel is “instrumented” this way for performance purposes for example,
if we find that this function is invoked A LOT, then this function is a
reasonable candidate for performance optimization, right?)
1. In this first step, well confirm that you can attach a debugger to the
kernel (we wont actually modify the kernel until the next step). Follow
the instructions at http://support.microsoft.com/kb/871171/ to attach the
kernel debugger to your Virtual Machine (Note that this works for Virtual
PC 2007 as well follow the instructions for Virtual PC 2004). Here is
some additional information:
a. Start your WRK Virtual Machine if its not already running and at
the boot prompt, chose the “Windows Server 2003 SP1, WRK [debugger
enabled]” option.
b. Your virtual machine should sit idle while it waits for the Windows
Debugger (WinDbg) to connect.
c. Open a console window on the host machine and start the Windows
Debugger:
- switch to the directory WRK was copied to;
- execute WRKDebug <arch> (see note about <arch> in Exercise #1);
OR
- switch to the directory WRK was copied to;
- execute WRKEnv <arch> (see note about <arch> in Exercise #1);
- execute WinDbg %windbgargs%
d. During the booting activity, you should see a few lines of text on
your “WinDbg” window (probably beginning with “Connected to Windows
Server 2003 3790 x86 compatible target, ptr64 FALSE”). If not, then
re-try, making sure that you selected the debugging kernel to be
booted.
i. Note: In order to connect to the kernel from WinDbg, you may
have to click Debug ( Break in the WinDbg window.
e. Once this works, go onto the next step without shutting down your
Virtual Machine or your windbdg.exe window. Youll know it works if
you see this info in the debugging window and youre able to log
onto your WRK Virtual Machine.
2. Now we will modify the kernel, install it on the Virtual Machine, boot
the modified kernel, and see the output on the debugging window. Well
start by modifying and recompiling our kernel on the physical machine:
a. Open a text editor of your choice and edit C:/WRK-
v1.2/base/ntos/ex/sysinfo.c
b. Get to line 1721 and insert the following line:
static int NumTimesCalled = 0;
c. Shortly after this (immediately before the line “Status =
STATUS_SUCCESS”), add the following line:
DbgPrint( “WRK %d: Entering
NTQuerySystemInformation!!!\n”,++NumTimesCalled );
d. Save the file and recompile the kernel as above (Exercise #2) [1]
3. Drag-and-drop your new kernel onto the Virtual Machines Administrators
“My Documents” folder (the new kernel will be on the physical machine in
C:\WRK-v1.2\base\ntos\BUILD\EXE, with the name wrkx86.exe). Once you have
moved it to the Virtual Machine, copy this file on the Virtual Machine to
C:\WINDOWS\system32\
a. The virtual machine has been preconfigured to boot the WRK and
already contains the file wrkx86.exe in C:\WINDOWS\System32. We
recommend you back up this file before copying over it with the
modified kernel. When this file is copied over, the WRK boot
options in the virtual machine will both point to the new kernel.
4. Reboot the Virtual Machine via Start ( Shutdown ( Restart. Select the
“Windows Server 2003 SP1, WRK [debugger enabled]” boot option and watch
the output on the debugging window.
a. Note: youll probably have to select the debugger window, which
may be hidden, and select “no” to the question “Save information
for workspace?”)
5. If everything is working, you should start seeing something like:
WRK 82: Entering NTQuerySystemInformation!!!
WRK 83: Entering NTQuerySystemInformation!!!
WRK 84: Entering NTQuerySystemInformation!!!
If youre not seeing this, then go back through the instructions to see
if youve missed something. Note: if your new kernel does not boot, then
you can reboot into the “Windows Server 2003, Standard” boot kernel.
Questions for this exercise:
3. How many times is this function invoked up until right before the
Windows login banner appears, right after the WRK Virtual Machine has
fully booted?
4. Show a small section of the output of the invocation of your debugging
statement. To do this, first select the Debugging window and then hit Alt-
PrtSc (“print screen”). This will put a copy of the window into the edit
buffer, which you can then get at (say in Microsoft Office) via Edit (
paste.
5. Once youve completed that, and closed your Virtual Machine and
debugging window, how big is the physical file that contains your virtual
disk now? Why is this? (I.e., why is it the same, or why has it changed?)
Thats it! You have successfully modified the Windows Research Kernel and
observed your change in action. By following this basic procedure, you are
now able to explore all kinds of kernel modifications and subsequently test
the effect of such changes. Our general advice: Always keep a “safe” copy
of a kernel bootable via C:\boot.ini this will allow you to easily revert
to a known safe state. Have fun!
-----------------------
[1] We recommend you make a backup copy of this file before saving the
modified version.

113
LICENSE.txt Normal file
View File

@ -0,0 +1,113 @@
Windows Research Kernel Source Code License
This license governs use of the accompanying software, and your use of
the software constitutes acceptance of this license. Your license rights
below are subject to the restrictions in the license, and are available
to you only so long as you remain eligible due to your affiliation with
an accredited educational institution. (For more details on eligibility
see http://www.microsoft.com/WindowsAcademic).
You may use and modify this software for any non-commercial purpose within
your educational institution, including making a reasonable number of copies.
Teaching, academic research, and personal experimentation are examples of
purposes which can be non-commercial. You may post copies on an internal
secure server, and it may be installed and used on personal machines of
eligible users.
You may distribute snippets of this software in research papers, books or
other teaching materials, or publish snippets of the software on websites
or on-line community forums that are intended for teaching and research.
The total amount of source code in each of your snippets should not
exceed 50 lines. If you wish to use a larger portion of the software,
please contact compsci@microsoft.com.
You may not use or distribute this software or any derivative works in
any form for commercial purposes. Examples of commercial purposes would
be running business operations, licensing, leasing, or selling the software,
or distributing the software for use with commercial products.
If you wish to commercialize your work related to the software or take
part in research with industrial partners, you need to contact
iplg@microsoft.com to enquire about a commercial license.
You may distribute the software and modifications to the software for
non-commercial purposes, but only to other eligible users of the
software (for example, to another university student or professor to
support joint academic research). You may not grant rights to the
software or derivative works that are broader than those provided
by this license. For example, you may not distribute modifications
of the software under terms that would permit commercial use, or under
terms that purport to require the software or derivative works to be
sublicensed to others.
You may use any information in intangible form that you remember after
accessing the software. However, this right does not grant you a license
to any of Microsoft's copyrights or patents for anything you might
create using such information.
In return for the license rights above, you must agree to these obligations:
1. You will not remove any copyright or other notices from the software,
nor reverse engineer or decompile binary portions of the software,
unless your laws give you the right to do so despite this restriction.
2. You will include a verbatim copy of this license if you distribute
the software in any form.
3. If you distribute derivative works of the software in source code
form you will do so only under this license, and if you distribute
derivative works of the software solely in object form you will do so
only under a license that complies with this license.
4. If you have modified the software or created derivative works,
and distribute such modifications or derivative works, you will cause
the modified files to carry prominent notices describing your changes
and the date of the changes, so that recipients know that they are not
receiving the original software.
5. Microsoft welcomes your comments and suggestions on the source code,
which you provide on a strictly voluntary basis. If you give Microsoft
comments and suggestions regarding bug fixes, enhancements or other
modifications to the source code, you agree that Microsoft may,
in connection with Microsoft products and services use, disclose or
otherwise commercialize your comments and suggestions entirely without
any obligation or restriction based on intellectual property rights or
otherwise. You will not give any comments or suggestions that you have
reason to believe are subject to any patent, copyright, or other
intellectual property claim or right of any third party.
6. THE SOFTWARE COMES "AS IS", WITH NO WARRANTIES. THIS MEANS NO EXPRESS,
IMPLIED OR STATUTORY WARRANTY, INCLUDING WITHOUT LIMITATION, WARRANTIES
OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE OR ANY WARRANTY
OF TITLE OR NON-INFRINGEMENT. YOU MUST PASS THIS DISCLAIMER ON WHENEVER
YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS.
7. MICROSOFT WILL NOT BE LIABLE FOR ANY DAMAGES RELATED TO THE SOFTWARE
OR THIS LICENSE, INCLUDING DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL
OR INCIDENTAL DAMAGES, TO THE MAXIMUM EXTENT THE LAW PERMITS, NO MATTER
WHAT LEGAL THEORY IT IS BASED ON. YOU MUST PASS THIS LIMITATION OF
LIABILITY ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS.
8. If you sue anyone over patents that you think may apply to the software
or anyone's use of the software, your license to the software ends
immediately.
9. You will not use the software to aid the development of any software
programs that are designed to:
(a) harm or intentionally interfere with the operation of a computer
system including any data or information stored on such computer
system; and/or
(b) surreptitiously gain or maintain high level access to a computer
system, self-propagate, and/or execute in a manner that prevents
detection, including but not limited to, so-called “rootkit”
software programs, viruses, or worms.
10. Your rights under the license end immediately if you breach it
in any way.
11. Microsoft reserves all rights not expressly granted to you in this
license.
License Version: 5 December 2008.

148
README.txt Normal file
View File

@ -0,0 +1,148 @@
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of
the Windows Research Kernel Source Code License agreement
(see License.txt). If you do not agree to the terms, do not use the code.
***
WRK v1.2
The Windows Research Kernel v1.2 contains the sources for the core of
the Windows (NTOS) kernel and a build environment for a kernel that will run on
x86 (Windows Server 2003 Service Pack 1) and
amd64 (Windows XP x64 Professional)
A future version may also support booting WRK kernels on Windows XP x86 systems,
but the current kernels will fail to boot due to differences in some shared
structures.
The NTOS kernel implements the basic OS functions
for processes, threads, virtual memory and cache managers, I/O management,
the registry, executive functions such as the kernel heap and synchronization,
the object manager, the local procedure call mechanism, the security reference
monitor, low-level CPU management (thread scheduling, Asynchronous and Deferred
Procedure calls, interrupt/trap handling, exceptions), etc.
The NT Hardware Abstraction Layer, file systems, network stacks, and device
drivers are implemented separately from NTOS and loaded into kernel mode
as dynamic libraries. Sources for these dynamic components are not included
in the WRK, but some are available in various development kits published
by Microsoft, such as the Installable File System (IFS) Kit and the
Windows Driver Development Kit (DDK).
WRK v1.2 includes most of the NTOS kernel sources from the latest released
version of Windows, which supports the AMD64 architecture on the Desktop.
The kernel sources excluded from the kit are primarily in the areas of
plug-and-play, power management, the device verifier, kernel debugger
interface, and virtual dos machine. The primary modifications to WRK
from the released kernel are related to cleanup and removal of server
support, such as code related to the Intel IA64.
***
Organization of the WRK sources
The file License.txt contains the license covering use of the WRK.
The public\ directory contains a number of include files shared among system
components. base\ntos\ contains the NTOS sources.
The primary NTOS source components included in the WRK are organized as follows:
cache\ - cache manager
config\ - registry implementation
dbgk\ - user-mode debugger support
ex\ - executive functions (kernel heap, synchronization, time)
fsrtl\ - file system run-time support
io\ - I/O manager
ke\ - scheduler, CPU management, low-level synchronization
lpc\ - local procedure call implementation
mm\ - virtual memory manager
ob\ - kernel object manager
ps\ - process/thread support
se\ - security functions
wmi\ - Windows Management Instrumentation
inc\ - NTOS-only include files
rtl\ - kernel run-time support
init\ - kernel startup
***
Copying and building the WRK
WRK can be built on Windows Server 2003 or later, or on Windows XP or later.
To copy WRK to your machine:
- open a console window;
- switch to DVD;
- switch to \Resources\Windows_Research_Kernel\Get_WRK\;
- run WRKCopy.bat /w <destination_directory>
(if you run WRKCopy.bat without parameters, WRK will be copied to C:\WRK-v1.2\);
ALTERNATIVELY
- open Windows Explorer (MyComputer);
- create the destination directory on your hard drive;
- switch to DVD;
- navigate to \Resources\Windows_Research_Kernel\Get_WRK\WRK-v1.2\;
- select all files and subdirectories, drag and drop them to the destination
directory.
To adjust the WRK environment setting batch file:
- open console window;
- switch to the directory WRK was copied to;
- run Notepad WRKEnv.bat;
- make sure the "set path=..." statement contains the directory WinDbg was
installed to; (unchanged WRKEnv.bat refers to default directory
C:\Program Files\Debugging Tools for Windows);
- save the file and exit Notepad.
To build WRK from command line:
- open console window;
- switch to the directory WRK was copied to;
- run Build <arch> (or Rebuild <arch> or Clean <arch>), see note about <arch>
below;
ALTERNATIVELY
- open console window;
- switch to the directory WRK was copied to;
- run WRKEnv <arch>, see note about <arch> below;
- switch to base\ntos;
- run nmake %wrkarch%=
To build WRK in Visual Studio 2008 environment:
- start VS2008;
- open solution <WRK_DIR>\WRK.sln, where <WRK_DIR> is the directory WRK was
copied to;
- make sure the configuration is amd64/Win32 or x86/Win32, as is appropriate;
- select Build/Build Solution (or Rebuild Solution, or Clean Solution).
To start Windows Debugger from command line:
- open console window;
- switch to the directory WRK was copied to;
- run WRKDebug <arch>, see note about <arch> below;
ALTERNATIVELY
- open console window;
- switch to the directory WRK was copied to;
- run WRKEnv <arch>, see note about <arch> below;
- run WinDbg %windbgargs%
-----------------------------------------------------------------------------
NOTE ABOUT <ARCH>
Batch files Build.bat, Rebuild.bat, Clean.bat, WRKEnv.bat and WRKDebug.bat
take one parameter target architecture, which is x86 or amd64.
For the first use of either of these batch files, default target architecture
is x86.
Once the target architecture was defined (explicitly or by default), it
cannot be changed for current console window, and <arch> parameter of the
batch files is ignored.
The title of the window where the WRK environment has been set to some target
architecture changes to “WRK x86” or “WRK amd64”.
To work with different target architecture, open another console window.
-----------------------------------------------------------------------------
***

5
Rebuild.bat Normal file
View File

@ -0,0 +1,5 @@
@ECHO OFF
call clean.bat %1 %2
call build.bat %1 %2

19
WRK.sln Normal file
View File

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsResearchKernel", "WRK.vcproj", "{7B312FB7-F0A3-41FE-89D1-6100FDC35009}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
amd64|Win32 = amd64|Win32
x86|Win32 = x86|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7B312FB7-F0A3-41FE-89D1-6100FDC35009}.amd64|Win32.ActiveCfg = amd64|Win32
{7B312FB7-F0A3-41FE-89D1-6100FDC35009}.amd64|Win32.Build.0 = amd64|Win32
{7B312FB7-F0A3-41FE-89D1-6100FDC35009}.x86|Win32.ActiveCfg = x86|Win32
{7B312FB7-F0A3-41FE-89D1-6100FDC35009}.x86|Win32.Build.0 = x86|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

2770
WRK.vcproj Normal file

File diff suppressed because it is too large Load Diff

708
WRK.vcxproj Normal file
View File

@ -0,0 +1,708 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="amd64|Win32">
<Configuration>amd64</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="x86|Win32">
<Configuration>x86</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>WindowsResearchKernel</ProjectName>
<ProjectGuid>{7B312FB7-F0A3-41FE-89D1-6100FDC35009}</ProjectGuid>
<RootNamespace>WindowsResearchKernel</RootNamespace>
<Keyword>MakeFileProj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64|Win32'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86|Win32'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='amd64|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='x86|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.25123.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)base\ntos\BUILD\$(Configuration)\</IntDir>
<NMakeBuildCommandLine>"$(SolutionDir)build.bat" $(Configuration) $(SolutionDir)</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>"$(SolutionDir)rebuild.bat" $(Configuration) $(SolutionDir)</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>"$(SolutionDir)clean.bat" $(Configuration) $(SolutionDir)</NMakeCleanCommandLine>
<NMakeOutput />
<NMakePreprocessorDefinitions>_X86_=1;i386=1;STD_CALL;FPO=0;CONDITION_HANDLING=1;WRK_MEMORY_MANAGEMENT;NT_INST=0;WIN32=100;_NT1X_=100;WINNT=1;_WIN32_WINNT=0x0502;WINVER=0x0502;_WIN32_IE=0x0603;WIN32_LEAN_AND_MEAN=1;DBG=0;DEVL=1;__BUILDMACHINE__=WRK1.2(university);NDEBUG;_NTSYSTEM_;NT_SMT;NTOS_KERNEL_RUNTIME=1;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
<NMakeIncludeSearchPath>$(SolutionDir)base\ntos\se;$(SolutionDir)base\ntos\rtl;$(SolutionDir)base\ntos\raw;$(SolutionDir)base\ntos\ps;$(SolutionDir)base\ntos\perf;$(SolutionDir)base\ntos\ob;$(SolutionDir)base\ntos\mm;$(SolutionDir)base\ntos\lpc;$(SolutionDir)base\ntos\ke;$(SolutionDir)base\ntos\io\iomgr;$(SolutionDir)base\ntos\io;$(SolutionDir)base\ntos\init;$(SolutionDir)base\ntos\fstub;$(SolutionDir)base\ntos\fsrtl;$(SolutionDir)base\ntos\ex;$(SolutionDir)base\ntos\dbgk;$(SolutionDir)base\ntos\config;$(SolutionDir)base\ntos\cache;$(SolutionDir)public\halkit\inc;$(SolutionDir)public\sdk\inc\crt;$(SolutionDir)public\sdk\inc;$(SolutionDir)public\internal\base\inc;$(SolutionDir)base\inc;$(SolutionDir)public\internal\sdktools\inc;$(SolutionDir)public\internal\ds\inc;$(SolutionDir)public\ddk\inc;..\$(Configuration);$(SolutionDir)base\ntos\$(ProjectName);$(SolutionDir)base\ntos\inc;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>base\ntos\BUILD\$(Configuration)\</IntDir>
<NMakeBuildCommandLine>"$(SolutionDir)build.bat" $(Configuration) $(SolutionDir)</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>"$(SolutionDir)rebuild.bat" $(Configuration) $(SolutionDir)</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>"$(SolutionDir)clean.bat" $(Configuration) $(SolutionDir)</NMakeCleanCommandLine>
<NMakeOutput />
<NMakePreprocessorDefinitions>_WIN64;_AMD64_;AMD64CONDITION_HANDLING=1;NT_INST=0;WIN32=100;_NT1X_=100; WINNT=1;_WIN32_WINNT=0x0502;WINVER=0x0502;_WIN32_IE=0x0603;WIN32_LEAN_AND_MEAN=1;DBG=0;DEVL=1;__BUILDMACHINE__=WRK1.2(university);NDEBUG;_NTSYSTEM_;NT_SMT;NTOS_KERNEL_RUNTIME=1;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
<NMakeIncludeSearchPath>$(SolutionDir)base\ntos\se;$(SolutionDir)base\ntos\rtl;$(SolutionDir)base\ntos\raw;$(SolutionDir)base\ntos\ps;$(SolutionDir)base\ntos\perf;$(SolutionDir)base\ntos\ob;$(SolutionDir)base\ntos\mm;$(SolutionDir)base\ntos\lpc;$(SolutionDir)base\ntos\ke;$(SolutionDir)base\ntos\io\iomgr;$(SolutionDir)base\ntos\io;$(SolutionDir)base\ntos\init;$(SolutionDir)base\ntos\fstub;$(SolutionDir)base\ntos\fsrtl;$(SolutionDir)base\ntos\ex;$(SolutionDir)base\ntos\dbgk;$(SolutionDir)base\ntos\config;$(SolutionDir)base\ntos\cache;$(SolutionDir)public\halkit\inc;$(SolutionDir)public\sdk\inc\crt;$(SolutionDir)public\sdk\inc;$(SolutionDir)public\internal\base\inc;$(SolutionDir)base\inc;$(SolutionDir)public\internal\sdktools\inc;$(SolutionDir)public\internal\ds\inc;$(SolutionDir)public\ddk\inc;..\$(Configuration);$(SolutionDir)base\ntos\$(ProjectName);$(SolutionDir)base\ntos\inc;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
</PropertyGroup>
<ItemDefinitionGroup>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="base\ntos\cache\cachedat.c" />
<ClCompile Include="base\ntos\cache\cachesub.c" />
<ClCompile Include="base\ntos\cache\ccperf.c" />
<ClCompile Include="base\ntos\cache\copysup.c" />
<ClCompile Include="base\ntos\cache\fssup.c" />
<ClCompile Include="base\ntos\cache\lazyrite.c" />
<ClCompile Include="base\ntos\cache\logsup.c" />
<ClCompile Include="base\ntos\cache\mdlsup.c" />
<ClCompile Include="base\ntos\cache\pinsup.c" />
<ClCompile Include="base\ntos\cache\vacbsup.c" />
<ClCompile Include="base\ntos\config\cmalloc.c" />
<ClCompile Include="base\ntos\config\cmapi.c" />
<ClCompile Include="base\ntos\config\cmapi2.c" />
<ClCompile Include="base\ntos\config\cmboot.c" />
<ClCompile Include="base\ntos\config\cmchek.c" />
<ClCompile Include="base\ntos\config\cmchek2.c" />
<ClCompile Include="base\ntos\config\cmclose.c" />
<ClCompile Include="base\ntos\config\cmconfig.c" />
<ClCompile Include="base\ntos\config\cmcontrl.c" />
<ClCompile Include="base\ntos\config\cmdat.c" />
<ClCompile Include="base\ntos\config\cmdat2.c" />
<ClCompile Include="base\ntos\config\cmdatini.c" />
<ClCompile Include="base\ntos\config\cmdelay.c" />
<ClCompile Include="base\ntos\config\cmdelete.c" />
<ClCompile Include="base\ntos\config\cmdown.c" />
<ClCompile Include="base\ntos\config\cmgquota.c" />
<ClCompile Include="base\ntos\config\cmhook.c" />
<ClCompile Include="base\ntos\config\cmhvlist.c" />
<ClCompile Include="base\ntos\config\cmindex.c" />
<ClCompile Include="base\ntos\config\cminit.c" />
<ClCompile Include="base\ntos\config\cmmapvw.c" />
<ClCompile Include="base\ntos\config\cmname.c" />
<ClCompile Include="base\ntos\config\cmnotify.c" />
<ClCompile Include="base\ntos\config\cmparse.c" />
<ClCompile Include="base\ntos\config\cmparse2.c" />
<ClCompile Include="base\ntos\config\cmquery.c" />
<ClCompile Include="base\ntos\config\cmsavres.c" />
<ClCompile Include="base\ntos\config\cmse.c" />
<ClCompile Include="base\ntos\config\cmsecache.c" />
<ClCompile Include="base\ntos\config\cmsubs.c" />
<ClCompile Include="base\ntos\config\cmsubs2.c" />
<ClCompile Include="base\ntos\config\cmsubs3.c" />
<ClCompile Include="base\ntos\config\cmsysini.c" />
<ClCompile Include="base\ntos\config\cmtrecpy.c" />
<ClCompile Include="base\ntos\config\cmtredel.c" />
<ClCompile Include="base\ntos\config\cmtree.c" />
<ClCompile Include="base\ntos\config\cmvalue.c" />
<ClCompile Include="base\ntos\config\cmwmi.c" />
<ClCompile Include="base\ntos\config\cmworker.c" />
<ClCompile Include="base\ntos\config\cmwrapr.c" />
<ClCompile Include="base\ntos\config\cmwrapr2.c" />
<ClCompile Include="base\ntos\config\hivebin.c" />
<ClCompile Include="base\ntos\config\hivecell.c" />
<ClCompile Include="base\ntos\config\hivechek.c" />
<ClCompile Include="base\ntos\config\hivefree.c" />
<ClCompile Include="base\ntos\config\hivehint.c" />
<ClCompile Include="base\ntos\config\hiveinit.c" />
<ClCompile Include="base\ntos\config\hiveload.c" />
<ClCompile Include="base\ntos\config\hivemap.c" />
<ClCompile Include="base\ntos\config\hivesum.c" />
<ClCompile Include="base\ntos\config\hivesync.c" />
<ClCompile Include="base\ntos\config\ntapi.c" />
<ClCompile Include="base\ntos\dbgk\dbgkobj.c" />
<ClCompile Include="base\ntos\dbgk\dbgkport.c" />
<ClCompile Include="base\ntos\dbgk\dbgkproc.c" />
<ClCompile Include="base\ntos\ex\amd64\wowinfo.c" />
<ClCompile Include="base\ntos\ex\callback.c" />
<ClCompile Include="base\ntos\ex\callperf.c" />
<ClCompile Include="base\ntos\ex\delay.c" />
<ClCompile Include="base\ntos\ex\event.c" />
<ClCompile Include="base\ntos\ex\eventpr.c" />
<ClCompile Include="base\ntos\ex\exatom.c" />
<ClCompile Include="base\ntos\ex\exdata.c" />
<ClCompile Include="base\ntos\ex\exinit.c" />
<ClCompile Include="base\ntos\ex\fmutexc.c" />
<ClCompile Include="base\ntos\ex\handle.c" />
<ClCompile Include="base\ntos\ex\harderr.c" />
<ClCompile Include="base\ntos\ex\keyedevent.c" />
<ClCompile Include="base\ntos\ex\lookasid.c" />
<ClCompile Include="base\ntos\ex\luid.c" />
<ClCompile Include="base\ntos\ex\mutant.c" />
<ClCompile Include="base\ntos\ex\nbqueue.c" />
<ClCompile Include="base\ntos\ex\pool.c" />
<ClCompile Include="base\ntos\ex\probe.c" />
<ClCompile Include="base\ntos\ex\profile.c" />
<ClCompile Include="base\ntos\ex\pushlock.c" />
<ClCompile Include="base\ntos\ex\raise.c" />
<ClCompile Include="base\ntos\ex\resource.c" />
<ClCompile Include="base\ntos\ex\rundown.c" />
<ClCompile Include="base\ntos\ex\semphore.c" />
<ClCompile Include="base\ntos\ex\sysinfo.c" />
<ClCompile Include="base\ntos\ex\timer.c" />
<ClCompile Include="base\ntos\ex\uuid.c" />
<ClCompile Include="base\ntos\ex\win32.c" />
<ClCompile Include="base\ntos\ex\worker.c" />
<ClCompile Include="base\ntos\ex\zone.c" />
<ClCompile Include="base\ntos\fsrtl\dbcsname.c" />
<ClCompile Include="base\ntos\fsrtl\fastio.c" />
<ClCompile Include="base\ntos\fsrtl\faulttol.c" />
<ClCompile Include="base\ntos\fsrtl\filelock.c" />
<ClCompile Include="base\ntos\fsrtl\filter.c" />
<ClCompile Include="base\ntos\fsrtl\filtrctx.c" />
<ClCompile Include="base\ntos\fsrtl\fsfilter.c" />
<ClCompile Include="base\ntos\fsrtl\fsrtlpc.c" />
<ClCompile Include="base\ntos\fsrtl\largemcb.c" />
<ClCompile Include="base\ntos\fsrtl\name.c" />
<ClCompile Include="base\ntos\fsrtl\notify.c" />
<ClCompile Include="base\ntos\fsrtl\oplock.c" />
<ClCompile Include="base\ntos\fsrtl\pnp.c" />
<ClCompile Include="base\ntos\fsrtl\stackovf.c" />
<ClCompile Include="base\ntos\fsrtl\tunnel.c" />
<ClCompile Include="base\ntos\fsrtl\unc.c" />
<ClCompile Include="base\ntos\fstub\drivesup.c" />
<ClCompile Include="base\ntos\init\initos.c" />
<ClCompile Include="base\ntos\init\ntkrnlmp.c" />
<ClCompile Include="base\ntos\init\ntoskrnl.c" />
<ClCompile Include="base\ntos\io\ioguid.c" />
<ClCompile Include="base\ntos\io\iomgr\cancelapi.c" />
<ClCompile Include="base\ntos\io\iomgr\complete.c" />
<ClCompile Include="base\ntos\io\iomgr\create.c" />
<ClCompile Include="base\ntos\io\iomgr\dev2dos.c" />
<ClCompile Include="base\ntos\io\iomgr\devctrl.c" />
<ClCompile Include="base\ntos\io\iomgr\dir.c" />
<ClCompile Include="base\ntos\io\iomgr\errorlog.c" />
<ClCompile Include="base\ntos\io\iomgr\fsctrl.c" />
<ClCompile Include="base\ntos\io\iomgr\internal.c" />
<ClCompile Include="base\ntos\io\iomgr\iodata.c" />
<ClCompile Include="base\ntos\io\iomgr\ioinit.c" />
<ClCompile Include="base\ntos\io\iomgr\iosubs.c" />
<ClCompile Include="base\ntos\io\iomgr\loadunld.c" />
<ClCompile Include="base\ntos\io\iomgr\lock.c" />
<ClCompile Include="base\ntos\io\iomgr\misc.c" />
<ClCompile Include="base\ntos\io\iomgr\objsup.c" />
<ClCompile Include="base\ntos\io\iomgr\open.c" />
<ClCompile Include="base\ntos\io\iomgr\parse.c" />
<ClCompile Include="base\ntos\io\iomgr\qsea.c" />
<ClCompile Include="base\ntos\io\iomgr\qsfs.c" />
<ClCompile Include="base\ntos\io\iomgr\qsinfo.c" />
<ClCompile Include="base\ntos\io\iomgr\qsquota.c" />
<ClCompile Include="base\ntos\io\iomgr\read.c" />
<ClCompile Include="base\ntos\io\iomgr\write.c" />
<ClCompile Include="base\ntos\ke\amd64\allproc.c" />
<ClCompile Include="base\ntos\ke\amd64\apcuser.c" />
<ClCompile Include="base\ntos\ke\amd64\callback.c" />
<ClCompile Include="base\ntos\ke\amd64\decode.c" />
<ClCompile Include="base\ntos\ke\amd64\exceptn.c" />
<ClCompile Include="base\ntos\ke\amd64\flush.c" />
<ClCompile Include="base\ntos\ke\amd64\flushtb.c" />
<ClCompile Include="base\ntos\ke\amd64\initkr.c" />
<ClCompile Include="base\ntos\ke\amd64\intobj.c" />
<ClCompile Include="base\ntos\ke\amd64\ipi.c" />
<ClCompile Include="base\ntos\ke\amd64\misc.c" />
<ClCompile Include="base\ntos\ke\amd64\pat.c" />
<ClCompile Include="base\ntos\ke\amd64\queuelock.c" />
<ClCompile Include="base\ntos\ke\amd64\runtime.c" />
<ClCompile Include="base\ntos\ke\amd64\spinlock.c" />
<ClCompile Include="base\ntos\ke\amd64\thredini.c" />
<ClCompile Include="base\ntos\ke\apcobj.c" />
<ClCompile Include="base\ntos\ke\apcsup.c" />
<ClCompile Include="base\ntos\ke\balmgr.c" />
<ClCompile Include="base\ntos\ke\bugcheck.c" />
<ClCompile Include="base\ntos\ke\config.c" />
<ClCompile Include="base\ntos\ke\debug.c" />
<ClCompile Include="base\ntos\ke\devquobj.c" />
<ClCompile Include="base\ntos\ke\dpclock.c" />
<ClCompile Include="base\ntos\ke\dpcobj.c" />
<ClCompile Include="base\ntos\ke\dpcsup.c" />
<ClCompile Include="base\ntos\ke\eventobj.c" />
<ClCompile Include="base\ntos\ke\gateobj.c" />
<ClCompile Include="base\ntos\ke\hifreqlk.c" />
<ClCompile Include="base\ntos\ke\i386\abiosc.c" />
<ClCompile Include="base\ntos\ke\i386\allproc.c" />
<ClCompile Include="base\ntos\ke\i386\apcuser.c" />
<ClCompile Include="base\ntos\ke\i386\biosc.c" />
<ClCompile Include="base\ntos\ke\i386\callback.c" />
<ClCompile Include="base\ntos\ke\i386\exceptn.c" />
<ClCompile Include="base\ntos\ke\i386\flush.c" />
<ClCompile Include="base\ntos\ke\i386\flushtb.c" />
<ClCompile Include="base\ntos\ke\i386\gdtsup.c" />
<ClCompile Include="base\ntos\ke\i386\i386init.c" />
<ClCompile Include="base\ntos\ke\i386\intobj.c" />
<ClCompile Include="base\ntos\ke\i386\iopm.c" />
<ClCompile Include="base\ntos\ke\i386\kernlini.c" />
<ClCompile Include="base\ntos\ke\i386\largepag.c" />
<ClCompile Include="base\ntos\ke\i386\ldtsup.c" />
<ClCompile Include="base\ntos\ke\i386\misc.c" />
<ClCompile Include="base\ntos\ke\i386\mtrr.c" />
<ClCompile Include="base\ntos\ke\i386\mtrramd.c" />
<ClCompile Include="base\ntos\ke\i386\pat.c" />
<ClCompile Include="base\ntos\ke\i386\thredini.c" />
<ClCompile Include="base\ntos\ke\i386\trapc.c" />
<ClCompile Include="base\ntos\ke\idsched.c" />
<ClCompile Include="base\ntos\ke\interobj.c" />
<ClCompile Include="base\ntos\ke\kernldat.c" />
<ClCompile Include="base\ntos\ke\kevutil.c" />
<ClCompile Include="base\ntos\ke\kiinit.c" />
<ClCompile Include="base\ntos\ke\miscc.c" />
<ClCompile Include="base\ntos\ke\mutntobj.c" />
<ClCompile Include="base\ntos\ke\procobj.c" />
<ClCompile Include="base\ntos\ke\profobj.c" />
<ClCompile Include="base\ntos\ke\queueobj.c" />
<ClCompile Include="base\ntos\ke\raisexcp.c" />
<ClCompile Include="base\ntos\ke\semphobj.c" />
<ClCompile Include="base\ntos\ke\thkemul.c" />
<ClCompile Include="base\ntos\ke\thredobj.c" />
<ClCompile Include="base\ntos\ke\thredsup.c" />
<ClCompile Include="base\ntos\ke\timerobj.c" />
<ClCompile Include="base\ntos\ke\timersup.c" />
<ClCompile Include="base\ntos\ke\wait.c" />
<ClCompile Include="base\ntos\ke\waitsup.c" />
<ClCompile Include="base\ntos\ke\xipi.c" />
<ClCompile Include="base\ntos\ke\yield.c" />
<ClCompile Include="base\ntos\lpc\lpcclose.c" />
<ClCompile Include="base\ntos\lpc\lpccompl.c" />
<ClCompile Include="base\ntos\lpc\lpcconn.c" />
<ClCompile Include="base\ntos\lpc\lpccreat.c" />
<ClCompile Include="base\ntos\lpc\lpcinit.c" />
<ClCompile Include="base\ntos\lpc\lpclistn.c" />
<ClCompile Include="base\ntos\lpc\lpcpriv.c" />
<ClCompile Include="base\ntos\lpc\lpcquery.c" />
<ClCompile Include="base\ntos\lpc\lpcqueue.c" />
<ClCompile Include="base\ntos\lpc\lpcrecv.c" />
<ClCompile Include="base\ntos\lpc\lpcreply.c" />
<ClCompile Include="base\ntos\lpc\lpcsend.c" />
<ClCompile Include="base\ntos\mm\acceschk.c" />
<ClCompile Include="base\ntos\mm\addrsup.c" />
<ClCompile Include="base\ntos\mm\allocpag.c" />
<ClCompile Include="base\ntos\mm\allocvm.c" />
<ClCompile Include="base\ntos\mm\amd64\dataamd.c" />
<ClCompile Include="base\ntos\mm\amd64\initamd.c" />
<ClCompile Include="base\ntos\mm\buildmdl.c" />
<ClCompile Include="base\ntos\mm\creasect.c" />
<ClCompile Include="base\ntos\mm\deleteva.c" />
<ClCompile Include="base\ntos\mm\dmpaddr.c" />
<ClCompile Include="base\ntos\mm\extsect.c" />
<ClCompile Include="base\ntos\mm\flushbuf.c" />
<ClCompile Include="base\ntos\mm\flushsec.c" />
<ClCompile Include="base\ntos\mm\forksup.c" />
<ClCompile Include="base\ntos\mm\freevm.c" />
<ClCompile Include="base\ntos\mm\hypermap.c" />
<ClCompile Include="base\ntos\mm\i386\data386.c" />
<ClCompile Include="base\ntos\mm\i386\init386.c" />
<ClCompile Include="base\ntos\mm\i386\paesup.c" />
<ClCompile Include="base\ntos\mm\i386\procpae.c" />
<ClCompile Include="base\ntos\mm\i386\procx86.c" />
<ClCompile Include="base\ntos\mm\i386\setmodfy.c" />
<ClCompile Include="base\ntos\mm\iosup.c" />
<ClCompile Include="base\ntos\mm\lockvm.c" />
<ClCompile Include="base\ntos\mm\mapcache.c" />
<ClCompile Include="base\ntos\mm\mapview.c" />
<ClCompile Include="base\ntos\mm\miglobal.c" />
<ClCompile Include="base\ntos\mm\mmfault.c" />
<ClCompile Include="base\ntos\mm\mminit.c" />
<ClCompile Include="base\ntos\mm\mmquota.c" />
<ClCompile Include="base\ntos\mm\mmsup.c" />
<ClCompile Include="base\ntos\mm\modwrite.c" />
<ClCompile Include="base\ntos\mm\pagfault.c" />
<ClCompile Include="base\ntos\mm\pfndec.c" />
<ClCompile Include="base\ntos\mm\pfnlist.c" />
<ClCompile Include="base\ntos\mm\physical.c" />
<ClCompile Include="base\ntos\mm\procsup.c" />
<ClCompile Include="base\ntos\mm\protect.c" />
<ClCompile Include="base\ntos\mm\querysec.c" />
<ClCompile Include="base\ntos\mm\queryvm.c" />
<ClCompile Include="base\ntos\mm\readwrt.c" />
<ClCompile Include="base\ntos\mm\sectsup.c" />
<ClCompile Include="base\ntos\mm\session.c" />
<ClCompile Include="base\ntos\mm\sessload.c" />
<ClCompile Include="base\ntos\mm\shutdown.c" />
<ClCompile Include="base\ntos\mm\sysload.c" />
<ClCompile Include="base\ntos\mm\sysptes.c" />
<ClCompile Include="base\ntos\mm\umapview.c" />
<ClCompile Include="base\ntos\mm\vadtree.c" />
<ClCompile Include="base\ntos\mm\wrtfault.c" />
<ClCompile Include="base\ntos\mm\wrtwatch.c" />
<ClCompile Include="base\ntos\mm\wslist.c" />
<ClCompile Include="base\ntos\mm\wsmanage.c" />
<ClCompile Include="base\ntos\mm\wstree.c" />
<ClCompile Include="base\ntos\mm\zeropage.c" />
<ClCompile Include="base\ntos\ob\fastref.c" />
<ClCompile Include="base\ntos\ob\obclose.c" />
<ClCompile Include="base\ntos\ob\obcreate.c" />
<ClCompile Include="base\ntos\ob\obdevmap.c" />
<ClCompile Include="base\ntos\ob\obdir.c" />
<ClCompile Include="base\ntos\ob\obhandle.c" />
<ClCompile Include="base\ntos\ob\obinit.c" />
<ClCompile Include="base\ntos\ob\obinsert.c" />
<ClCompile Include="base\ntos\ob\oblink.c" />
<ClCompile Include="base\ntos\ob\obquery.c" />
<ClCompile Include="base\ntos\ob\obref.c" />
<ClCompile Include="base\ntos\ob\obsdata.c" />
<ClCompile Include="base\ntos\ob\obse.c" />
<ClCompile Include="base\ntos\ob\obtype.c" />
<ClCompile Include="base\ntos\ob\obwait.c" />
<ClCompile Include="base\ntos\perf\hooks.c" />
<ClCompile Include="base\ntos\perf\logging.c" />
<ClCompile Include="base\ntos\perf\perfdata.c" />
<ClCompile Include="base\ntos\perf\perfsup.c" />
<ClCompile Include="base\ntos\ps\amd64\psctxamd64.c" />
<ClCompile Include="base\ntos\ps\amd64\psldt.c" />
<ClCompile Include="base\ntos\ps\amd64\psvdm.c" />
<ClCompile Include="base\ntos\ps\create.c" />
<ClCompile Include="base\ntos\ps\i386\psctx386.c" />
<ClCompile Include="base\ntos\ps\i386\psldt.c" />
<ClCompile Include="base\ntos\ps\i386\psvdm.c" />
<ClCompile Include="base\ntos\ps\kulookup.c" />
<ClCompile Include="base\ntos\ps\pscid.c" />
<ClCompile Include="base\ntos\ps\psctx.c" />
<ClCompile Include="base\ntos\ps\psdelete.c" />
<ClCompile Include="base\ntos\ps\psenum.c" />
<ClCompile Include="base\ntos\ps\pshelper.c" />
<ClCompile Include="base\ntos\ps\psimpers.c" />
<ClCompile Include="base\ntos\ps\psinit.c" />
<ClCompile Include="base\ntos\ps\psjob.c" />
<ClCompile Include="base\ntos\ps\psopen.c" />
<ClCompile Include="base\ntos\ps\psquery.c" />
<ClCompile Include="base\ntos\ps\psquota.c" />
<ClCompile Include="base\ntos\ps\psspnd.c" />
<ClCompile Include="base\ntos\ps\security.c" />
<ClCompile Include="base\ntos\raw\cleanup.c" />
<ClCompile Include="base\ntos\raw\close.c" />
<ClCompile Include="base\ntos\raw\create.c" />
<ClCompile Include="base\ntos\raw\fileinfo.c" />
<ClCompile Include="base\ntos\raw\fsctrl.c" />
<ClCompile Include="base\ntos\raw\rawdisp.c" />
<ClCompile Include="base\ntos\raw\rawinit.c" />
<ClCompile Include="base\ntos\raw\readwrit.c" />
<ClCompile Include="base\ntos\raw\strucsup.c" />
<ClCompile Include="base\ntos\rtl\acledit.c" />
<ClCompile Include="base\ntos\rtl\add2stra.c" />
<ClCompile Include="base\ntos\rtl\add2strw.c" />
<ClCompile Include="base\ntos\rtl\amd64\context.c" />
<ClCompile Include="base\ntos\rtl\amd64\exdsptch.c" />
<ClCompile Include="base\ntos\rtl\amd64\misalign.c" />
<ClCompile Include="base\ntos\rtl\amd64\raise.c" />
<ClCompile Include="base\ntos\rtl\amd64\stkwalk.c" />
<ClCompile Include="base\ntos\rtl\assert.c" />
<ClCompile Include="base\ntos\rtl\atom.c" />
<ClCompile Include="base\ntos\rtl\avltable.c" />
<ClCompile Include="base\ntos\rtl\bitmap.c" />
<ClCompile Include="base\ntos\rtl\byteswap.c" />
<ClCompile Include="base\ntos\rtl\cnvint.c" />
<ClCompile Include="base\ntos\rtl\debug.c" />
<ClCompile Include="base\ntos\rtl\eballoc.c" />
<ClCompile Include="base\ntos\rtl\environ.c" />
<ClCompile Include="base\ntos\rtl\error.c" />
<ClCompile Include="base\ntos\rtl\excptdbg.c" />
<ClCompile Include="base\ntos\rtl\generr.c" />
<ClCompile Include="base\ntos\rtl\gentable.c" />
<ClCompile Include="base\ntos\rtl\guid.c" />
<ClCompile Include="base\ntos\rtl\i386\context.c" />
<ClCompile Include="base\ntos\rtl\i386\debug3.c" />
<ClCompile Include="base\ntos\rtl\i386\divlarge.c" />
<ClCompile Include="base\ntos\rtl\i386\exdsptch.c" />
<ClCompile Include="base\ntos\rtl\i386\getcalr.c" />
<ClCompile Include="base\ntos\rtl\imagedir.c" />
<ClCompile Include="base\ntos\rtl\intbits.c" />
<ClCompile Include="base\ntos\rtl\ldrreloc.c" />
<ClCompile Include="base\ntos\rtl\ldrrsrc.c" />
<ClCompile Include="base\ntos\rtl\lookup.c" />
<ClCompile Include="base\ntos\rtl\message.c" />
<ClCompile Include="base\ntos\rtl\nls.c" />
<ClCompile Include="base\ntos\rtl\nlsxlat.c" />
<ClCompile Include="base\ntos\rtl\pctohdr.c" />
<ClCompile Include="base\ntos\rtl\peb.c" />
<ClCompile Include="base\ntos\rtl\prefix.c" />
<ClCompile Include="base\ntos\rtl\regutil.c" />
<ClCompile Include="base\ntos\rtl\rtlassig.c" />
<ClCompile Include="base\ntos\rtl\rtldata.c" />
<ClCompile Include="base\ntos\rtl\rtlexec.c" />
<ClCompile Include="base\ntos\rtl\rtlnthdr.c" />
<ClCompile Include="base\ntos\rtl\sertl.c" />
<ClCompile Include="base\ntos\rtl\splay.c" />
<ClCompile Include="base\ntos\rtl\stktrace.c" />
<ClCompile Include="base\ntos\rtl\str2adda.c" />
<ClCompile Include="base\ntos\rtl\str2addw.c" />
<ClCompile Include="base\ntos\rtl\string.c" />
<ClCompile Include="base\ntos\rtl\sysvol.c" />
<ClCompile Include="base\ntos\rtl\time.c" />
<ClCompile Include="base\ntos\rtl\tracedb.c" />
<ClCompile Include="base\ntos\se\accessck.c" />
<ClCompile Include="base\ntos\se\adtinit.c" />
<ClCompile Include="base\ntos\se\adtlog.c" />
<ClCompile Include="base\ntos\se\adtutil.c" />
<ClCompile Include="base\ntos\se\adtvars.c" />
<ClCompile Include="base\ntos\se\capture.c" />
<ClCompile Include="base\ntos\se\privileg.c" />
<ClCompile Include="base\ntos\se\rmaudit.c" />
<ClCompile Include="base\ntos\se\rmlogon.c" />
<ClCompile Include="base\ntos\se\rmmain.c" />
<ClCompile Include="base\ntos\se\rmvars.c" />
<ClCompile Include="base\ntos\se\seassign.c" />
<ClCompile Include="base\ntos\se\seastate.c" />
<ClCompile Include="base\ntos\se\seaudit.c" />
<ClCompile Include="base\ntos\se\seclient.c" />
<ClCompile Include="base\ntos\se\seglobal.c" />
<ClCompile Include="base\ntos\se\seinit.c" />
<ClCompile Include="base\ntos\se\semethod.c" />
<ClCompile Include="base\ntos\se\sep.c" />
<ClCompile Include="base\ntos\se\sepaudit.c" />
<ClCompile Include="base\ntos\se\subject.c" />
<ClCompile Include="base\ntos\se\token.c" />
<ClCompile Include="base\ntos\se\tokenadj.c" />
<ClCompile Include="base\ntos\se\tokendup.c" />
<ClCompile Include="base\ntos\se\tokenopn.c" />
<ClCompile Include="base\ntos\se\tokenqry.c" />
<ClCompile Include="base\ntos\se\tokenset.c" />
<ClCompile Include="base\ntos\wmi\alloc.c" />
<ClCompile Include="base\ntos\wmi\amd64\mcaevent.c" />
<ClCompile Include="base\ntos\wmi\api.c" />
<ClCompile Include="base\ntos\wmi\callouts.c" />
<ClCompile Include="base\ntos\wmi\chunk.c" />
<ClCompile Include="base\ntos\wmi\consumer.c" />
<ClCompile Include="base\ntos\wmi\dataprov.c" />
<ClCompile Include="base\ntos\wmi\ds.c" />
<ClCompile Include="base\ntos\wmi\enabdisa.c" />
<ClCompile Include="base\ntos\wmi\globalog.c" />
<ClCompile Include="base\ntos\wmi\i386\mcaevent.c" />
<ClCompile Include="base\ntos\wmi\mca.c" />
<ClCompile Include="base\ntos\wmi\notify.c" />
<ClCompile Include="base\ntos\wmi\provider.c" />
<ClCompile Include="base\ntos\wmi\register.c" />
<ClCompile Include="base\ntos\wmi\secure.c" />
<ClCompile Include="base\ntos\wmi\smbios.c" />
<ClCompile Include="base\ntos\wmi\traceapi.c" />
<ClCompile Include="base\ntos\wmi\tracelog.c" />
<ClCompile Include="base\ntos\wmi\tracesup.c" />
<ClCompile Include="base\ntos\wmi\wmi.c" />
<ClCompile Include="base\ntos\wmi\wmidata.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="base\inc\ntdlltrc.h" />
<ClInclude Include="base\ntos\cache\cc.h" />
<ClInclude Include="base\ntos\config\cmp.h" />
<ClInclude Include="base\ntos\config\cmpbug.h" />
<ClInclude Include="base\ntos\config\hive.h" />
<ClInclude Include="base\ntos\dbgk\dbgkp.h" />
<ClInclude Include="base\ntos\ex\exp.h" />
<ClInclude Include="base\ntos\fsrtl\fsrtlp.h" />
<ClInclude Include="base\ntos\fstub\drivesup.h" />
<ClInclude Include="base\ntos\fstub\fstub.h" />
<ClInclude Include="base\ntos\fstub\haldisp.h" />
<ClInclude Include="base\ntos\inc\amd64.h" />
<ClInclude Include="base\ntos\inc\cache.h" />
<ClInclude Include="base\ntos\inc\cm.h" />
<ClInclude Include="base\ntos\inc\cmdata.h" />
<ClInclude Include="base\ntos\inc\cpyuchr.h" />
<ClInclude Include="base\ntos\inc\dbgk.h" />
<ClInclude Include="base\ntos\inc\dockintf.h" />
<ClInclude Include="base\ntos\inc\ex.h" />
<ClInclude Include="base\ntos\inc\exboosts.h" />
<ClInclude Include="base\ntos\inc\exlevels.h" />
<ClInclude Include="base\ntos\inc\fsrtl.h" />
<ClInclude Include="base\ntos\inc\hal.h" />
<ClInclude Include="base\ntos\inc\hivedata.h" />
<ClInclude Include="base\ntos\inc\i386.h" />
<ClInclude Include="base\ntos\inc\init.h" />
<ClInclude Include="base\ntos\inc\intrlk.h" />
<ClInclude Include="base\ntos\inc\io.h" />
<ClInclude Include="base\ntos\inc\kd.h" />
<ClInclude Include="base\ntos\inc\kddll.h" />
<ClInclude Include="base\ntos\inc\ke.h" />
<ClInclude Include="base\ntos\inc\kx.h" />
<ClInclude Include="base\ntos\inc\lfs.h" />
<ClInclude Include="base\ntos\inc\lpc.h" />
<ClInclude Include="base\ntos\inc\mm.h" />
<ClInclude Include="base\ntos\inc\ntos.h" />
<ClInclude Include="base\ntos\inc\ntosdef.h" />
<ClInclude Include="base\ntos\inc\ob.h" />
<ClInclude Include="base\ntos\inc\perf.h" />
<ClInclude Include="base\ntos\inc\pnp.h" />
<ClInclude Include="base\ntos\inc\po.h" />
<ClInclude Include="base\ntos\inc\pool.h" />
<ClInclude Include="base\ntos\inc\procpowr.h" />
<ClInclude Include="base\ntos\inc\ps.h" />
<ClInclude Include="base\ntos\inc\se.h" />
<ClInclude Include="base\ntos\inc\smbios.h" />
<ClInclude Include="base\ntos\inc\stktrace.h" />
<ClInclude Include="base\ntos\inc\v86emul.h" />
<ClInclude Include="base\ntos\inc\vdmntos.h" />
<ClInclude Include="base\ntos\inc\verifier.h" />
<ClInclude Include="base\ntos\inc\wmi.h" />
<ClInclude Include="base\ntos\io\iomgr\iomgr.h" />
<ClInclude Include="base\ntos\io\iop.h" />
<ClInclude Include="base\ntos\io\iopcmn.h" />
<ClInclude Include="base\ntos\io\ioverifier.h" />
<ClInclude Include="base\ntos\io\iovutil.h" />
<ClInclude Include="base\ntos\io\PNPMGR\pplastgood.h" />
<ClInclude Include="base\ntos\io\PNPMGR\ppvutil.h" />
<ClInclude Include="base\ntos\io\sessnirp.h" />
<ClInclude Include="base\ntos\io\trackirp.h" />
<ClInclude Include="base\ntos\ke\amd64\kiamd64.h" />
<ClInclude Include="base\ntos\ke\i386\abios.h" />
<ClInclude Include="base\ntos\ke\i386\kix86.h" />
<ClInclude Include="base\ntos\ke\i386\mtrr.h" />
<ClInclude Include="base\ntos\ke\i386\pat.h" />
<ClInclude Include="base\ntos\ke\ki.h" />
<ClInclude Include="base\ntos\lpc\lpcp.h" />
<ClInclude Include="base\ntos\mm\amd64\miamd.h" />
<ClInclude Include="base\ntos\mm\i386\mi386.h" />
<ClInclude Include="base\ntos\mm\mi.h" />
<ClInclude Include="base\ntos\ob\obp.h" />
<ClInclude Include="base\ntos\ob\obvutil.h" />
<ClInclude Include="base\ntos\perf\perfp.h" />
<ClInclude Include="base\ntos\ps\psp.h" />
<ClInclude Include="base\ntos\raw\nodetype.h" />
<ClInclude Include="base\ntos\raw\rawprocs.h" />
<ClInclude Include="base\ntos\raw\rawstruc.h" />
<ClInclude Include="base\ntos\rtl\add2strt.h" />
<ClInclude Include="base\ntos\rtl\amd64\ntrtlamd64.h" />
<ClInclude Include="base\ntos\rtl\error.h" />
<ClInclude Include="base\ntos\rtl\i386\ntrtl386.h" />
<ClInclude Include="base\ntos\rtl\ntrtlp.h" />
<ClInclude Include="base\ntos\rtl\str2addt.h" />
<ClInclude Include="base\ntos\rtl\tracedbp.h" />
<ClInclude Include="base\ntos\se\adt.h" />
<ClInclude Include="base\ntos\se\adtp.h" />
<ClInclude Include="base\ntos\se\adtutil.h" />
<ClInclude Include="base\ntos\se\pch.h" />
<ClInclude Include="base\ntos\se\rmp.h" />
<ClInclude Include="base\ntos\se\sep.h" />
<ClInclude Include="base\ntos\se\tokenp.h" />
<ClInclude Include="base\ntos\VERIFIER\halverifier.h" />
<ClInclude Include="base\ntos\VERIFIER\vfbugcheck.h" />
<ClInclude Include="base\ntos\VERIFIER\vfddi.h" />
<ClInclude Include="base\ntos\VERIFIER\vfdeadlock.h" />
<ClInclude Include="base\ntos\VERIFIER\vfdebug.h" />
<ClInclude Include="base\ntos\VERIFIER\vfdef.h" />
<ClInclude Include="base\ntos\VERIFIER\vfdevobj.h" />
<ClInclude Include="base\ntos\VERIFIER\vffilter.h" />
<ClInclude Include="base\ntos\VERIFIER\vfgeneric.h" />
<ClInclude Include="base\ntos\VERIFIER\vfinit.h" />
<ClInclude Include="base\ntos\VERIFIER\vfirp.h" />
<ClInclude Include="base\ntos\VERIFIER\vfirpdb.h" />
<ClInclude Include="base\ntos\VERIFIER\vfirplog.h" />
<ClInclude Include="base\ntos\VERIFIER\vfmacro.h" />
<ClInclude Include="base\ntos\VERIFIER\vfmajor.h" />
<ClInclude Include="base\ntos\VERIFIER\vfmessage.h" />
<ClInclude Include="base\ntos\VERIFIER\vfpacket.h" />
<ClInclude Include="base\ntos\VERIFIER\vfpnp.h" />
<ClInclude Include="base\ntos\VERIFIER\vfpower.h" />
<ClInclude Include="base\ntos\VERIFIER\vfpragma.h" />
<ClInclude Include="base\ntos\VERIFIER\vfprint.h" />
<ClInclude Include="base\ntos\VERIFIER\vfrandom.h" />
<ClInclude Include="base\ntos\VERIFIER\vfsettings.h" />
<ClInclude Include="base\ntos\VERIFIER\vfstack.h" />
<ClInclude Include="base\ntos\VERIFIER\vftriage.h" />
<ClInclude Include="base\ntos\VERIFIER\vfutil.h" />
<ClInclude Include="base\ntos\VERIFIER\vfwmi.h" />
<ClInclude Include="base\ntos\VERIFIER\vfzwapi.h" />
<ClInclude Include="base\ntos\wmi\mcaevent.h" />
<ClInclude Include="base\ntos\wmi\tracep.h" />
<ClInclude Include="base\ntos\wmi\wmikmp.h" />
<ClInclude Include="base\ntos\wmi\wmiumds.h" />
</ItemGroup>
<ItemGroup>
<None Include="base\ntos\ex\amd64\hifreqlk.asm" />
<None Include="base\ntos\ex\amd64\hrderror.asm" />
<None Include="base\ntos\ex\amd64\intrlock.asm" />
<None Include="base\ntos\ex\i386\intrlfst.asm" />
<None Include="base\ntos\ex\i386\intrlock.asm" />
<None Include="base\ntos\ex\i386\splocks.asm" />
<None Include="base\ntos\inc\em387.inc" />
<None Include="base\ntos\inc\fastsys.inc" />
<None Include="base\ntos\inc\irqli386.inc" />
<None Include="base\ntos\inc\mac386.inc" />
<None Include="base\ntos\init\amd64def.src" />
<None Include="base\ntos\init\i386def.src" />
<None Include="base\ntos\init\ntoskrnl.src" />
<None Include="base\ntos\ke\amd64\apcint.asm" />
<None Include="base\ntos\ke\amd64\callout.asm" />
<None Include="base\ntos\ke\amd64\clockint.asm" />
<None Include="base\ntos\ke\amd64\cpuid.asm" />
<None Include="base\ntos\ke\amd64\ctxswap.asm" />
<None Include="base\ntos\ke\amd64\dpcint.asm" />
<None Include="base\ntos\ke\amd64\idle.asm" />
<None Include="base\ntos\ke\amd64\intipi.asm" />
<None Include="base\ntos\ke\amd64\intsup.asm" />
<None Include="base\ntos\ke\amd64\miscs.asm" />
<None Include="base\ntos\ke\amd64\procstat.asm" />
<None Include="base\ntos\ke\amd64\profint.asm" />
<None Include="base\ntos\ke\amd64\services.stb" />
<None Include="base\ntos\ke\amd64\services.tab" />
<None Include="base\ntos\ke\amd64\start.asm" />
<None Include="base\ntos\ke\amd64\sysstubs.asm" />
<None Include="base\ntos\ke\amd64\systable.asm" />
<None Include="base\ntos\ke\amd64\table.stb" />
<None Include="base\ntos\ke\amd64\threadbg.asm" />
<None Include="base\ntos\ke\amd64\trap.asm" />
<None Include="base\ntos\ke\amd64\zero.asm" />
<None Include="base\ntos\ke\genxx.inc" />
<None Include="base\ntos\ke\i386\abiosa.asm" />
<None Include="base\ntos\ke\i386\callout.asm" />
<None Include="base\ntos\ke\i386\clockint.asm" />
<None Include="base\ntos\ke\i386\cpu.asm" />
<None Include="base\ntos\ke\i386\cpu.inc" />
<None Include="base\ntos\ke\i386\ctxswap.asm" />
<None Include="base\ntos\ke\i386\emv86.asm" />
<None Include="base\ntos\ke\i386\emxcptn.asm" />
<None Include="base\ntos\ke\i386\i386pcr.asm" />
<None Include="base\ntos\ke\i386\instemul.asm" />
<None Include="base\ntos\ke\i386\int.asm" />
<None Include="base\ntos\ke\i386\intsup.asm" />
<None Include="base\ntos\ke\i386\kimacro.inc" />
<None Include="base\ntos\ke\i386\ldtsup2.asm" />
<None Include="base\ntos\ke\i386\mi.inc" />
<None Include="base\ntos\ke\i386\mpipia.asm" />
<None Include="base\ntos\ke\i386\newsysbg.asm" />
<None Include="base\ntos\ke\i386\procstat.asm" />
<None Include="base\ntos\ke\i386\services.stb" />
<None Include="base\ntos\ke\i386\services.tab" />
<None Include="base\ntos\ke\i386\spindbg.asm" />
<None Include="base\ntos\ke\i386\spinlock.asm" />
<None Include="base\ntos\ke\i386\sysstubs.asm" />
<None Include="base\ntos\ke\i386\systable.asm" />
<None Include="base\ntos\ke\i386\table.stb" />
<None Include="base\ntos\ke\i386\threadbg.asm" />
<None Include="base\ntos\ke\i386\timindex.asm" />
<None Include="base\ntos\ke\i386\trap.asm" />
<None Include="base\ntos\ke\i386\zero.asm" />
<None Include="base\ntos\lpc\i386\lpcmove.asm" />
<None Include="base\ntos\mm\i386\pae.asm" />
<None Include="base\ntos\ps\amd64\psctxwrap.asm" />
<None Include="base\ntos\rtl\amd64\capture.asm" />
<None Include="base\ntos\rtl\amd64\chkstk.asm" />
<None Include="base\ntos\rtl\amd64\debugstb.asm" />
<None Include="base\ntos\rtl\amd64\movemem.asm" />
<None Include="base\ntos\rtl\amd64\slist.asm" />
<None Include="base\ntos\rtl\amd64\xcptmisc.asm" />
<None Include="base\ntos\rtl\i386\debug2.asm" />
<None Include="base\ntos\rtl\i386\ioaccess.asm" />
<None Include="base\ntos\rtl\i386\largeint.asm" />
<None Include="base\ntos\rtl\i386\movemem.asm" />
<None Include="base\ntos\rtl\i386\raise.asm" />
<None Include="base\ntos\rtl\i386\slist.asm" />
<None Include="base\ntos\rtl\i386\stkwalk.asm" />
<None Include="base\ntos\rtl\i386\stringsp.asm" />
<None Include="base\ntos\rtl\i386\xcptmisc.asm" />
<None Include="base\ntos\rtl\mp" />
<None Include="base\ntos\VDM\i386\vdm.inc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

2039
WRK.vcxproj.filters Normal file

File diff suppressed because it is too large Load Diff

3
WRKDebug.bat Normal file
View File

@ -0,0 +1,3 @@
call WRKEnv.bat %1
windbg %windbgargs%

24
WRKEnv.bat Normal file
View File

@ -0,0 +1,24 @@
@echo off
rem
rem This batch file sets the following WRK build and debug environment variables:
rem wrkarch - the target architecture, "x86" or "amd64"; 1st parameter of the batch file; default is x86
rem path - the search path, modified to include the tools for respective target architecture
rem and Windows Debugger (WinDbg)
rem windbgargs - the arguments for WinDbg
rem _NT_SYMBOL_PATH - symbol path for WinDbg
rem
rem Usage: copy this file to your hard drive and edit it to reflect your installation;
rem open a console window and run this batch file;
rem run command "set" to make sure the environment is set properly;
rem now you can build WRK and run Windbg from this console window.
rem
IF DEFINED wrkarch goto finish
SET wrkarch=x86
IF NOT [%1] EQU [] SET wrkarch=%1
SET path=%cd%\tools\%wrkarch%;%path%;C:\Program Files\Debugging Tools for Windows
SET windbgargs=-k com:pipe,port=\\.\pipe\debug,resets=0,reconnect
SET _NT_SYMBOL_PATH="%cd%\base\ntos\build\exe;%cd%\WS03SP1HALS\x86\halacpim"
@title WRK %wrkarch%
:finish

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

109
base/inc/ntdlltrc.h Normal file
View File

@ -0,0 +1,109 @@
/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
NtdllTracer.h
Abstract:
This file contains structures and functions definitions used in Ntdll
events tracing
--*/
#ifndef _NTDLL_WMI_TRACE_
#define _NTDLL_WMI_TRACE_
#define MEMORY_FROM_LOOKASIDE 1 //Activity from LookAside
#define MEMORY_FROM_LOWFRAG 2 //Activity from Low Frag Heap
#define MEMORY_FROM_MAINPATH 3 //Activity from Main Code Path
#define MEMORY_FROM_SLOWPATH 4 //Activity from Slow Code Path
#define LOG_LOOKASIDE 0x00000001 //Bit for LookAside trace
#define FAILED_TLSINDEX -1
#define MAX_PID 10
#ifndef UserSharedData
#define UserSharedData USER_SHARED_DATA
#endif
#define IN_TRACING 0x00000001 // Flag to see if this thread is tracing.
extern BOOLEAN bNtdllTrace;
#define IsCritSecLogging(CriticalSection) ((USER_SHARED_DATA->TraceLogging & ENABLECRITSECTRACE) \
&&(bNtdllTrace || GlobalCounter != (USER_SHARED_DATA->TraceLogging >> 16)) \
&&((HandleToUlong(NtCurrentTeb()->EtwTraceData) & IN_TRACING) != IN_TRACING))
extern
ULONG GlobalCounter;
#define IsHeapLogging(HeapHandle) (USER_SHARED_DATA->TraceLogging & ENABLEHEAPTRACE &&\
(bNtdllTrace || GlobalCounter != (USER_SHARED_DATA->TraceLogging >> 16))&& \
((HandleToUlong(NtCurrentTeb()->EtwTraceData) & IN_TRACING) != IN_TRACING))
//
// When calling from deep inside heap allocation routines, we do not want to
// be initializing ETW process heap since that gets into recursive behaviour.
//
#define IsDeepHeapLogging(HeapHandle) (USER_SHARED_DATA->TraceLogging & ENABLEHEAPTRACE &&\
(bNtdllTrace || GlobalCounter != (USER_SHARED_DATA->TraceLogging >> 16))&& \
(EtwpProcessHeap != NULL) && \
((HandleToUlong(NtCurrentTeb()->EtwTraceData) & IN_TRACING) != IN_TRACING))
typedef struct _THREAD_LOCAL_DATA THREAD_LOCAL_DATA, *PTHREAD_LOCAL_DATA, **PPTHREAD_LOCAL_DATA;
typedef struct _THREAD_LOCAL_DATA {
PTHREAD_LOCAL_DATA FLink; //Forward Link
PTHREAD_LOCAL_DATA BLink; //Backward Link
PWMI_BUFFER_HEADER pBuffer; //Pointer to thread buffer info.
LONG ReferenceCount;
} THREAD_LOCAL_DATA, *PTHREAD_LOCAL_DATA, **PPTHREAD_LOCAL_DATA;
extern
PVOID EtwpProcessHeap;
#ifndef EtwpGetCycleCount
__int64
EtwpGetCycleCount();
#endif // EtwpGetCycleCount
void
ReleaseBufferLocation(PTHREAD_LOCAL_DATA pThreadLocalData);
NTSTATUS
AcquireBufferLocation(PVOID *pEvent, PPTHREAD_LOCAL_DATA pThreadLocalData, PUSHORT ReqSize);
typedef struct _NTDLL_EVENT_COMMON {
PVOID Handle; //Handle of Heap
}NTDLL_EVENT_COMMON, *PNTDLL_EVENT_COMMON;
typedef struct _NTDLL_EVENT_HANDLES {
RTL_CRITICAL_SECTION CriticalSection; //Critical section
ULONG dwTlsIndex; //TLS Index
TRACEHANDLE hRegistrationHandle; //Registration Handle used for Unregistration.
TRACEHANDLE hLoggerHandle; //Handle to Trace Logger
PTHREAD_LOCAL_DATA pThreadListHead; //Link List that contains all threads info invovled in tracing.
}NTDLL_EVENT_HANDLES, *PNTDLL_EVENT_HANDLES, **PPNTDLL_EVENT_HANDLES;
extern LONG TraceLevel;
extern PNTDLL_EVENT_HANDLES NtdllTraceHandles;
extern RTL_CRITICAL_SECTION UMLogCritSect;
extern RTL_CRITICAL_SECTION PMCritSect;
extern RTL_CRITICAL_SECTION LoaderLock;
#endif //_NTDLL_WMI_TRACE_

View File

@ -0,0 +1 @@
*** This file is here solely to preserve the directory structure when WRK is xcopy'ed ***

76
base/ntos/BUILD/WARNING.h Normal file
View File

@ -0,0 +1,76 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
// If you do not agree to the terms, do not use the code.
//
#pragma warning(3:4092) // sizeof returns 'unsigned long'
#pragma warning(4:4096) // '__cdecl' must be used with '...'
#pragma warning(4:4121) // structure is sensitive to alignment
#pragma warning(3:4125) // decimal digit in octal sequence
#pragma warning(3:4130) // logical operation on address of string constant
#pragma warning(3:4132) // const object should be initialized
#if _DBG_MEMCPY_INLINE_
#pragma warning(disable:4163) // not available as an intrinsic function
#endif
#pragma warning(4:4206) // Source File is empty
#pragma warning(4:4101) // Unreferenced local variable
#pragma warning(4:4208) // delete[exp] - exp evaluated but ignored
#pragma warning(3:4212) // function declaration used ellipsis
#pragma warning(3:4242) // convertion possible loss of data
#pragma warning(4:4267) // convertion from size_t to smaller type
#pragma warning(4:4312) // conversion to type of greater size
#pragma warning(disable:4324) // structure padded due to __declspec(align())
#pragma warning(error:4700) // Local used w/o being initialized
#pragma warning(error:4259) // pure virtual function was not defined
#pragma warning(disable:4071) // no function prototype given - formals unspecified
#pragma warning(error:4013) // function' undefined - assuming extern returning int
#pragma warning(error:4551) // Function call missing argument list
#pragma warning(error:4806) // unsafe operation involving type 'bool'
#pragma warning(4:4509) // use of SEH with destructor
#pragma warning(4:4177) // pragma data_seg s/b at global scope
#pragma warning(disable:4274) // #ident ignored
#pragma warning(disable:4786) // identifier was truncated to 255 characters in debug information.
#pragma warning(disable:4503) // decorated name length exceeded, name was truncated.
#pragma warning(disable:4263) // Derived override doesn't match base - who cares...
#pragma warning(disable:4264) // base function is hidden - again who cares.
#pragma warning(disable:4710) // Function marked as inline - wasn't
#pragma warning(disable:4917) // A GUID can only be associated with a class, interface or namespace
#pragma warning(error:4552) // <<, >> ops used to no effect (probably missing an = sign)
#pragma warning(error:4553) // == op used w/o effect (probably s/b an = sign)
#pragma warning(3:4288) // nonstandard extension used (loop counter)
#pragma warning(3:4532) // jump out of __finally block
#pragma warning(error:4312) // cast of 32-bit int to 64-bit ptr
#pragma warning(error:4296) // expression is always true/false
#pragma warning(3:4546) // function call before comma missing argument list
// disable until __noop(arg,arg,arg) doesn't generate false hits.
// #pragma warning(3:4547) // '<' : operator before comma has no effect; expected operator with side-effect
// #pragma warning(3:4548) // expression before comma has no effect; expected expression with side-effect
#pragma warning(disable:4197) // illegal use of const/volatile: qualifier ignored (disabled until sources fixed)
#pragma warning(disable:4675) // picked overload found via Koenig lookup
#pragma warning(disable:4356) // static member cannot be initialized via derived class
#ifndef __cplusplus
#undef try
#undef except
#undef finally
#undef leave
#define try __try
#define except __except
#define finally __finally
#define leave __leave
#endif
#if _MSC_VER <= 1400
#pragma warning(disable: 4068) // turn off unknown pragma warning so prefast pragmas won't show
// show up in build.wrn/build.err
#endif
#if defined(_M_IX86) && _MSC_FULL_VER >= 13102154
#define __TYPENAME typename
#else
#define __TYPENAME
#endif

66
base/ntos/BUILD/makefile Normal file
View File

@ -0,0 +1,66 @@
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
# If you do not agree to the terms, do not use the code.
#
kernel = wrk$(machine)
asobjs=
ccobjs=
ccarchobjs=
default: kernelexp kernellib kernelexe
nodefault=1
!include $(ntos)\BUILD\makefile.build
linklibpath = -LIBPATH:$(topobj) -LIBPATH:PREBUILT\$(targ)
ntoswrklib = ntoswrk.lib
ntosarchlib = ntosarch.lib
bootlibs = bootvid.lib sdbapint.lib kdcom.lib
fullkernel = EXE\$(kernel)
# kernel link definitions
LINKFLAGS = -IGNORE:4087,4001,4010,4037,4039,4065,4070,4078,4087,4089,4221,4198 -WX -NODEFAULTLIB -machine:$(machine) $(linklibpath)
LINK = link.exe -nologo
LINKEDIT = link.exe -edit -nologo
LIB = $(LIB) $(linklibpath)
!if "$(targ)" == "i386"
archlinkopts = -safeseh -functionpadmin:5 -debugtype:cv,fixup -STACK:0x40000,0x2000 -align:0x1000
hotpatch = -stub:PREBUILT\i386\stub512.com
entrypoint = KiSystemStartup@4
!else
archlinkopts = -functionpadmin:6 -debugtype:cv,fixup,pdata -STACK:0x80000,0x2000
hotpatch = PREBUILT\amd64\hotpatch.obj
LINKFLAGS = -IGNORE:4108,4088,4218,4218,4235 $(LINKFLAGS)
LIBFLAGS = -IGNORE:4108,4088,4218,4218,4235 $(LIBFLAGS)
entrypoint = KiSystemStartup
!endif
ntosmerge = -merge:PAGECONST=PAGE -merge:INITCONST=INIT -merge:INITDATA=INIT -merge:PAGELKCONST=PAGELK \
-merge:PAGEVRFY_CONST=PAGEVRFY -MERGE:_PAGE=PAGE -MERGE:_TEXT=.text -merge:.rdata=.text
ntosversion = -release -version:5.2 -osversion:5.2 -subsystem:native,5.02
ntoslinkopts = $(ntosversion) $(ntosmerge) -SECTION:INIT,d -OPT:REF -OPT:ICF -INCREMENTAL:NO \
-FULLBUILD -debug $(archlinkopts) -opt:nowin98 -pdbcompress -driver
kernelexp:
copy ..\init\ntoskrnl.src+..\init\$(targ)def.src $(OBJ)\$(kernel).pp
$(CC) $(CFLAGS0) -EP $(OBJ)\$(kernel).pp > $(fullkernel).def
-del $(OBJ)\$(kernel).pp
$(LIB) $(LIBFLAGS) -IGNORE:4001 $(OBJ)\*.lib $(ntoswrklib) -def:$(fullkernel).def -out:$(fullkernel).lib
kernellib:
$(LIB) $(fullkernel).lib $(ntosarchlib) -out:$(fullkernel).lib
kernelexe:
$(LINK) $(LINKFLAGS) $(ntoslinkopts) -out:$(fullkernel).exe -map:$(fullkernel).map -pdb:$(fullkernel).pdb -entry:$(entrypoint) \
$(hotpatch) PREBUILT\$(targ)\ntoskrnl.res $(OBJ)\ntkrnlmp.obj $(OBJ)\*.lib $(ntoswrklib) hal.lib $(fullkernel).exp $(bootlibs)
$(LINKEDIT) -section:.rsrc,!d $(fullkernel).exe

View File

@ -0,0 +1,83 @@
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
# If you do not agree to the terms, do not use the code.
#
!if !defined(ntos) || !defined(pub) || !defined(module) || !defined(topobj) || !defined(targ) || ("$(targ)" != "i386" && "$(targ)" != "amd64")
!ERROR Usage: nmake ntos=ntosdir pub=pubdir module=ntossubdir targ=[i386|amd64]
!endif
!if "$(targ)" == "i386"
targdefs = -D_X86_=1 -Di386=1 -DSTD_CALL -DFPO=0
targaopts = -safeseh -coff -Zm
targcopts = -Gm- -Gz -GX- -G6 -Ze -Gi- -QIfdiv- -Z7 -Oxs -Oy-
targlopts =
machine = x86
archml = ml
!else
targdefs = -D_WIN64 -D_AMD64_ -DAMD64
targaopts =
targcopts = -Wp64 -Oxt -EHs-c- /Oxt -Gs12288 -GL- -MT -U_MT
targlopts = -IGNORE:4108,4088,4218,4218,4235
machine = amd64
archml = ml64
!endif
tempdir = $(topobj)\temp
ipub = $(pub)\internal
baseinc = $(ntos)\..\inc
incs = -I..\$(targ) -I. -I$(ntos)\$(module) -I$(ntos)\inc -I$(pub)\ddk\inc -I$(ipub)\ds\inc -I$(ipub)\sdktools\inc \
-I$(baseinc) -I$(ipub)\base\inc -I$(pub)\sdk\inc -I$(pub)\sdk\inc\crt -I$(pub)\halkit\inc
defs = $(targdefs) -DCONDITION_HANDLING=1 -DNT_INST=0 -DWIN32=100 -D_NT1X_=100 -DWINNT=1 \
-D_WIN32_WINNT=0x0502 -DWINVER=0x0502 -D_WIN32_IE=0x0603 -DWIN32_LEAN_AND_MEAN=1 -DDBG=0 -DDEVL=1 \
-D__BUILDMACHINE__=WRK1.2(university) -DNDEBUG -D_NTSYSTEM_ -DNT_SMT -DNTOS_KERNEL_RUNTIME=1
aopts = -Cx -Zi $(targaopts)
copts = -Zl -Zp8 -Gy -cbstring -W3 -WX -GR- -GF -GS $(targcopts)
compilerwarnings = -FI$(ntos)\BUILD\WARNING.h
AS = $(archml).exe -nologo
AFLAGS = $(aopts) $(incs) -Foobj$(targ)\ $(defs) $(specialaflags)
CC = cl.exe -nologo
CFLAGS0 = $(copts) $(incs) -Foobj$(targ)\ $(defs) $(specialcflags)
CFLAGS = $(CFLAGS0) $(compilerwarnings)
LIBFLAGS = $(targlopts) -IGNORE:4010,4037,4039,4065,4070,4078,4087,4089,4221,4198 -WX -nodefaultlib -machine:$(machine)
LIB = lib.exe -nologo
OBJ = obj$(targ)
!ifndef nodefault
default: build $(localtargets)
!endif
# assembly files
{..\$(targ)\}.asm{$(OBJ)\}.obj::
$(AS) $(AFLAGS) -c $<
# arch-specific C files
{..\$(targ)\}.c{$(OBJ)\}.obj::
$(CC) $(CFLAGS) -c $<
# C files
{..\}.c{$(OBJ)\}.obj::
$(CC) $(CFLAGS) -c $<
# library
$(topobj)\$(library).lib: $(asobjs) $(ccarchobjs) $(ccobjs)
@echo linking $(library).lib
$(LIB) $(LIBFLAGS) -out:$@ $**
# pseudo targets
build: $(topobj)\$(library).lib
clean: clean0 $(localclean)
clean0:
-del $(asobjs) $(ccarchobjs) $(ccobjs) $(extraobjs)

View File

@ -0,0 +1 @@
*** This file is here solely to preserve the directory structure when WRK is xcopy'ed ***

View File

@ -0,0 +1 @@
*** This file is here solely to preserve the directory structure when WRK is xcopy'ed ***

340
base/ntos/VDM/i386/vdm.inc Normal file
View File

@ -0,0 +1,340 @@
;++
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
; You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
; If you do not agree to the terms, do not use the code.
;
;
; Module Name:
;
; vdm.inc
;
; Abstract:
;
; This module contains the structure and constant definitions for
; the vdm component
;--
.386p
TRUE equ 1
FALSE equ 0
;
; Macro's to only do locked memory operations on MP systems
;
IFDEF NT_UP
MPLOCK equ <>
ELSE
MPLOCK equ <lock>
ENDIF
page , 132
subttl "Macro to dispatch exception"
;++
;
; Macro Description:
;
; This macro allocates exception record on stack, sets up exception
; record using specified parameters and finally sets up arguments
; and calls _KiDispatchException.
;
; Arguments:
;
; ExcepCode - Exception code to put into exception record
; ExceptFlags - Exception flags to put into exception record
; ExceptRecord - Associated exception record
; ExceptAddress - Addr of instruction which the hardware exception occurs
; NumParms - Number of additional parameters
; ParameterList - the additional parameter list
;
; Return Value:
;
; None.
;
;--
DISPATCH_EXCEPTION macro ExceptCode, ExceptFlags, ExceptRecord, ExceptAddress,\
NumParms, ParameterList
local de10, de20
; Set up exception record for raising exception
?i = 0
sub esp, ExceptionRecordSize + NumParms * 4
; allocate exception record
mov dword ptr [esp]+ErExceptionCode, ExceptCode
; set up exception code
mov dword ptr [esp]+ErExceptionFlags, ExceptFlags
; set exception flags
mov dword ptr [esp]+ErExceptionRecord, ExceptRecord
; set associated exception record
mov dword ptr [esp]+ErExceptionAddress, ExceptAddress
mov dword ptr [esp]+ErNumberParameters, NumParms
; set number of parameters
IRP z, <ParameterList>
mov dword ptr [esp]+(ErExceptionInformation+?i*4), z
?i = ?i + 1
ENDM
; set up arguments and call _KiDispatchException
mov ecx, esp ; (ecx)->exception record
test dword ptr [ebp]+TsEFlags,EFLAGS_V86_MASK
jz de10
mov eax,0FFFFh
jmp de20
de10: mov eax,[ebp]+TsSegCs
de20: and eax,MODE_MASK
; 1 - set first chance TRUE
; eax - PreviousMode
; ebp - trap frame addr
; 0 - Null exception frame
; ecx - exception record addr
; dispatchexception as appropriate
stdCall _KiDispatchException, <ecx, 0, ebp, eax, 1>
add esp,ExceptionRecordSize + NumParms*4
ENDM
;
; Prefix Flags
;
PREFIX_ES equ 00000100h
PREFIX_CS equ 00000200h
PREFIX_SS equ 00000400h
PREFIX_DS equ 00000800h
PREFIX_FS equ 00001000h
PREFIX_GS equ 00002000h
PREFIX_OPER32 equ 00004000h
PREFIX_ADDR32 equ 00008000h
PREFIX_LOCK equ 00010000h
PREFIX_REPNE equ 00020000h
PREFIX_REP equ 00040000h
PREFIX_SEG_ALL equ 00003f00h
NUM_OPCODE equ 255
;
; Reginfo structure
;
RegInfo struc
RiSegSs dd 0
RiEsp dd 0
RiEFlags dd 0
RiSegCs dd 0
RiEip dd 0
RiTrapFrame dd 0
RiCsLimit dd 0
RiCsBase dd 0
RiCsFlags dd 0
RiSsLimit dd 0
RiSsBase dd 0
RiSsFlags dd 0
RiPrefixFlags dd 0
RiOperand dd 0
RegInfo ends
REGINFOSIZE EQU 56
MAX_VDM_ADDR EQU 0FFFFFFH
DR7_GLOBAL EQU 002AAH
;
;Fast Read/Write Defines
;
SVC_DEMFASTREAD equ 42h
SVC_DEMFASTWRITE equ 43h
DOS_BOP equ 50h
;
;
; Size of Exception Record
;
ExceptionRecordSize = (ErNumberParameters + 4 + 3) AND 0fffffffcH ;
;
; Magic value
;
OPCODE_MAGIC equ 00f5ah
;++
; diBEGIN - BEGIN index table
;
; ENTRY name = name of di table
; badindex = local label for unspecified entries
;
; EXIT ?sindex = specific entry index
; ?badindex = default index for unspecified entries
;--
diBEGIN macro name,badindex ;; Beginning of dispatch table
?sopc = 0
?badindex = badindex
name label byte ;; Start of dispatch table
endm
;++
; dtI - SPECIFIC index table entry
;
; ENTRY opc = opcode value
; index = INDEX_ value corresponding to opcode
; ?badindex = unspecified entry index
; ?sopc = specific entry index
;
; EXIT Unspecified entries prior to "index" filled in;
; Specified entry filled in.
; ?sopc = next index to fill in;
;--
dtI macro opc,index ;; Specific entry in dispatch table
if ?sopc gt opc
%out dtI: opcode out of order
.err
else
if ?sopc lt opc ;; Fill unspecified entries
rept opc - ?sopc
db ?badindex
endm
endif
db index ;; Specified entry
?sopc = opc+1 ;; Set new start index
endif
endm
;++
; diEND - END index table
;
; ENTRY index = highest entry in table
; ?sopc = specific entry index
;
; EXIT rest of the table filled in
;--
diEND macro index ;; End of dispatch table
if ?sopc lt index ;; Fill in rest of table
rept index - ?sopc
db ?badindex
endm
db ?badindex ;; fill in last entry of table!
endif
endm
;++
; dtBEGIN - BEGIN dispatch table
;
; ENTRY name = name of dt table
; badaddr = local label for unspecified entries
;
; EXIT ?sindex = specific entry index
; ?badaddr = default handler for unspecified entries
;--
dtBEGIN macro name,badaddr ;; Beginning of dispatch table
?sindex = 0
?badaddr = badaddr
name label dword ;; Start of dispatch table
endm
;++
; dtS - SPECIFIC dispatch table entry
;
; ENTRY index = index of entry
; addr = address of handler
; ?badaddr = unspecified entry handler
; ?sindex = specific entry index
;
; EXIT Unspecified entries prior to "index" filled in;
; Specified entry filled in.
; ?sindex = next index to fill in;
;--
dtS macro index,addr ;; Specific entry in dispatch table
if ?sindex gt index
%out dtS: index out of order
.err
else
if ?sindex lt index ;; Fill unspecified entries
rept index - ?sindex
dd offset FLAT:?badaddr
endm
endif
dd offset FLAT:addr ;; Specified entry
?sindex = index+1 ;; Set new start index
endif
endm
;++
; dtEND - END dispatch table
;
; ENTRY index = highest entry in table
; ?sindex = specific entry index
;
; EXIT rest of the table filled in
;--
dtEND macro index ;; End of dispatch table
if ?sindex lt index ;; Fill in rest of table
rept index - ?sindex
dd offset FLAT:?badaddr
endm
dd offset FLAT:?badaddr ;; fill in last entry of table!
endif
endm
;++
; CsToLinearPM
;
;--
CsToLinearPM macro sel, erraddr
lea eax,[esi].RiCsLimit
push eax
lea eax,[esi].RiCsBase
push eax
lea eax,[esi].RiCsFlags
push eax
push sel
call _Ki386GetSelectorParameters@16
or al,al
jz erraddr
test [esi].RiCsFlags,SEL_TYPE_EXECUTE
jz erraddr
test [esi].RiCsFlags,SEL_TYPE_2GIG
jz @f
; Correct limit value for granularity
shl [esi].RiCsLimit,12
or [esi].RiCsLimit,0FFFh
@@:
endm
;++
; CsToLinearV86
;
;--
CsToLinearV86 macro
movzx eax,word ptr [esi].RiSegCs
shl eax,4
mov [esi].RiCsBase,eax
mov [esi].RiCsLimit,0FFFFh
mov [esi].RiCsFlags,0
endm

View File

@ -0,0 +1,28 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
halverifier.c
Abstract:
This module contains the routines to verify hal usage & apis.
--*/
#ifndef _HAL_VERIFIER_
#define _HAL_VERIFIER_
VOID
VfHalVerifierInitialize(
VOID
);
#endif

View File

@ -0,0 +1,66 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfbugcheck.h
Abstract:
This header defines the prototypes and constants required for verifier
bugchecks.
--*/
#ifndef _VFBUGCHECK_H_
#define _VFBUGCHECK_H_
extern LONG IovpInitCalled;
#define KDASSERT(x) { if (KdDebuggerEnabled) { ASSERT(x) ; } }
#define ASSERT_SPINLOCK_HELD(x)
#define DCPARAM_ROUTINE 0x00000001
#define DCPARAM_IRP 0x00000008
#define DCPARAM_IRPSNAP 0x00000040
#define DCPARAM_DEVOBJ 0x00000200
#define DCPARAM_STATUS 0x00001000
#define DCPARAM_ULONG 0x00008000
#define DCPARAM_PVOID 0x00040000
#define WDM_FAIL_ROUTINE(ParenWrappedParamList) \
{ \
if (IovpInitCalled) { \
VfBugcheckThrowIoException##ParenWrappedParamList;\
} \
}
VOID
FASTCALL
VfBugcheckInit(
VOID
);
NTSTATUS
VfBugcheckThrowIoException(
IN DCERROR_ID MessageIndex,
IN ULONG MessageParameterMask,
...
);
NTSTATUS
VfBugcheckThrowException(
IN PVFMESSAGE_TEMPLATE_TABLE MessageTable OPTIONAL,
IN VFMESSAGE_ERRORID MessageID,
IN PCSTR MessageParamFormat,
IN va_list * MessageParameters
);
#endif // _VFBUGCHECK_H_

View File

@ -0,0 +1,28 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfddi.h
Abstract:
This header contains prototypes for verifier device driver interfaces.
--*/
VOID
VfDdiInit(
VOID
);
VOID
VfDdiExposeWmiObjects(
VOID
);

View File

@ -0,0 +1,440 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfdeadlock.h
Abstract:
Detect deadlocks in arbitrary synchronization objects.
--*/
#ifndef _VF_DEADLOCK_
#define _VF_DEADLOCK_
//
// Deadlock detection package initialization.
//
VOID
VfDeadlockDetectionInitialize(
);
//
// Functions called from IovCallDriver (driver verifier replacement for
// IoCallDriver) just before and after the real call to the driver is made.
//
BOOLEAN
VfDeadlockBeforeCallDriver (
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
VOID
VfDeadlockAfterCallDriver (
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp,
IN BOOLEAN PagingIrp
);
//
// Maximum depth of stack traces captured.
//
#define VI_MAX_STACK_DEPTH 8
#define NO_OF_DEADLOCK_PARTICIPANTS 32
//
// VI_DEADLOCK_NODE
//
typedef struct _VI_DEADLOCK_NODE {
//
// Node representing the acquisition of the previous resource.
//
struct _VI_DEADLOCK_NODE * Parent;
//
// Node representing the next resource acquisitions, that are
// done after acquisition of the current resource.
//
struct _LIST_ENTRY ChildrenList;
//
// Field used to chain siblings in the tree. A parent node has the
// ChildrenList field as the head of the children list that is chained
// with the Siblings field.
//
struct _LIST_ENTRY SiblingsList;
union {
//
// List of nodes representing the same resource acquisition
// as the current node but in different contexts (lock combinations).
//
struct _LIST_ENTRY ResourceList;
//
// Used to chain free nodes. This is used only after the node has
// been deleted (resource was freed). Nodes are kept in a cache
// to reduce contention for the kernel pool.
//
struct _LIST_ENTRY FreeListEntry;
};
//
// Back pointer to the descriptor for this resource.
//
struct _VI_DEADLOCK_RESOURCE * Root;
//
// When we find a deadlock, we keep this info around in order to
// be able to identify the parties involved who have caused
// the deadlock.
//
struct _VI_DEADLOCK_THREAD * ThreadEntry;
//
// Fields used for decision making within the deadlock analysis
// algorithm.
//
// Active: 1 if the node represents a resource currently acquired,
// 0 if resource was acquired in the past.
//
// OnlyTryAcquiredUsed: 1 if resource was always acquired with TryAcquire.
// 0 if at least once normal acquire was used. A node that uses
// only TryAcquire cannot be involved in a deadlock.
//
// ReleasedOutOfOrder: 1 if the resource was at least once released
// out of order. The flag is used while looking for cycles because
// this type of nodes will appear as part of the cycle but there is
// no deadlock.
//
// SequenceNumber: field that gets a unique stamp during each deadlock
// analysis run. It helps figure out if the node was touched
// already in the current graph traversal.
//
struct {
ULONG Active : 1;
ULONG OnlyTryAcquireUsed : 1;
ULONG ReleasedOutOfOrder : 1;
ULONG SequenceNumber : 29;
};
//
// Stack traces for the resource acquisition moment.
// Used when displaying deadlock proofs. On free builds
// anything other than the first entry (return address)
// may be bogus in case stack trace capturing failed.
//
PVOID StackTrace[VI_MAX_STACK_DEPTH];
PVOID ParentStackTrace[VI_MAX_STACK_DEPTH];
} VI_DEADLOCK_NODE, *PVI_DEADLOCK_NODE;
//
// VI_DEADLOCK_RESOURCE
//
typedef struct _VI_DEADLOCK_RESOURCE {
//
// Resource type (mutex, spinlock, etc.).
//
VI_DEADLOCK_RESOURCE_TYPE Type;
//
// Resource flags
//
// NodeCount : number of resource nodes created for this resource.
//
// RecursionCount : number of times this resource has been recursively acquired
// It makes sense to put this counter in the resource because as long as
// resource is acquired only one thread can operate on it.
//
struct {
ULONG NodeCount : 16;
ULONG RecursionCount : 16;
};
//
// The address of the synchronization object used by the kernel.
//
PVOID ResourceAddress;
//
// The thread that currently owns the resource. The field is
// null if nobody owns the resource.
//
struct _VI_DEADLOCK_THREAD * ThreadOwner;
//
// List of resource nodes representing acquisitions of this resource.
//
LIST_ENTRY ResourceList;
union {
//
// List used for chaining resources from a hash bucket.
//
LIST_ENTRY HashChainList;
//
// Used to chain free resources. This list is used only after
// the resource has been freed and we put the structure
// into a cache to reduce kernel pool contention.
//
LIST_ENTRY FreeListEntry;
};
//
// Stack trace of the resource creator. On free builds we
// may have here only a return address that is bubbled up
// from verifier thunks.
//
PVOID StackTrace [VI_MAX_STACK_DEPTH];
//
// Stack trace for last acquire
//
PVOID LastAcquireTrace [VI_MAX_STACK_DEPTH];
//
// Stack trace for last release
//
PVOID LastReleaseTrace [VI_MAX_STACK_DEPTH];
} VI_DEADLOCK_RESOURCE, * PVI_DEADLOCK_RESOURCE;
//
// VI_DEADLOCK_THREAD
//
typedef struct _VI_DEADLOCK_THREAD {
//
// Kernel thread address
//
PKTHREAD Thread;
//
// The node representing the last resource acquisition made by
// this thread.
//
//
// We have separate graph branches for spinlocks and other types
// of locks (fast mutex, mutex). The thread keeps a list of both types
// so that we can properly release locks
//
PVI_DEADLOCK_NODE CurrentSpinNode;
PVI_DEADLOCK_NODE CurrentOtherNode;
union {
//
// Thread list. It is used for chaining into a hash bucket.
//
LIST_ENTRY ListEntry;
//
// Used to chain free nodes. The list is used only after we decide
// to delete the thread structure (possibly because it does not
// hold resources anymore). Keeping the structures in a cache
// reduces pool contention.
//
LIST_ENTRY FreeListEntry;
};
//
// Count of resources currently acquired by a thread. When this becomes
// zero the thread will be destroyed. The count goes up during acquire
// and down during release.
//
ULONG NodeCount;
//
// This counter is used to count how many IoCallDriver() calls with
// paging IRPs are active for this thread. This information is necessary
// to decide if we should temporarily disable deadlock verification
// to avoid known lack of lock hierarchy issues in file system drivers.
//
ULONG PagingCount;
} VI_DEADLOCK_THREAD, *PVI_DEADLOCK_THREAD;
//
// Deadlock verifier globals
//
typedef struct _VI_DEADLOCK_GLOBALS {
//
// Structure counters: [0] - current, [1] - maximum
//
ULONG Nodes[2];
ULONG Resources[2];
ULONG Threads[2];
//
// Maximum times for Acquire() and Release() in ticks.
//
LONGLONG TimeAcquire;
LONGLONG TimeRelease;
//
// Total number of kernel pool bytes used by the deadlock verifier
//
SIZE_T BytesAllocated;
//
// Resource and thread collection.
//
PLIST_ENTRY ResourceDatabase;
PLIST_ENTRY ThreadDatabase;
//
// How many times ExAllocatePool failed on us?
// If this is >0 we stop deadlock verification.
//
ULONG AllocationFailures;
//
// How many nodes have been trimmed when we decided to forget
// partially the history of some resources.
//
ULONG NodesTrimmedBasedOnAge;
ULONG NodesTrimmedBasedOnCount;
//
// Deadlock analysis statistics
//
ULONG NodesSearched;
ULONG MaxNodesSearched;
ULONG SequenceNumber;
ULONG RecursionDepthLimit;
ULONG SearchedNodesLimit;
ULONG DepthLimitHits;
ULONG SearchLimitHits;
//
// Number of times we have to exhonerate a deadlock because
// it was protected by a common resource (e.g. thread 1 takes ABC,
// thread 2 takes ACB -- this will get flagged initially by our algorithm
// since B&C are taken out of order but is not actually a deadlock.
//
ULONG ABC_ACB_Skipped;
ULONG OutOfOrderReleases;
ULONG NodesReleasedOutOfOrder;
#if DBG
//
// How many locks are held simultaneously while the system is running?
//
ULONG NodeLevelCounter[8];
ULONG GraphNodes[8];
#endif
ULONG TotalReleases;
ULONG RootNodesDeleted;
//
// Used to control how often we delete portions of the dependency
// graph.
//
ULONG ForgetHistoryCounter;
//
// How often was a worker items dispatched to trim the
// pool cache.
//
ULONG PoolTrimCounter;
//
// Caches of freed structures (thread, resource, node) used to
// decrease kernel pool contention.
//
LIST_ENTRY FreeResourceList;
LIST_ENTRY FreeThreadList;
LIST_ENTRY FreeNodeList;
ULONG FreeResourceCount;
ULONG FreeThreadCount;
ULONG FreeNodeCount;
//
// Resource address that caused the deadlock
//
PVOID Instigator;
//
// Number of participants in the deadlock
//
ULONG NumberOfParticipants;
//
// List of the nodes that participate in the deadlock
//
PVI_DEADLOCK_NODE Participant [NO_OF_DEADLOCK_PARTICIPANTS];
LOGICAL CacheReductionInProgress;
} VI_DEADLOCK_GLOBALS, *PVI_DEADLOCK_GLOBALS;
#endif

View File

@ -0,0 +1,31 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfdebug.h
Abstract:
This header contains debugging macros used by the driver verifier code.
--*/
extern ULONG VfSpewLevel;
#if DBG
#define VERIFIER_DBGPRINT(txt,level) \
{ \
if (VfSpewLevel>(level)) { \
DbgPrint##txt; \
}\
}
#else
#define VERIFIER_DBGPRINT(txt,level)
#endif

View File

@ -0,0 +1,60 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfdef.h
Abstract:
This header collects together the various files necessary to create a basic
set of definitions for the verifier.
--*/
//
// Disable W4 level warnings generated by public headers.
//
#include "vfpragma.h"
#include "ntos.h"
#include "vfdebug.h"
#include "vfmacro.h"
#include "vfinit.h"
#include "vfsettings.h"
#include "vfmessage.h"
#include "vfbugcheck.h"
#include "vfprint.h"
#include "vfutil.h"
#include "vfstack.h"
#include "vftriage.h"
#include "vfirp.h"
#include "vfirpdb.h"
#include "vfirplog.h"
#include "vfdevobj.h"
#include "vfpacket.h"
#include "halverifier.h"
#include "vfdeadlock.h"
#include "..\io\trackirp.h"
#include "..\io\sessnirp.h"
#include "..\ob\obvutil.h"
#include "..\io\iovutil.h"
#include "..\io\pnpmgr\ppvutil.h"
#include "vffilter.h"
#include "vfmajor.h"
#include "vfpnp.h"
#include "vfpower.h"
#include "vfwmi.h"
#include "vfgeneric.h"
#include "vfrandom.h"
#include "vfddi.h"

View File

@ -0,0 +1,69 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfdevobj.h
Abstract:
This header exposes function hooks that verify drivers properly manage
device objects.
--*/
typedef enum {
VF_DEVOBJ_PDO = 0,
VF_DEVOBJ_BUS_FILTER,
VF_DEVOBJ_LOWER_DEVICE_FILTER,
VF_DEVOBJ_LOWER_CLASS_FILTER,
VF_DEVOBJ_FDO,
VF_DEVOBJ_UPPER_DEVICE_FILTER,
VF_DEVOBJ_UPPER_CLASS_FILTER
} VF_DEVOBJ_TYPE, *PVF_DEVOBJ_TYPE;
VOID
VfDevObjPreAddDevice(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PDRIVER_OBJECT DriverObject,
IN PDRIVER_ADD_DEVICE AddDeviceFunction,
IN VF_DEVOBJ_TYPE DevObjType
);
VOID
VfDevObjPostAddDevice(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PDRIVER_OBJECT DriverObject,
IN PDRIVER_ADD_DEVICE AddDeviceFunction,
IN VF_DEVOBJ_TYPE DevObjType,
IN NTSTATUS Result
);
VOID
VfDevObjAdjustFdoForVerifierFilters(
IN OUT PDEVICE_OBJECT *FunctionalDeviceObject
);
VOID
VerifierIoAttachDeviceToDeviceStack(
IN PDEVICE_OBJECT NewDevice,
IN PDEVICE_OBJECT ExistingDevice
);
VOID
VerifierIoDetachDevice(
IN PDEVICE_OBJECT LowerDevice
);
VOID
VerifierIoDeleteDevice(
IN PDEVICE_OBJECT DeviceObject
);

View File

@ -0,0 +1,34 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vffilter.h
Abstract:
This header contains prototypes for using the verifier driver filter.
--*/
VOID
VfFilterInit(
VOID
);
VOID
VfFilterAttach(
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN VF_DEVOBJ_TYPE DeviceObjectType
);
BOOLEAN
VfFilterIsVerifierFilterObject(
IN PDEVICE_OBJECT DeviceObject
);

View File

@ -0,0 +1,24 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfgeneric.h
Abstract:
This header contains prototypes for verifying generic IRPs are handled
correctly.
--*/
VOID
VfGenericInit(
VOID
);

View File

@ -0,0 +1,24 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfinit.h
Abstract:
This header exposes the routines necessary to initialize the driver verifier.
--*/
VOID
FASTCALL
VfInitVerifier(
IN ULONG MmFlags
);

216
base/ntos/VERIFIER/vfirp.h Normal file
View File

@ -0,0 +1,216 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfirp.h
Abstract:
This module contains prototypes for functions used to manage IRPs used in
the verification process.
--*/
struct _IOV_STACK_LOCATION;
struct _IOV_REQUEST_PACKET;
struct _IOFCALLDRIVER_STACKDATA;
typedef struct _IOV_STACK_LOCATION *PIOV_STACK_LOCATION;
typedef struct _IOV_REQUEST_PACKET *PIOV_REQUEST_PACKET;
typedef struct _IOV_SESSION_DATA *PIOV_SESSION_DATA;
typedef struct _IOFCALLDRIVER_STACKDATA *PIOFCALLDRIVER_STACKDATA;
//
// Mini-snapshots of the IRP are stored on the stack for cases when the
// verifier needs to inform the developer as to the mistake, but no longer
// has the original IRP in memory. Because these may be stored on the stack,
// they need to be small and light.
//
typedef struct _IRP_MINI_SNAPSHOT {
PIRP Irp;
IO_STACK_LOCATION IoStackLocation;
} IRP_MINI_SNAPSHOT, *PIRP_MINI_SNAPSHOT;
typedef struct _IOV_STACK_LOCATION {
BOOLEAN InUse;
ULONG Flags;
PIOV_STACK_LOCATION RequestsFirstStackLocation;
LIST_ENTRY CallStackData;
PIO_STACK_LOCATION IrpSp;
PVOID LastDispatch;
LARGE_INTEGER PerfDispatchStart;
LARGE_INTEGER PerfStackLocationStart;
PDEVICE_OBJECT ReferencingObject;
LONG ReferencingCount;
IO_STATUS_BLOCK InitialStatusBlock;
IO_STATUS_BLOCK LastStatusBlock;
PETHREAD ThreadDispatchedTo;
} IOV_STACK_LOCATION;
typedef struct _IOV_SESSION_DATA {
PIOV_REQUEST_PACKET IovRequestPacket;
LONG SessionRefCount;
LIST_ENTRY SessionLink;
ULONG SessionFlags;
PETHREAD OriginatorThread;
PDEVICE_OBJECT DeviceLastCalled; // Last device called
ULONG ForwardMethod;
PIRP BestVisibleIrp;
PVERIFIER_SETTINGS_SNAPSHOT VerifierSettings;
IOV_STACK_LOCATION StackData[ANYSIZE_ARRAY];
} IOV_SESSION_DATA;
typedef struct _IOFCALLDRIVER_STACKDATA {
PIOV_SESSION_DATA IovSessionData;
PIOV_STACK_LOCATION IovStackLocation;
PIOV_REQUEST_PACKET IovPacket;
ULONG Flags;
LIST_ENTRY SharedLocationList;
PDRIVER_DISPATCH DispatchRoutine;
NTSTATUS ExpectedStatus;
NTSTATUS NewStatus;
PDEVICE_OBJECT RemovePdo;
IRP_MINI_SNAPSHOT IrpSnapshot;
} IOFCALLDRIVER_STACKDATA;
typedef struct _IOFCOMPLETEREQUEST_STACKDATA {
PIOV_SESSION_DATA IovSessionData;
PIOV_REQUEST_PACKET IovRequestPacket;
BOOLEAN IsRemoveIrp;
LONG LocationsAdvanced;
ULONG RaisedCount;
KIRQL PreviousIrql;
PVOID CompletionRoutine;
} IOFCOMPLETEREQUEST_STACKDATA, *PIOFCOMPLETEREQUEST_STACKDATA;
VOID
FASTCALL
VfIrpInit(
VOID
);
PIRP
FASTCALL
VfIrpAllocate(
IN CCHAR StackSize
);
VOID
FASTCALL
VfIrpMakeTouchable(
IN PIRP Irp
);
VOID
FASTCALL
VfIrpMakeUntouchable(
IN PIRP Irp OPTIONAL
);
VOID
FASTCALL
VfIrpFree(
IN PIRP Irp OPTIONAL
);
VOID
FASTCALL
VerifierIoAllocateIrp1(
IN CCHAR StackSize,
IN BOOLEAN ChargeQuota,
IN OUT PIRP *IrpPointer
);
VOID
FASTCALL
VerifierIoAllocateIrp2(
IN PIRP Irp
);
VOID
FASTCALL
VerifierIoFreeIrp(
IN PIRP Irp,
IN OUT PBOOLEAN FreeHandled
);
VOID
FASTCALL
VerifierIoInitializeIrp(
IN OUT PIRP Irp,
IN USHORT PacketSize,
IN CCHAR StackSize,
IN OUT PBOOLEAN InitializeHandled
);
BOOLEAN
FASTCALL
VfIrpReserveCallStackData(
IN PIRP Irp,
OUT PIOFCALLDRIVER_STACKDATA *IofCallDriverStackData
);
VOID
FASTCALL
VfIrpPrepareAllocaCallStackData(
OUT PIOFCALLDRIVER_STACKDATA IofCallDriverStackData
);
VOID
FASTCALL
VfIrpReleaseCallStackData(
IN PIOFCALLDRIVER_STACKDATA IofCallDriverStackData OPTIONAL
);
//
// VfIrpCallDriverPreprocess is a macro function that may do an alloca as
// part of it's operation. As such callers must be careful not to use
// variable length arrays in a scope that encompasses
// VfIrpCallDriverPreProcess but not VfIrpCallDriverPostProcess.
//
#define VfIrpCallDriverPreProcess(DeviceObject, IrpPointer, CallStackData, CallerAddress) \
if (!VfIrpReserveCallStackData(*(IrpPointer), (CallStackData))) { \
*(CallStackData) = alloca(sizeof(IOFCALLDRIVER_STACKDATA)); \
VfIrpPrepareAllocaCallStackData(*(CallStackData)); \
} \
IovpCallDriver1((DeviceObject), (IrpPointer), *(CallStackData), (CallerAddress))
#define VfIrpCallDriverPostProcess(DeviceObject, FinalStatus, CallStackData) \
IovpCallDriver2(DeviceObject, FinalStatus, CallStackData); \
VfIrpReleaseCallStackData(CallStackData)
BOOLEAN
VfIrpSendSynchronousIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION TopStackLocation,
IN BOOLEAN Untouchable,
IN NTSTATUS InitialStatus,
IN ULONG_PTR InitialInformation OPTIONAL,
OUT ULONG_PTR *FinalInformation OPTIONAL,
OUT NTSTATUS *FinalStatus OPTIONAL
);
VOID
FASTCALL
VfIrpWatermark(
IN PIRP Irp,
IN ULONG Flags
);

View File

@ -0,0 +1,128 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfirpdb.h
Abstract:
This header exposes prototypes for functions used to manage the database of
IRP tracking data.
--*/
struct _IOV_DATABASE_HEADER;
typedef struct _IOV_DATABASE_HEADER IOV_DATABASE_HEADER;
typedef struct _IOV_DATABASE_HEADER *PIOV_DATABASE_HEADER;
typedef enum _IOV_REFERENCE_TYPE {
IOVREFTYPE_PACKET = 0,
IOVREFTYPE_POINTER
} IOV_REFERENCE_TYPE;
typedef enum {
IRPDBEVENT_POINTER_COUNT_ZERO = 1,
IRPDBEVENT_REFERENCE_COUNT_ZERO
} IRP_DATABASE_EVENT;
typedef VOID (*PFN_IRPDBEVENT_CALLBACK)(
IN PIOV_DATABASE_HEADER IovHeader,
IN PIRP TrackedIrp OPTIONAL,
IN IRP_DATABASE_EVENT Event
);
typedef struct _IOV_DATABASE_HEADER {
PIRP TrackedIrp; // Tracked IRP
KSPIN_LOCK HeaderLock; // Spinlock on data structure
KIRQL LockIrql; // IRQL taken at.
LONG ReferenceCount; // # of reasons to keep this packet
LONG PointerCount; // # of reasons to track by irp addr
ULONG HeaderFlags;
LIST_ENTRY HashLink; // Link in hash table.
LIST_ENTRY ChainLink; // Head is HeadPacket
PIOV_DATABASE_HEADER ChainHead; // First packet in a chain.
PFN_IRPDBEVENT_CALLBACK NotificationCallback;
};
VOID
FASTCALL
VfIrpDatabaseInit(
VOID
);
BOOLEAN
FASTCALL
VfIrpDatabaseEntryInsertAndLock(
IN PIRP Irp,
IN PFN_IRPDBEVENT_CALLBACK NotificationCallback,
IN OUT PIOV_DATABASE_HEADER IovHeader
);
PIOV_DATABASE_HEADER
FASTCALL
VfIrpDatabaseEntryFindAndLock(
IN PIRP Irp
);
VOID
FASTCALL
VfIrpDatabaseEntryAcquireLock(
IN PIOV_DATABASE_HEADER IovHeader OPTIONAL
);
VOID
FASTCALL
VfIrpDatabaseEntryReleaseLock(
IN PIOV_DATABASE_HEADER IovHeader
);
VOID
FASTCALL
VfIrpDatabaseEntryReference(
IN PIOV_DATABASE_HEADER IovHeader,
IN IOV_REFERENCE_TYPE IovRefType
);
VOID
FASTCALL
VfIrpDatabaseEntryDereference(
IN PIOV_DATABASE_HEADER IovHeader,
IN IOV_REFERENCE_TYPE IovRefType
);
VOID
FASTCALL
VfIrpDatabaseEntryAppendToChain(
IN OUT PIOV_DATABASE_HEADER IovExistingHeader,
IN OUT PIOV_DATABASE_HEADER IovNewHeader
);
VOID
FASTCALL
VfIrpDatabaseEntryRemoveFromChain(
IN OUT PIOV_DATABASE_HEADER IovHeader
);
PIOV_DATABASE_HEADER
FASTCALL
VfIrpDatabaseEntryGetChainPrevious(
IN PIOV_DATABASE_HEADER IovHeader
);
PIOV_DATABASE_HEADER
FASTCALL
VfIrpDatabaseEntryGetChainNext(
IN PIOV_DATABASE_HEADER IovHeader
);

View File

@ -0,0 +1,75 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfirplog.h
Abstract:
This header exposes functions for logging IRP events.
--*/
//
// Log-snapshots are retrievable by user mode for profiling and targetted
// probing of stacks. Content-wise they are heavier.
//
typedef struct _IRPLOG_SNAPSHOT {
ULONG Count;
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR Flags;
UCHAR Control;
ULONGLONG ArgArray[4];
} IRPLOG_SNAPSHOT, *PIRPLOG_SNAPSHOT;
VOID
VfIrpLogInit(
VOID
);
VOID
VfIrpLogRecordEvent(
IN PVERIFIER_SETTINGS_SNAPSHOT VerifierSettingsSnapshot,
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
ULONG
VfIrpLogGetIrpDatabaseSiloCount(
VOID
);
NTSTATUS
VfIrpLogLockDatabase(
IN ULONG SiloNumber
);
NTSTATUS
VfIrpLogRetrieveWmiData(
IN ULONG SiloNumber,
OUT PUCHAR OutputBuffer OPTIONAL,
OUT ULONG *OffsetInstanceNameOffsets,
OUT ULONG *InstanceCount,
OUT ULONG *DataBlockOffset,
OUT ULONG *TotalRequiredSize
);
VOID
VfIrpLogUnlockDatabase(
IN ULONG SiloNumber
);
VOID
VfIrpLogDeleteDeviceLogs(
IN PDEVICE_OBJECT DeviceObject
);

View File

@ -0,0 +1,35 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfmacro.h
Abstract:
This header contains a collection of macros used by the verifier.
--*/
//
// This macro takes an array and returns the number of elements in it.
//
#define ARRAY_COUNT(array) (sizeof(array)/sizeof(array[0]))
//
// This macro takes a value and an alignment and rounds the entry up
// appropriately. The alignment MUST be a power of two!
//
#define ALIGN_UP_ULONG(value, alignment) (((value)+(alignment)-1)&(~(alignment-1)))
//
// This macro compares two guids in their binary form for equivalence.
//
#define IS_EQUAL_GUID(a,b) (RtlCompareMemory(a, b, sizeof(GUID)) == sizeof(GUID))

View File

@ -0,0 +1,221 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfmajor.h
Abstract:
This header contains prototypes for per-major IRP code verification.
--*/
//
// Use this major code to register a handler for default or all IRPs (context
// specific to function)
//
#define IRP_MJ_ALL_MAJORS 0xFF
typedef VOID (FASTCALL *PFN_DUMP_IRP_STACK)(
IN PIO_STACK_LOCATION IrpSp
);
typedef VOID (FASTCALL *PFN_VERIFY_NEW_REQUEST)(
IN PIOV_REQUEST_PACKET IrpTrackingData,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
typedef VOID (FASTCALL *PFN_VERIFY_IRP_STACK_DOWNWARD)(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
typedef VOID (FASTCALL *PFN_VERIFY_IRP_STACK_UPWARD)(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN BOOLEAN IsNewlyCompleted,
IN BOOLEAN RequestFinalized
);
typedef BOOLEAN (FASTCALL *PFN_IS_SYSTEM_RESTRICTED_IRP)(
IN PIO_STACK_LOCATION IrpSp
);
typedef BOOLEAN (FASTCALL *PFN_ADVANCE_IRP_STATUS)(
IN PIO_STACK_LOCATION IrpSp,
IN NTSTATUS OriginalStatus,
IN OUT NTSTATUS *StatusToAdvance
);
typedef BOOLEAN (FASTCALL *PFN_IS_VALID_IRP_STATUS)(
IN PIO_STACK_LOCATION IrpSp,
IN NTSTATUS Status
);
typedef BOOLEAN (FASTCALL *PFN_IS_NEW_REQUEST)(
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp
);
typedef VOID (FASTCALL *PFN_VERIFY_NEW_IRP)(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
typedef VOID (FASTCALL *PFN_VERIFY_FINAL_IRP_STACK)(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIO_STACK_LOCATION IrpSp
);
typedef VOID (FASTCALL *PFN_TEST_STARTED_PDO_STACK)(
IN PDEVICE_OBJECT PhysicalDeviceObject
);
typedef LOGICAL (FASTCALL *PFN_BUILD_LOG_ENTRY)(
IN PIRP Irp,
IN ULONG CurrentCount,
IN PIRPLOG_SNAPSHOT CurrentEntryArray,
OUT PIRPLOG_SNAPSHOT IrpSnapshot
);
VOID
VfMajorInit(
VOID
);
VOID
FASTCALL
VfMajorRegisterHandlers(
IN UCHAR IrpMajorCode,
IN PFN_DUMP_IRP_STACK DumpIrpStack OPTIONAL,
IN PFN_VERIFY_NEW_REQUEST VerifyNewRequest OPTIONAL,
IN PFN_VERIFY_IRP_STACK_DOWNWARD VerifyStackDownward OPTIONAL,
IN PFN_VERIFY_IRP_STACK_UPWARD VerifyStackUpward OPTIONAL,
IN PFN_IS_SYSTEM_RESTRICTED_IRP IsSystemRestrictedIrp OPTIONAL,
IN PFN_ADVANCE_IRP_STATUS AdvanceIrpStatus OPTIONAL,
IN PFN_IS_VALID_IRP_STATUS IsValidIrpStatus OPTIONAL,
IN PFN_IS_NEW_REQUEST IsNewRequest OPTIONAL,
IN PFN_VERIFY_NEW_IRP VerifyNewIrp OPTIONAL,
IN PFN_VERIFY_FINAL_IRP_STACK VerifyFinalIrpStack OPTIONAL,
IN PFN_TEST_STARTED_PDO_STACK TestStartedPdoStack OPTIONAL,
IN PFN_BUILD_LOG_ENTRY BuildIrpLogEntry OPTIONAL
);
VOID
FASTCALL
VfMajorDumpIrpStack(
IN PIO_STACK_LOCATION IrpSp
);
VOID
FASTCALL
VfMajorVerifyNewRequest(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfMajorVerifyIrpStackDownward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfMajorVerifyIrpStackUpward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN BOOLEAN IsNewlyCompleted,
IN BOOLEAN RequestFinalized
);
BOOLEAN
FASTCALL
VfMajorIsSystemRestrictedIrp(
IN PIO_STACK_LOCATION IrpSp
);
BOOLEAN
FASTCALL
VfMajorAdvanceIrpStatus(
IN PIO_STACK_LOCATION IrpSp,
IN NTSTATUS OriginalStatus,
IN OUT NTSTATUS *StatusToAdvance
);
BOOLEAN
FASTCALL
VfMajorIsValidIrpStatus(
IN PIO_STACK_LOCATION IrpSp,
IN NTSTATUS Status
);
BOOLEAN
FASTCALL
VfMajorIsNewRequest(
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp
);
VOID
FASTCALL
VfMajorVerifyNewIrp(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfMajorVerifyFinalIrpStack(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIO_STACK_LOCATION IrpSp
);
VOID
FASTCALL
VfMajorTestStartedPdoStack(
IN PDEVICE_OBJECT PhysicalDeviceObject
);
LOGICAL
FASTCALL
VfMajorBuildIrpLogEntry(
IN PIRP Irp,
IN ULONG CurrentCount,
IN PIRPLOG_SNAPSHOT CurrentEntryArray,
OUT PIRPLOG_SNAPSHOT IrpSnapshot
);

View File

@ -0,0 +1,237 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfmessage.h
Abstract:
This module contains prototypes for functions used to retrieve text and
flags associated with each error.
--*/
//
// The verifier uses tables of messages and with indexes into the tables.
//
typedef ULONG VFMESSAGE_TABLEID;
typedef ULONG VFMESSAGE_ERRORID;
//
// VFM_ flags control how a verifier message is handled.
//
// VFM_FLAG_INITIALIZED - Set when the error template has been updated with
// error-class information
//
// VFM_FLAG_BEEP - Set if error should beep in debugger
//
// VFM_FLAG_ZAPPED - Set if error was "zapped" (ie prints instead of
// stops) via debugger
//
// VFM_FLAG_CLEARED - Set if error was cleared (disabled) in debugger
//
// VFM_DEPLOYMENT_FAILURE - Set if the error is severe enough to warrant
// removal of the driver from a production system
//
// VFM_LOGO_FAILURE - Set if the error should disallow certification
// for the hardware or the driver
//
// VFM_IGNORE_DRIVER_LIST - Set if error should fire regardless of whether
// the offending driver is being verified or not.
//
#define VFM_FLAG_INITIALIZED 0x00000001
#define VFM_FLAG_BEEP 0x00000002
#define VFM_FLAG_ZAPPED 0x00000004
#define VFM_FLAG_CLEARED 0x00000008
#define VFM_DEPLOYMENT_FAILURE 0x00000010
#define VFM_LOGO_FAILURE 0x00000020
#define VFM_IGNORE_DRIVER_LIST 0x00000040
//
// A message class contains VFM_ flags and some generic text describing the
// problem class.
//
typedef struct _VFMESSAGE_CLASS {
ULONG ClassFlags;
PCSTR MessageClassText;
} VFMESSAGE_CLASS, *PVFMESSAGE_CLASS;
typedef VFMESSAGE_CLASS const *PCVFMESSAGE_CLASS;
//
// Individual error template. Identifies the index, the message class it's
// associated with, the parameters it takes along with the formatted text it
// displays. Note the ulong flags field - this should always be preinited to
// zero!
//
typedef struct _VFMESSAGE_TEMPLATE {
VFMESSAGE_ERRORID MessageID;
PCVFMESSAGE_CLASS MessageClass;
ULONG Flags;
PCSTR ParamString;
PCSTR MessageText;
} VFMESSAGE_TEMPLATE, *PVFMESSAGE_TEMPLATE;
//
// Message index 0 is reserved for use in the override tables
//
#define VIMESSAGE_ALL_IDS 0
//
// An override entry allows the verifier to special case generic assertions
// that occur against specific drivers. This is done by overriding the error
// class on the fly.
//
typedef struct _VFMESSAGE_OVERRIDE {
VFMESSAGE_ERRORID MessageID;
PCSTR DriverName;
PCVFMESSAGE_CLASS ReplacementClass;
} VFMESSAGE_OVERRIDE, *PVFMESSAGE_OVERRIDE;
typedef VFMESSAGE_OVERRIDE const *PCVFMESSAGE_OVERRIDE;
//
// The table of errors. Contains the TableID (used for internal lookup),
// bugcheck major ID, array of messages and array of overrides
//
typedef struct _VFMESSAGE_TEMPLATE_TABLE {
VFMESSAGE_TABLEID TableID;
ULONG BugCheckMajor;
PVFMESSAGE_TEMPLATE TemplateArray;
ULONG TemplateCount;
PCVFMESSAGE_OVERRIDE OverrideArray;
ULONG OverrideCount;
} VFMESSAGE_TEMPLATE_TABLE, *PVFMESSAGE_TEMPLATE_TABLE;
//
// Retrieves an internal error table based on ID.
//
VOID
VfMessageRetrieveInternalTable(
IN VFMESSAGE_TABLEID TableID,
OUT PVFMESSAGE_TEMPLATE_TABLE *MessageTable
);
//
// Retrieves and formats the appropriate error message.
//
VOID
VfMessageRetrieveErrorData(
IN PVFMESSAGE_TEMPLATE_TABLE MessageTable OPTIONAL,
IN VFMESSAGE_ERRORID MessageID,
IN PSTR AnsiDriverName,
OUT ULONG *BugCheckMajor,
OUT PCVFMESSAGE_CLASS *MessageClass,
OUT PCSTR *MessageTextTemplate,
OUT PULONG *TemplateFlags
);
//
// This file contains a set of internal message tables.
//
// The IO Verifier Table Index is...
//
#define VFMESSAGE_TABLE_IOVERIFIER 1
//
// IO Verifier Messages
//
typedef enum _DCERROR_ID {
DCERROR_UNSPECIFIED = 0x200,
DCERROR_DELETE_WHILE_ATTACHED,
DCERROR_DETACH_NOT_ATTACHED,
DCERROR_CANCELROUTINE_FORWARDED,
DCERROR_NULL_DEVOBJ_FORWARDED,
DCERROR_QUEUED_IRP_FORWARDED,
DCERROR_NEXTIRPSP_DIRTY,
DCERROR_IRPSP_COPIED,
DCERROR_INSUFFICIENT_STACK_LOCATIONS,
DCERROR_QUEUED_IRP_COMPLETED,
DCERROR_FREE_OF_INUSE_TRACKED_IRP,
DCERROR_FREE_OF_INUSE_IRP,
DCERROR_FREE_OF_THREADED_IRP,
DCERROR_REINIT_OF_ALLOCATED_IRP_WITH_QUOTA,
DCERROR_PNP_IRP_BAD_INITIAL_STATUS,
DCERROR_POWER_IRP_BAD_INITIAL_STATUS,
DCERROR_WMI_IRP_BAD_INITIAL_STATUS,
DCERROR_SKIPPED_DEVICE_OBJECT,
DCERROR_BOGUS_FUNC_TRASHED,
DCERROR_BOGUS_STATUS_TRASHED,
DCERROR_BOGUS_INFO_TRASHED,
DCERROR_PNP_FAILURE_FORWARDED,
DCERROR_PNP_IRP_STATUS_RESET,
DCERROR_PNP_IRP_NEEDS_HANDLING,
DCERROR_PNP_IRP_HANDS_OFF,
DCERROR_POWER_FAILURE_FORWARDED,
DCERROR_POWER_IRP_STATUS_RESET,
DCERROR_INVALID_STATUS,
DCERROR_UNNECCESSARY_COPY,
DCERROR_SHOULDVE_DETACHED,
DCERROR_SHOULDVE_DELETED,
DCERROR_MISSING_DISPATCH_FUNCTION,
DCERROR_WMI_IRP_NOT_FORWARDED,
DCERROR_DELETED_PRESENT_PDO,
DCERROR_BUS_FILTER_ERRONEOUSLY_DETACHED,
DCERROR_BUS_FILTER_ERRONEOUSLY_DELETED,
DCERROR_INCONSISTANT_STATUS,
DCERROR_UNINITIALIZED_STATUS,
DCERROR_IRP_RETURNED_WITHOUT_COMPLETION,
DCERROR_COMPLETION_ROUTINE_PAGABLE,
DCERROR_PENDING_BIT_NOT_MIGRATED,
DCERROR_CANCELROUTINE_ON_FORWARDED_IRP,
DCERROR_PNP_IRP_NEEDS_PDO_HANDLING,
DCERROR_TARGET_RELATION_LIST_EMPTY,
DCERROR_TARGET_RELATION_NEEDS_REF,
DCERROR_BOGUS_PNP_IRP_COMPLETED,
DCERROR_SUCCESSFUL_PNP_IRP_NOT_FORWARDED,
DCERROR_UNTOUCHED_PNP_IRP_NOT_FORWARDED,
DCERROR_BOGUS_POWER_IRP_COMPLETED,
DCERROR_SUCCESSFUL_POWER_IRP_NOT_FORWARDED,
DCERROR_UNTOUCHED_POWER_IRP_NOT_FORWARDED,
DCERROR_PNP_QUERY_CAP_BAD_VERSION,
DCERROR_PNP_QUERY_CAP_BAD_SIZE,
DCERROR_PNP_QUERY_CAP_BAD_ADDRESS,
DCERROR_PNP_QUERY_CAP_BAD_UI_NUM,
DCERROR_RESTRICTED_IRP,
DCERROR_REINIT_OF_ALLOCATED_IRP_WITHOUT_QUOTA,
DCERROR_UNFORWARDED_IRP_COMPLETED,
DCERROR_DISPATCH_CALLED_AT_BAD_IRQL,
DCERROR_BOGUS_MINOR_STATUS_TRASHED,
DCERROR_CANCELROUTINE_AFTER_COMPLETION,
DCERROR_PENDING_RETURNED_NOT_MARKED,
DCERROR_PENDING_MARKED_NOT_RETURNED,
DCERROR_POWER_PAGABLE_NOT_INHERITED,
DCERROR_DOUBLE_DELETION,
DCERROR_DETACHED_IN_SURPRISE_REMOVAL,
DCERROR_DELETED_IN_SURPRISE_REMOVAL,
DCERROR_DO_INITIALIZING_NOT_CLEARED,
DCERROR_DO_FLAG_NOT_COPIED,
DCERROR_INCONSISTANT_DO_FLAGS,
DCERROR_DEVICE_TYPE_NOT_COPIED,
DCERROR_NON_FAILABLE_IRP,
DCERROR_NON_PDO_RETURNED_IN_RELATION,
DCERROR_DUPLICATE_ENUMERATION,
DCERROR_FILE_IO_AT_BAD_IRQL,
DCERROR_MISHANDLED_TARGET_DEVICE_RELATIONS,
DCERROR_PENDING_RETURNED_NOT_MARKED_2,
DCERROR_DDI_REQUIRES_PDO,
DCERROR_MAXIMUM
} DCERROR_ID;

View File

@ -0,0 +1,158 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfpacket.h
Abstract:
This header exposes functions used to manage the verifier packet data that
tracks IRPs.
--*/
//
// Currently, ntddk.h uses up to 0x2000 for Irp->Flags
//
#define IRPFLAG_EXAMINE_MASK 0xC0000000
#define IRPFLAG_EXAMINE_NOT_TRACKED 0x80000000
#define IRPFLAG_EXAMINE_TRACKED 0x40000000
#define IRPFLAG_EXAMINE_UNMARKED 0x00000000
#define TRACKFLAG_ACTIVE 0x00000001
#define IRP_ALLOC_COUNT 8
#define IRP_LOG_ENTRIES 16
typedef enum {
IOV_EVENT_NONE = 0,
IOV_EVENT_IO_ALLOCATE_IRP,
IOV_EVENT_IO_CALL_DRIVER,
IOV_EVENT_IO_CALL_DRIVER_UNWIND,
IOV_EVENT_IO_COMPLETE_REQUEST,
IOV_EVENT_IO_COMPLETION_ROUTINE,
IOV_EVENT_IO_COMPLETION_ROUTINE_UNWIND,
IOV_EVENT_IO_CANCEL_IRP,
IOV_EVENT_IO_FREE_IRP
} IOV_LOG_EVENT;
typedef struct {
IOV_LOG_EVENT Event;
PETHREAD Thread;
PVOID Address;
ULONG_PTR Data;
LARGE_INTEGER TimeStamp;
} IOV_LOG_ENTRY, *PIOV_LOG_ENTRY;
struct _IOV_SESSION_DATA;
struct _IOV_REQUEST_PACKET;
typedef struct _IOV_SESSION_DATA *PIOV_SESSION_DATA;
typedef struct _IOV_REQUEST_PACKET *PIOV_REQUEST_PACKET;
typedef struct _IOV_REQUEST_PACKET {
IOV_DATABASE_HEADER;
ULONG Flags;
KIRQL DepartureIrql; // Irql IRP will be dispatched at.
KIRQL ArrivalIrql; // Irql IRP was sent in at.
LIST_ENTRY SessionHead; // List of all sessions.
CCHAR StackCount; // StackCount of tracked IRP.
ULONG QuotaCharge; // Quota charged against IRP.
PEPROCESS QuotaProcess; // Process quota was charged to.
PIO_COMPLETION_ROUTINE RealIrpCompletionRoutine;
UCHAR RealIrpControl;
PVOID RealIrpContext;
PVOID AllocatorStack[IRP_ALLOC_COUNT];
//
// The following information is for the assertion routines to read.
//
UCHAR TopStackLocation;
CCHAR PriorityBoost; // Boost from IofCompleteRequest
UCHAR LastLocation; // Last location from IofCallDriver
ULONG RefTrackingCount;
//
// This field is only set on surrogate IRPs, and contains the locked system
// VA for the destination of a direct I/O IRP that's being buffered.
//
PUCHAR SystemDestVA;
#if DBG
IOV_LOG_ENTRY LogEntries[IRP_LOG_ENTRIES];
ULONG LogEntryHead;
ULONG LogEntryTail;
#endif
PVERIFIER_SETTINGS_SNAPSHOT VerifierSettings;
PIOV_SESSION_DATA pIovSessionData;
} IOV_REQUEST_PACKET;
PIOV_REQUEST_PACKET
FASTCALL
VfPacketCreateAndLock(
IN PIRP Irp
);
PIOV_REQUEST_PACKET
FASTCALL
VfPacketFindAndLock(
IN PIRP Irp
);
VOID
FASTCALL
VfPacketAcquireLock(
IN PIOV_REQUEST_PACKET IrpTrackingData
);
VOID
FASTCALL
VfPacketReleaseLock(
IN PIOV_REQUEST_PACKET IrpTrackingData
);
VOID
FASTCALL
VfPacketReference(
IN PIOV_REQUEST_PACKET IovPacket,
IN IOV_REFERENCE_TYPE IovRefType
);
VOID
FASTCALL
VfPacketDereference(
IN PIOV_REQUEST_PACKET IovPacket,
IN IOV_REFERENCE_TYPE IovRefType
);
PIOV_SESSION_DATA
FASTCALL
VfPacketGetCurrentSessionData(
IN PIOV_REQUEST_PACKET IovPacket
);
VOID
FASTCALL
VfPacketLogEntry(
IN PIOV_REQUEST_PACKET IovPacket,
IN IOV_LOG_EVENT IovLogEvent,
IN PVOID Address,
IN ULONG_PTR Data
);

View File

@ -0,0 +1,84 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfpnp.h
Abstract:
This header contains prototypes for verifying Pnp IRPs are handled
correctly.
--*/
VOID
VfPnpInit(
VOID
);
VOID
FASTCALL
VfPnpVerifyNewRequest(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfPnpVerifyIrpStackDownward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfPnpVerifyIrpStackUpward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN BOOLEAN IsNewlyCompleted,
IN BOOLEAN RequestFinalized
);
VOID
FASTCALL
VfPnpDumpIrpStack(
IN PIO_STACK_LOCATION IrpSp
);
BOOLEAN
FASTCALL
VfPnpIsSystemRestrictedIrp(
IN PIO_STACK_LOCATION IrpSp
);
BOOLEAN
FASTCALL
VfPnpAdvanceIrpStatus(
IN PIO_STACK_LOCATION IrpSp,
IN NTSTATUS OriginalStatus,
IN OUT NTSTATUS *StatusToAdvance
);
VOID
FASTCALL
VfPnpTestStartedPdoStack(
IN PDEVICE_OBJECT PhysicalDeviceObject
);

View File

@ -0,0 +1,84 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfpower.h
Abstract:
This header contains prototypes for verifying Power IRPs are handled
correctly.
--*/
VOID
VfPowerInit(
VOID
);
VOID
FASTCALL
VfPowerVerifyNewRequest(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfPowerVerifyIrpStackDownward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfPowerVerifyIrpStackUpward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN BOOLEAN IsNewlyCompleted,
IN BOOLEAN RequestFinalized
);
VOID
FASTCALL
VfPowerDumpIrpStack(
IN PIO_STACK_LOCATION IrpSp
);
BOOLEAN
FASTCALL
VfPowerIsSystemRestrictedIrp(
IN PIO_STACK_LOCATION IrpSp
);
BOOLEAN
FASTCALL
VfPowerAdvanceIrpStatus(
IN PIO_STACK_LOCATION IrpSp,
IN NTSTATUS OriginalStatus,
IN OUT NTSTATUS *StatusToAdvance
);
VOID
FASTCALL
VfPowerTestStartedPdoStack(
IN PDEVICE_OBJECT PhysicalDeviceObject
);

View File

@ -0,0 +1,32 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfpragma.h
Abstract:
This header contains disable instructions for W4 warnings generated
by public headers. This way we can still compile modules at W4.
--*/
//
// Disable W4 level warnings generated by public headers.
//
#pragma warning(disable:4214) // bit field types other than int
#pragma warning(disable:4201) // nameless struct/union
#pragma warning(disable:4324) // alignment sensitive to declspec
#pragma warning(disable:4127) // condition expression is constant
#pragma warning(disable:4115) // named type definition in parentheses
#pragma warning(disable:4232) // dllimport not static
#pragma warning(disable:4206) // translation unit empty
#pragma warning(disable:4054) // function pointer to data pointer cast

View File

@ -0,0 +1,29 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfprint.h
Abstract:
This header exposes prototypes required when outputting various data types
to the debugger.
--*/
VOID
VfPrintDumpIrpStack(
IN PIO_STACK_LOCATION IrpSp
);
VOID
VfPrintDumpIrp(
IN PIRP IrpToFlag
);

View File

@ -0,0 +1,31 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfrandom.h
Abstract:
This header exposes support for random number generation as needed by the
verifier.
--*/
VOID
VfRandomInit(
VOID
);
ULONG
FASTCALL
VfRandomGetNumber(
IN ULONG Minimum,
IN ULONG Maximum
);

View File

@ -0,0 +1,316 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfsettings.h
Abstract:
This header contains prototypes for manipulating verifier options and
values.
--*/
typedef PVOID PVERIFIER_SETTINGS_SNAPSHOT;
typedef enum {
//
// This option lets the verifer begin tracking all IRPs. It must be enabled
// for most of the other IRP verification options to work.
//
VERIFIER_OPTION_TRACK_IRPS = 1,
//
// This option forces all IRPs to be allocated from the special pool.
// VERIFIER_OPTION_TRACK_IRPS need not be enabled.
//
VERIFIER_OPTION_MONITOR_IRP_ALLOCS,
//
// This option enables various checks for basic/common IRP handling mistakes.
//
VERIFIER_OPTION_POLICE_IRPS,
//
// This option enables checks specific to major/minor codes.
//
VERIFIER_OPTION_MONITOR_MAJORS,
//
// This option causes the call stacks of IRP dispatch and completion
// routines to be seeded with 0xFFFFFFFF. This value is illegal for a
// status code, and such seeding flushes out uninitialized variable bugs.
//
VERIFIER_OPTION_SEEDSTACK,
//
// This option sends a bogus QueryDeviceRelations IRP to newly built stacks.
// The particular IRP sent is of type -1, and has a -1 passed in for the
// device list.
//
VERIFIER_OPTION_RELATION_IGNORANCE_TEST,
//
// This option causes the verifier to stop on unnecessary IRP stack copies.
// It is useful for optimizing drivers.
//
VERIFIER_OPTION_FLAG_UNNECCESSARY_COPIES,
VERIFIER_OPTION_SEND_BOGUS_WMI_IRPS,
VERIFIER_OPTION_SEND_BOGUS_POWER_IRPS,
//
// If this option is enabled, the verifier makes sure drivers mark the IRP
// pending if and only if STATUS_PENDING is returned, and visa versa.
//
VERIFIER_OPTION_MONITOR_PENDING_IO,
//
// If this option is enabled, the verifier makes all IRPs return in an
// asynchronous manner. Specifically, all IRPs are marked pending, and
// STATUS_PENDING is returned from every IoCallDriver.
//
VERIFIER_OPTION_FORCE_PENDING,
//
// If this option is enabled, the verifier will change the status code of
// successful IRPs to alternate success status's. This catches many IRP
// forwarding bugs.
//
VERIFIER_OPTION_ROTATE_STATUS,
//
// If this option is enabled, the verifier will undo the effects of
// IoSkipCurrentIrpStackLocation so that all stacks appear to be copied.
// (Exempting the case where an IRP was forwarded to another stack)
//
VERIFIER_OPTION_CONSUME_ALWAYS,
//
// If this option is enabled, the verifier will update SRB's to handle
// surrogate IRPs. Some SCSI IRPs can't be surrogated unless the
// SRB->OriginalRequest pointer is updated. This is due to a busted SRB
// architecture. Note that the technique used to identify an SRB IRP is
// "fuzzy", and could in theory touch an IRP it shouldn't have!
//
VERIFIER_OPTION_SMASH_SRBS,
//
// If this option is enabled, the verifier will replace original IRPs with
// surrogates when traveling down the stack. The surrogates are allocated
// from special pool, and get freed immediately upon completion. This lets
// the verifier catch drivers that touch IRPs after they're completed.
//
VERIFIER_OPTION_SURROGATE_IRPS,
//
// If this option is enabled, the verifier buffers all direct I/O. It does
// this by allocating an alternate MDL and copying the MDL contents back
// to user mode only after IRP completion. This allows overruns, underruns,
// and late accesses to be detected.
//
VERIFIER_OPTION_BUFFER_DIRECT_IO,
//
// If this option is enabled, the verifier delays completion of all IRPs
// via timer. VERIFIER_OPTION_FORCE_PENDING is set by inference.
//
VERIFIER_OPTION_DEFER_COMPLETION,
//
// If this option is enabled, the verifier completes every IRP at
// PASSIVE_LEVEL, regardless of major function.
// VERIFIER_OPTION_FORCE_PENDING is set by inference.
//
VERIFIER_OPTION_COMPLETE_AT_PASSIVE,
//
// If this option is enabled, the verifier completes every IRP at
// DISPATCH_LEVEL, regardless of major function.
//
VERIFIER_OPTION_COMPLETE_AT_DISPATCH,
//
// If this option is enabled, the verifier monitors cancel routines to make
// sure they are cleared appropriately.
//
VERIFIER_OPTION_VERIFY_CANCEL_LOGIC,
VERIFIER_OPTION_RANDOMLY_CANCEL_IRPS,
//
// If this option is enabled, the verifier inserts filter device objects
// into WDM stacks to ensure IRPs are properly forwarded.
//
VERIFIER_OPTION_INSERT_WDM_FILTERS,
//
// If this option is enabled, the verifier monitors drivers to ensure they
// don't send system reserved IRPs to WDM stacks.
//
VERIFIER_OPTION_PROTECT_RESERVED_IRPS,
//
// If this option is enabled, the verifier walks the entire stack to ensure
// the DO bits are properly built during AddDevice. This includes the
// DO_POWER_PAGABLE flag.
//
VERIFIER_OPTION_VERIFY_DO_FLAGS,
//
// If this option is enabled, the verifier watches Target device relation
// IRPs to make sure the device object is properly reference counted.
//
VERIFIER_OPTION_TEST_TARGET_REFCOUNT,
//
// Lets you detect when deadlocks can occur
//
VERIFIER_OPTION_DETECT_DEADLOCKS,
//
// If this option is enabled, all dma operations will be hooked and
// validated.
//
VERIFIER_OPTION_VERIFY_DMA,
//
// This option double buffers all dma and erects guard pages on each side
// of all common buffers and mapped buffers. Is memory-intensive but can
// catch hardware buffer overruns and drivers that don't flush adapter
// buffers.
//
VERIFIER_OPTION_DOUBLE_BUFFER_DMA,
//
// If this option is enabled, you get notified when the performance counter
// is being naughty
//
VERIFIER_OPTION_VERIFY_PERFORMANCE_COUNTER,
//
// If this option is enabled, the verifier checks for implementations of
// IRP_MN_DEVICE_USAGE_NOTIFICATION and IRP_MN_SURPRISE_REMOVAL. The
// verifier will also make sure PnP Cancel IRPs are not explicitely failed.
//
VERIFIER_OPTION_EXTENDED_REQUIRED_IRPS,
//
// If this option is enabled, the verifier mixes up device relations
// to ensure drivers aren't depending on ordering.
//
VERIFIER_OPTION_SCRAMBLE_RELATIONS,
//
// If this option is enabled, the verifier ensures proper detaching and
// deletion occurs on removes and surprise removes.
//
VERIFIER_OPTION_MONITOR_REMOVES,
//
// If this option is enabled, the verifier ensures device relations only
// consist of PDO's.
//
VERIFIER_OPTION_EXAMINE_RELATION_PDOS,
//
// If this option is enabled, the verifier enabled hardware verification
// (bus specific behavior)
//
VERIFIER_OPTION_HARDWARE_VERIFICATION,
//
// If this option is enabled, the verifier ensures system BIOS verification
//
VERIFIER_OPTION_SYSTEM_BIOS_VERIFICATION,
//
// If this option is enabled, the verifier exposes IRP history data that
// can be used to test for security holes.
//
VERIFIER_OPTION_EXPOSE_IRP_HISTORY,
VERIFIER_OPTION_MAX
} VERIFIER_OPTION;
typedef enum {
//
// If VERIFIER_OPTION_DEFER_COMPLETION is set, this value contains the time
// an IRP will be deferred, in 100us units.
//
VERIFIER_VALUE_IRP_DEFERRAL_TIME = 1,
//
// This shall be the percentage of allocates to fail during low resource
// simulation.
//
VERIFIER_VALUE_LOW_RESOURCE_PERCENTAGE,
//
// If VERIFIER_OPTION_EXPOSE_IRP_HISTORY is set, this value contains the
// amount of IRPs per device object to log.
//
VERIFIER_VALUE_IRPLOG_COUNT,
VERIFIER_VALUE_MAX
} VERIFIER_VALUE;
VOID
FASTCALL
VfSettingsInit(
IN ULONG MmFlags
);
BOOLEAN
FASTCALL
VfSettingsIsOptionEnabled(
IN PVERIFIER_SETTINGS_SNAPSHOT VerifierSettingsSnapshot OPTIONAL,
IN VERIFIER_OPTION VerifierOption
);
VOID
FASTCALL
VfSettingsCreateSnapshot(
IN OUT PVERIFIER_SETTINGS_SNAPSHOT VerifierSettingsSnapshot
);
ULONG
FASTCALL
VfSettingsGetSnapshotSize(
VOID
);
VOID
FASTCALL
VfSettingsSetOption(
IN PVERIFIER_SETTINGS_SNAPSHOT VerifierSettingsSnapshot OPTIONAL,
IN VERIFIER_OPTION VerifierOption,
IN BOOLEAN Setting
);
VOID
FASTCALL
VfSettingsGetValue(
IN PVERIFIER_SETTINGS_SNAPSHOT VerifierSettingsSnapshot OPTIONAL,
IN VERIFIER_VALUE VerifierValue,
OUT ULONG *Value
);
VOID
FASTCALL
VfSettingsSetValue(
IN PVERIFIER_SETTINGS_SNAPSHOT VerifierSettingsSnapshot OPTIONAL,
IN VERIFIER_VALUE VerifierValue,
IN ULONG Value
);

View File

@ -0,0 +1,25 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfstack.h
Abstract:
This header contains prototypes for verifying drivers don't improperly use
thread stacks.
--*/
VOID
FASTCALL
VfStackSeedStack(
IN ULONG Seed
);

View File

@ -0,0 +1,23 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vftriage
Abstract:
Code to support driver verifier triage decisions and running mode.
--*/
#ifndef INCLUDED_VFTRIAGE_H
#define INCLUDED_VFTRIAGE_H
#endif // #ifndef INCLUDED_VFTRIAGE_H

View File

@ -0,0 +1,38 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfutil.h
Abstract:
This header contains prototypes for various functions required to do driver
verification.
--*/
typedef enum {
VFMP_INSTANT = 0,
VFMP_INSTANT_NONPAGED
} MEMORY_PERSISTANCE;
BOOLEAN
VfUtilIsMemoryRangeReadable(
IN PVOID Location,
IN size_t Length,
IN MEMORY_PERSISTANCE Persistance
);
VOID
VfSetVerifierEnabled (
LOGICAL Value
);

View File

@ -0,0 +1,70 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
vfwmi.h
Abstract:
This header contains prototypes for verifying System Control IRPs are
handled correctly.
--*/
VOID
VfWmiInit(
VOID
);
VOID
FASTCALL
VfWmiVerifyNewRequest(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfWmiVerifyIrpStackDownward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN PVOID CallerAddress OPTIONAL
);
VOID
FASTCALL
VfWmiVerifyIrpStackUpward(
IN PIOV_REQUEST_PACKET IovPacket,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION RequestHeadLocationData,
IN PIOV_STACK_LOCATION StackLocationData,
IN BOOLEAN IsNewlyCompleted,
IN BOOLEAN RequestFinalized
);
VOID
FASTCALL
VfWmiDumpIrpStack(
IN PIO_STACK_LOCATION IrpSp
);
VOID
FASTCALL
VfWmiTestStartedPdoStack(
IN PDEVICE_OBJECT PhysicalDeviceObject
);

1105
base/ntos/VERIFIER/vfzwapi.h Normal file

File diff suppressed because it is too large Load Diff

26
base/ntos/cache/BUILD/makefile vendored Normal file
View File

@ -0,0 +1,26 @@
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
# If you do not agree to the terms, do not use the code.
#
library = $(module)
asobjs=
ccarchobjs=
ccobjs= \
$(OBJ)\cachedat.obj \
$(OBJ)\cachesub.obj \
$(OBJ)\copysup.obj \
$(OBJ)\fssup.obj \
$(OBJ)\lazyrite.obj \
$(OBJ)\logsup.obj \
$(OBJ)\mdlsup.obj \
$(OBJ)\pinsup.obj \
$(OBJ)\ccperf.obj \
$(OBJ)\vacbsup.obj
!include $(ntos)\BUILD\makefile.build

195
base/ntos/cache/cachedat.c vendored Normal file
View File

@ -0,0 +1,195 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cachedat.c
Abstract:
This module implements the Memory Management based cache management
routines for the common Cache subsystem.
--*/
#include "cc.h"
//
// Global SharedCacheMap lists and resource to synchronize access to it.
//
//
// extern KSPIN_LOCK CcMasterSpinLock;
LIST_ENTRY CcCleanSharedCacheMapList;
SHARED_CACHE_MAP_LIST_CURSOR CcDirtySharedCacheMapList;
SHARED_CACHE_MAP_LIST_CURSOR CcLazyWriterCursor;
//
// Worker thread structures:
//
// A spinlock to synchronize all three lists.
// A count of the number of worker threads Cc will use
// A count of the number of worker threads Cc in use
// A listhead for preinitialized executive work items for Cc use.
// A listhead for an express queue of WORK_QUEUE_ENTRYs
// A listhead for a regular queue of WORK_QUEUE_ENTRYs
// A listhead for a post-tick queue of WORK_QUEUE_ENTRYs
//
// A flag indicating if we are throttling the queue to a single thread
//
// extern KSPIN_LOCK CcWorkQueueSpinLock;
ULONG CcNumberWorkerThreads = 0;
ULONG CcNumberActiveWorkerThreads = 0;
LIST_ENTRY CcIdleWorkerThreadList;
LIST_ENTRY CcExpressWorkQueue;
LIST_ENTRY CcRegularWorkQueue;
LIST_ENTRY CcPostTickWorkQueue;
BOOLEAN CcQueueThrottle = FALSE;
//
// Store the current idle delay and target time to clean all. We must calculate
// the idle delay in terms of clock ticks for the lazy writer timeout.
//
ULONG CcIdleDelayTick;
LARGE_INTEGER CcNoDelay;
LARGE_INTEGER CcFirstDelay = {(ULONG)-(3*LAZY_WRITER_IDLE_DELAY), -1};
LARGE_INTEGER CcIdleDelay = {(ULONG)-LAZY_WRITER_IDLE_DELAY, -1};
LARGE_INTEGER CcCollisionDelay = {(ULONG)-LAZY_WRITER_COLLISION_DELAY, -1};
LARGE_INTEGER CcTargetCleanDelay = {(ULONG)-(LONG)(LAZY_WRITER_IDLE_DELAY * (LAZY_WRITER_MAX_AGE_TARGET + 1)), -1};
//
// Spinlock for controlling access to Vacb and related global structures,
// and a counter indicating how many Vcbs are active.
//
// extern KSPIN_LOCK CcVacbSpinLock;
ULONG_PTR CcNumberVacbs;
//
// Pointer to the global Vacb vector.
//
PVACB CcVacbs;
PVACB CcBeyondVacbs;
LIST_ENTRY CcVacbLru;
LIST_ENTRY CcVacbFreeList;
ULONG CcMaxVacbLevelsSeen = 1;
ULONG CcVacbLevelEntries = 0;
PVACB *CcVacbLevelFreeList = NULL;
ULONG CcVacbLevelWithBcbsEntries = 0;
PVACB *CcVacbLevelWithBcbsFreeList = NULL;
//
// Deferred write list and respective Thresholds
//
extern ALIGNED_SPINLOCK CcDeferredWriteSpinLock;
LIST_ENTRY CcDeferredWrites;
ULONG CcDirtyPageThreshold;
ULONG CcDirtyPageTarget;
ULONG CcPagesYetToWrite;
ULONG CcPagesWrittenLastTime = 0;
ULONG CcDirtyPagesLastScan = 0;
ULONG CcAvailablePagesThreshold = 100;
ULONG CcTotalDirtyPages = 0;
//
// Captured system size
//
MM_SYSTEMSIZE CcCapturedSystemSize;
//
// Number of outstanding aggressive zeroers in the system. Used
// to throttle the activity.
//
LONG CcAggressiveZeroCount;
LONG CcAggressiveZeroThreshold;
//
// Tuning options du Jour
//
ULONG CcTune = 0;
//
// Global structure controlling lazy writer algorithms
//
LAZY_WRITER LazyWriter;
GENERAL_LOOKASIDE CcTwilightLookasideList;
//
// Global list of pinned Bcbs which may be examined for debug purposes
//
#if DBG
ULONG CcBcbCount;
LIST_ENTRY CcBcbList;
#endif
//
// Throw away miss counter.
//
ULONG CcThrowAway;
//
// Performance Counters
//
ULONG CcFastReadNoWait;
ULONG CcFastReadWait;
ULONG CcFastReadResourceMiss;
ULONG CcFastReadNotPossible;
ULONG CcFastMdlReadNoWait;
ULONG CcFastMdlReadWait;
ULONG CcFastMdlReadResourceMiss;
ULONG CcFastMdlReadNotPossible;
ULONG CcMapDataNoWait;
ULONG CcMapDataWait;
ULONG CcMapDataNoWaitMiss;
ULONG CcMapDataWaitMiss;
ULONG CcPinMappedDataCount;
ULONG CcPinReadNoWait;
ULONG CcPinReadWait;
ULONG CcPinReadNoWaitMiss;
ULONG CcPinReadWaitMiss;
ULONG CcCopyReadNoWait;
ULONG CcCopyReadWait;
ULONG CcCopyReadNoWaitMiss;
ULONG CcCopyReadWaitMiss;
ULONG CcMdlReadNoWait;
ULONG CcMdlReadWait;
ULONG CcMdlReadNoWaitMiss;
ULONG CcMdlReadWaitMiss;
ULONG CcReadAheadIos;
ULONG CcLazyWriteHotSpots;
ULONG CcLazyWriteIos;
ULONG CcLazyWritePages;
ULONG CcDataFlushes;
ULONG CcDataPages;
ULONG CcLostDelayedWrites;
PULONG CcMissCounter = &CcThrowAway;

6857
base/ntos/cache/cachesub.c vendored Normal file

File diff suppressed because it is too large Load Diff

2190
base/ntos/cache/cc.h vendored Normal file

File diff suppressed because it is too large Load Diff

104
base/ntos/cache/ccperf.c vendored Normal file
View File

@ -0,0 +1,104 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
CcPerf.c
Abstract:
This module contains the perf trace routines in Cc Component
--*/
#include "cc.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEWMI, CcPerfFileRunDown)
#endif //ALLOC_PRAGMA
VOID
CcPerfFileRunDown(
PPERFINFO_ENTRY_TABLE HashTable
)
/*++
Routine Description:
This routine walks the following lists:
1. CcDirtySharedCacheMapList
2. CcCleanSharedCacheMapList
and returns a pointer to a pool allocation
containing the referenced file object pointers.
Arguments:
None.
Return Value:
Returns a pointer to a NULL terminated pool allocation
containing the file object pointers from the two lists,
NULL if the memory could not be allocated.
It is also the responsibility of the caller to dereference each
file object in the list and then free the returned pool.
Environment:
PASSIVE_LEVEL, arbitrary thread context.
--*/
{
KIRQL OldIrql;
PSHARED_CACHE_MAP SharedCacheMap;
ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
CcAcquireMasterLock( &OldIrql );
//
// Walk through CcDirtySharedCacheMapList
//
SharedCacheMap = CONTAINING_RECORD( CcDirtySharedCacheMapList.SharedCacheMapLinks.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
while (&SharedCacheMap->SharedCacheMapLinks != &CcDirtySharedCacheMapList.SharedCacheMapLinks) {
//
// Skip over cursors
//
if (!FlagOn(SharedCacheMap->Flags, IS_CURSOR)) {
PerfInfoAddToFileHash(HashTable, SharedCacheMap->FileObject);
}
SharedCacheMap = CONTAINING_RECORD( SharedCacheMap->SharedCacheMapLinks.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
}
//
// CcCleanSharedCacheMapList
//
SharedCacheMap = CONTAINING_RECORD( CcCleanSharedCacheMapList.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
while (&SharedCacheMap->SharedCacheMapLinks != &CcCleanSharedCacheMapList) {
PerfInfoAddToFileHash(HashTable, SharedCacheMap->FileObject);
SharedCacheMap = CONTAINING_RECORD( SharedCacheMap->SharedCacheMapLinks.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
}
CcReleaseMasterLock( OldIrql );
return;
}

2175
base/ntos/cache/copysup.c vendored Normal file

File diff suppressed because it is too large Load Diff

4000
base/ntos/cache/fssup.c vendored Normal file

File diff suppressed because it is too large Load Diff

1056
base/ntos/cache/lazyrite.c vendored Normal file

File diff suppressed because it is too large Load Diff

699
base/ntos/cache/logsup.c vendored Normal file
View File

@ -0,0 +1,699 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
logsup.c
Abstract:
This module implements the special cache manager support for logging
file systems.
--*/
#include "cc.h"
//
// Define our debug constant
//
#define me 0x0000040
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CcSetLogHandleForFile)
#endif
VOID
CcSetAdditionalCacheAttributes (
__in PFILE_OBJECT FileObject,
__in BOOLEAN DisableReadAhead,
__in BOOLEAN DisableWriteBehind
)
/*++
Routine Description:
This routine supports the setting of disable read ahead or disable write
behind flags to control Cache Manager operation. This routine may be
called any time after calling CcInitializeCacheMap. Initially both
read ahead and write behind are enabled. Note that the state of both
of these flags must be specified on each call to this routine.
Arguments:
FileObject - File object for which the respective flags are to be set.
DisableReadAhead - FALSE to enable read ahead, TRUE to disable it.
DisableWriteBehind - FALSE to enable write behind, TRUE to disable it.
Return Value:
None.
--*/
{
PSHARED_CACHE_MAP SharedCacheMap;
KIRQL OldIrql;
//
// Get pointer to SharedCacheMap.
//
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
//
// Now set the flags and return.
//
CcAcquireMasterLock( &OldIrql );
if (DisableReadAhead) {
SetFlag(SharedCacheMap->Flags, DISABLE_READ_AHEAD);
} else {
ClearFlag(SharedCacheMap->Flags, DISABLE_READ_AHEAD);
}
if (DisableWriteBehind) {
SetFlag(SharedCacheMap->Flags, DISABLE_WRITE_BEHIND | MODIFIED_WRITE_DISABLED);
} else {
ClearFlag(SharedCacheMap->Flags, DISABLE_WRITE_BEHIND);
}
CcReleaseMasterLock( OldIrql );
}
NTKERNELAPI
BOOLEAN
CcSetPrivateWriteFile(
PFILE_OBJECT FileObject
)
/*++
Routine Description:
This routine will instruct the cache manager to treat the file as
a private-write stream, so that a caller can implement a private
logging mechanism for it. We will turn on both Mm's modify-no-write
and our disable-write-behind, and disallow non-aware flush/purge for
the file.
Caching must already be initiated on the file.
This routine is only exported to the kernel.
Arguments:
FileObject - File to make private-write.
Return Value:
None.
--*/
{
PSHARED_CACHE_MAP SharedCacheMap;
BOOLEAN Disabled;
KIRQL OldIrql;
PVACB Vacb;
ULONG ActivePage;
ULONG PageIsDirty;
//
// Pick up the file exclusive to synchronize against readahead and
// other purge/map activity.
//
FsRtlAcquireFileExclusive( FileObject );
//
// Get a pointer to the SharedCacheMap. Be sure to release the FileObject
// in case an error condition forces a premature exit.
//
if ((FileObject->SectionObjectPointer == NULL) ||
((SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap) == NULL)){
FsRtlReleaseFile( FileObject );
return FALSE;
}
//
// Unmap all the views in preparation for making the disable mw call.
//
//
// We still need to wait for any dangling cache read or writes.
//
// In fact we have to loop and wait because the lazy writer can
// sneak in and do an CcGetVirtualAddressIfMapped, and we are not
// synchronized.
//
// This is the same bit of code that our purge will do. We assume
// that a private writer has succesfully blocked out other activity.
//
//
// If there is an active Vacb, then delete it now (before waiting!).
//
CcAcquireMasterLock( &OldIrql );
GetActiveVacbAtDpcLevel( SharedCacheMap, Vacb, ActivePage, PageIsDirty );
CcReleaseMasterLock( OldIrql );
if (Vacb != NULL) {
CcFreeActiveVacb( SharedCacheMap, Vacb, ActivePage, PageIsDirty );
}
while ((SharedCacheMap->Vacbs != NULL) &&
!CcUnmapVacbArray( SharedCacheMap, NULL, 0, FALSE )) {
CcWaitOnActiveCount( SharedCacheMap );
}
//
// Knock the file down.
//
CcFlushCache( FileObject->SectionObjectPointer, NULL, 0, NULL );
//
// Now the file is clean and unmapped. We can still have a racing
// lazy writer, though.
//
// We just wait for the lazy writer queue to drain before disabling
// modified write. There may be a better way to do this by having
// an event for the WRITE_QUEUED flag. ? This would also let us
// dispense with the pagingio pick/drop in the FS cache coherency
// paths, but there could be reasons why CcFlushCache shouldn't
// always do such a block. Investigate this.
//
// This wait takes on the order of ~.5s avg. case.
//
CcAcquireMasterLock( &OldIrql );
if (FlagOn( SharedCacheMap->Flags, WRITE_QUEUED ) ||
FlagOn( SharedCacheMap->Flags, READ_AHEAD_QUEUED )) {
CcReleaseMasterLock( OldIrql );
FsRtlReleaseFile( FileObject );
CcWaitForCurrentLazyWriterActivity();
FsRtlAcquireFileExclusive( FileObject );
} else {
CcReleaseMasterLock( OldIrql );
}
//
// Now set the flags and return. We do not set our MODIFIED_WRITE_DISABLED
// since we don't want to fully promote this cache map. Future?
//
Disabled = MmDisableModifiedWriteOfSection( FileObject->SectionObjectPointer );
if (Disabled) {
CcAcquireMasterLock( &OldIrql );
SetFlag(SharedCacheMap->Flags, DISABLE_WRITE_BEHIND | PRIVATE_WRITE);
CcReleaseMasterLock( OldIrql );
}
//
// Now release the file for regular operation.
//
FsRtlReleaseFile( FileObject );
return Disabled;
}
VOID
CcSetLogHandleForFile (
__in PFILE_OBJECT FileObject,
__in PVOID LogHandle,
__in PFLUSH_TO_LSN FlushToLsnRoutine
)
/*++
Routine Description:
This routine may be called to instruct the Cache Manager to store the
specified log handle with the shared cache map for a file, to support
subsequent calls to the other routines in this module which effectively
perform an associative search for files by log handle.
Arguments:
FileObject - File for which the log handle should be stored.
LogHandle - Log Handle to store.
FlushToLsnRoutine - A routine to call before flushing buffers for this
file, to ensure a log file is flushed to the most
recent Lsn for any Bcb being flushed.
Return Value:
None.
--*/
{
PSHARED_CACHE_MAP SharedCacheMap;
//
// Get pointer to SharedCacheMap.
//
SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
//
// Now set the log file handle and flush routine
//
SharedCacheMap->LogHandle = LogHandle;
SharedCacheMap->FlushToLsnRoutine = FlushToLsnRoutine;
}
LARGE_INTEGER
CcGetDirtyPages (
__in PVOID LogHandle,
__in PDIRTY_PAGE_ROUTINE DirtyPageRoutine,
__in PVOID Context1,
__in PVOID Context2
)
/*++
Routine Description:
This routine may be called to return all of the dirty pages in all files
for a given log handle. Each page is returned by an individual call to
the Dirty Page Routine. The Dirty Page Routine is defined by a prototype
in ntos\inc\cache.h.
Arguments:
LogHandle - Log Handle which must match the log handle previously stored
for all files which are to be returned.
DirtyPageRoutine -- The routine to call as each dirty page for this log
handle is found.
Context1 - First context parameter to be passed to the Dirty Page Routine.
Context2 - First context parameter to be passed to the Dirty Page Routine.
Return Value:
LARGE_INTEGER - Oldest Lsn found of all the dirty pages, or 0 if no dirty pages
--*/
{
PSHARED_CACHE_MAP SharedCacheMap;
PBCB Bcb, BcbToUnpin = NULL;
KLOCK_QUEUE_HANDLE LockHandle;
LARGE_INTEGER SavedFileOffset, SavedOldestLsn, SavedNewestLsn;
ULONG SavedByteLength;
LARGE_INTEGER OldestLsn = {0,0};
//
// Synchronize with changes to the SharedCacheMap list.
//
CcAcquireMasterLock( &LockHandle.OldIrql );
SharedCacheMap = CONTAINING_RECORD( CcDirtySharedCacheMapList.SharedCacheMapLinks.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
//
// Use try/finally for cleanup. The only spot where we can raise is out of the
// filesystem callback, but we have the exception handler out here so we aren't
// constantly setting/unsetting it.
//
try {
while (&SharedCacheMap->SharedCacheMapLinks != &CcDirtySharedCacheMapList.SharedCacheMapLinks) {
//
// Skip over cursors, SharedCacheMaps for other LogHandles, and ones with
// no dirty pages
//
if (!FlagOn(SharedCacheMap->Flags, IS_CURSOR) && (SharedCacheMap->LogHandle == LogHandle) &&
(SharedCacheMap->DirtyPages != 0)) {
//
// This SharedCacheMap should stick around for a while in the dirty list.
//
CcIncrementOpenCount( SharedCacheMap, 'pdGS' );
SharedCacheMap->DirtyPages += 1;
CcReleaseMasterLock( LockHandle.OldIrql );
//
// Set our initial resume point and point to first Bcb in List.
//
KeAcquireInStackQueuedSpinLock( &SharedCacheMap->BcbSpinLock, &LockHandle );
Bcb = CONTAINING_RECORD( SharedCacheMap->BcbList.Flink, BCB, BcbLinks );
//
// Scan to the end of the Bcb list.
//
while (&Bcb->BcbLinks != &SharedCacheMap->BcbList) {
//
// If the Bcb is dirty, then capture the inputs for the
// callback routine so we can call without holding a spinlock.
//
if ((Bcb->NodeTypeCode == CACHE_NTC_BCB) && Bcb->Dirty) {
SavedFileOffset = Bcb->FileOffset;
SavedByteLength = Bcb->ByteLength;
SavedOldestLsn = Bcb->OldestLsn;
SavedNewestLsn = Bcb->NewestLsn;
//
// Increment PinCount so the Bcb sticks around
//
Bcb->PinCount += 1;
KeReleaseInStackQueuedSpinLock( &LockHandle );
//
// Any Bcb to unref from a previous loop?
//
if (BcbToUnpin != NULL) {
CcUnpinFileData( BcbToUnpin, TRUE, UNREF );
BcbToUnpin = NULL;
}
//
// Call the file system. This callback may raise status.
//
(*DirtyPageRoutine)( SharedCacheMap->FileObject,
&SavedFileOffset,
SavedByteLength,
&SavedOldestLsn,
&SavedNewestLsn,
Context1,
Context2 );
//
// Possibly update OldestLsn
//
if ((SavedOldestLsn.QuadPart != 0) &&
((OldestLsn.QuadPart == 0) || (SavedOldestLsn.QuadPart < OldestLsn.QuadPart ))) {
OldestLsn = SavedOldestLsn;
}
//
// Now reacquire the spinlock and scan from the resume point
// point to the next Bcb to return in the descending list.
//
KeAcquireInStackQueuedSpinLock( &SharedCacheMap->BcbSpinLock, &LockHandle );
//
// Normally the Bcb can stay around a while, but if not,
// we will just remember it for the next time we do not
// have the spin lock. We cannot unpin it now, because
// we would lose our place in the list.
//
// This is cheating, but it works and is sane since we're
// already traversing the bcb list - dropping the bcb count
// is OK, as long as we don't hit zero. Zero requires a
// slight bit more attention that shouldn't be replicated.
// (unmapping the view)
//
if (Bcb->PinCount > 1) {
Bcb->PinCount -= 1;
} else {
BcbToUnpin = Bcb;
}
}
Bcb = CONTAINING_RECORD( Bcb->BcbLinks.Flink, BCB, BcbLinks );
}
KeReleaseInStackQueuedSpinLock( &LockHandle );
//
// We need to unref any Bcb we are holding before moving on to
// the next SharedCacheMap, or else CcDeleteSharedCacheMap will
// also delete this Bcb.
//
if (BcbToUnpin != NULL) {
CcUnpinFileData( BcbToUnpin, TRUE, UNREF );
BcbToUnpin = NULL;
}
CcAcquireMasterLock( &LockHandle.OldIrql );
//
// Now release the SharedCacheMap, leaving it in the dirty list.
//
CcDecrementOpenCount( SharedCacheMap, 'pdGF' );
SharedCacheMap->DirtyPages -= 1;
}
//
// Now loop back for the next cache map.
//
SharedCacheMap =
CONTAINING_RECORD( SharedCacheMap->SharedCacheMapLinks.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
}
CcReleaseMasterLock( LockHandle.OldIrql );
} finally {
//
// Drop the Bcb if we are being ejected. We are guaranteed that the
// only raise is from the callback, at which point we have an incremented
// pincount.
//
if (AbnormalTermination()) {
CcUnpinFileData( Bcb, TRUE, UNPIN );
}
}
return OldestLsn;
}
BOOLEAN
CcIsThereDirtyData (
__in PVPB Vpb
)
/*++
Routine Description:
This routine returns TRUE if the specified Vcb has any unwritten dirty
data in the cache.
Arguments:
Vpb - specifies Vpb to check for
Return Value:
FALSE - if the Vpb has no dirty data
TRUE - if the Vpb has dirty data
--*/
{
PSHARED_CACHE_MAP SharedCacheMap;
KIRQL OldIrql;
ULONG LoopsWithLockHeld = 0;
//
// Synchronize with changes to the SharedCacheMap list.
//
CcAcquireMasterLock( &OldIrql );
SharedCacheMap = CONTAINING_RECORD( CcDirtySharedCacheMapList.SharedCacheMapLinks.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
while (&SharedCacheMap->SharedCacheMapLinks != &CcDirtySharedCacheMapList.SharedCacheMapLinks) {
//
// Look at this one if the Vpb matches and if there is dirty data.
// For what it's worth, don't worry about dirty data in temporary files,
// as that should not concern the caller if it wants to dismount.
//
if (!FlagOn(SharedCacheMap->Flags, IS_CURSOR) &&
(SharedCacheMap->FileObject->Vpb == Vpb) &&
(SharedCacheMap->DirtyPages != 0) &&
!FlagOn(SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) {
CcReleaseMasterLock( OldIrql );
return TRUE;
}
//
// Make sure we occasionally drop the lock. Set WRITE_QUEUED
// to keep the guy from going away, and increment DirtyPages to
// keep it in this list.
//
if ((++LoopsWithLockHeld >= 20) &&
!FlagOn(SharedCacheMap->Flags, WRITE_QUEUED | IS_CURSOR)) {
SetFlag( *((ULONG volatile *)&SharedCacheMap->Flags), WRITE_QUEUED);
*((ULONG volatile *)&SharedCacheMap->DirtyPages) += 1;
CcReleaseMasterLock( OldIrql );
LoopsWithLockHeld = 0;
CcAcquireMasterLock( &OldIrql );
ClearFlag( *((ULONG volatile *)&SharedCacheMap->Flags), WRITE_QUEUED);
*((ULONG volatile *)&SharedCacheMap->DirtyPages) -= 1;
}
//
// Now loop back for the next cache map.
//
SharedCacheMap =
CONTAINING_RECORD( SharedCacheMap->SharedCacheMapLinks.Flink,
SHARED_CACHE_MAP,
SharedCacheMapLinks );
}
CcReleaseMasterLock( OldIrql );
return FALSE;
}
LARGE_INTEGER
CcGetLsnForFileObject(
__in PFILE_OBJECT FileObject,
__out_opt PLARGE_INTEGER OldestLsn
)
/*++
Routine Description:
This routine returns the oldest and newest LSNs for a file object.
Arguments:
FileObject - File for which the log handle should be stored.
OldestLsn - pointer to location to store oldest LSN for file object.
Return Value:
The newest LSN for the file object.
--*/
{
PBCB Bcb;
KLOCK_QUEUE_HANDLE LockHandle;
LARGE_INTEGER Oldest, Newest;
PSHARED_CACHE_MAP SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
//
// initialize lsn variables
//
Oldest.LowPart = 0;
Oldest.HighPart = 0;
Newest.LowPart = 0;
Newest.HighPart = 0;
if(SharedCacheMap == NULL) {
return Oldest;
}
KeAcquireInStackQueuedSpinLock(&SharedCacheMap->BcbSpinLock, &LockHandle);
//
// Now point to first Bcb in List, and loop through it.
//
Bcb = CONTAINING_RECORD( SharedCacheMap->BcbList.Flink, BCB, BcbLinks );
while (&Bcb->BcbLinks != &SharedCacheMap->BcbList) {
//
// If the Bcb is dirty then capture the oldest and newest lsn
//
if ((Bcb->NodeTypeCode == CACHE_NTC_BCB) && Bcb->Dirty) {
LARGE_INTEGER BcbLsn, BcbNewest;
BcbLsn = Bcb->OldestLsn;
BcbNewest = Bcb->NewestLsn;
if ((BcbLsn.QuadPart != 0) &&
((Oldest.QuadPart == 0) ||
(BcbLsn.QuadPart < Oldest.QuadPart))) {
Oldest = BcbLsn;
}
if ((BcbLsn.QuadPart != 0) && (BcbNewest.QuadPart > Newest.QuadPart)) {
Newest = BcbNewest;
}
}
Bcb = CONTAINING_RECORD( Bcb->BcbLinks.Flink, BCB, BcbLinks );
}
//
// Now release the spin lock for this Bcb list and generate a callback
// if we got something.
//
KeReleaseInStackQueuedSpinLock( &LockHandle );
if (ARGUMENT_PRESENT(OldestLsn)) {
*OldestLsn = Oldest;
}
return Newest;
}

1161
base/ntos/cache/mdlsup.c vendored Normal file

File diff suppressed because it is too large Load Diff

1565
base/ntos/cache/pinsup.c vendored Normal file

File diff suppressed because it is too large Load Diff

3425
base/ntos/cache/vacbsup.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
# If you do not agree to the terms, do not use the code.
#
library = $(module)
specialcflags = -D_WANT_MACHINE_IDENTIFICATION
asobjs=
ccarchobjs=
ccobjs= \
$(OBJ)\cmapi.obj \
$(OBJ)\cmapi2.obj \
$(OBJ)\cmboot.obj \
$(OBJ)\cmchek.obj \
$(OBJ)\cmchek2.obj \
$(OBJ)\cmclose.obj \
$(OBJ)\cmconfig.obj \
$(OBJ)\cmcontrl.obj \
$(OBJ)\cmdat.obj \
$(OBJ)\cmdat2.obj \
$(OBJ)\cmdatini.obj \
$(OBJ)\cmdelete.obj \
$(OBJ)\cmgquota.obj \
$(OBJ)\cmhvlist.obj \
$(OBJ)\cmindex.obj \
$(OBJ)\cminit.obj \
$(OBJ)\cmname.obj \
$(OBJ)\cmnotify.obj \
$(OBJ)\cmparse.obj \
$(OBJ)\cmparse2.obj \
$(OBJ)\cmquery.obj \
$(OBJ)\cmsavres.obj \
$(OBJ)\cmsubs.obj \
$(OBJ)\cmsubs2.obj \
$(OBJ)\cmsubs3.obj \
$(OBJ)\cmse.obj \
$(OBJ)\cmsysini.obj \
$(OBJ)\cmtrecpy.obj \
$(OBJ)\cmtredel.obj \
$(OBJ)\cmtree.obj \
$(OBJ)\cmworker.obj \
$(OBJ)\cmwrapr.obj \
$(OBJ)\cmwrapr2.obj \
$(OBJ)\cmwmi.obj \
$(OBJ)\cmmapvw.obj \
$(OBJ)\cmdelay.obj \
$(OBJ)\cmvalue.obj \
$(OBJ)\cmsecache.obj \
$(OBJ)\cmdown.obj \
$(OBJ)\cmalloc.obj \
$(OBJ)\cmhook.obj \
$(OBJ)\hivebin.obj \
$(OBJ)\hivecell.obj \
$(OBJ)\hivechek.obj \
$(OBJ)\hivefree.obj \
$(OBJ)\hiveinit.obj \
$(OBJ)\hiveload.obj \
$(OBJ)\hivemap.obj \
$(OBJ)\hivesum.obj \
$(OBJ)\hivesync.obj \
$(OBJ)\hivehint.obj \
$(OBJ)\ntapi.obj
!include $(ntos)\BUILD\makefile.build

554
base/ntos/config/cmalloc.c Normal file
View File

@ -0,0 +1,554 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmalloc.c
Abstract:
Provides routines for implementing the registry's own pool allocator.
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpInitCmPrivateAlloc)
#pragma alloc_text(PAGE,CmpDestroyCmPrivateAlloc)
#pragma alloc_text(PAGE,CmpAllocateKeyControlBlock)
#pragma alloc_text(PAGE,CmpFreeKeyControlBlock)
#pragma alloc_text(INIT,CmpInitCmPrivateDelayAlloc)
#pragma alloc_text(PAGE,CmpDestroyCmPrivateDelayAlloc)
#pragma alloc_text(PAGE,CmpAllocateDelayItem)
#pragma alloc_text(PAGE,CmpFreeDelayItem)
#endif
typedef struct _CM_ALLOC_PAGE {
ULONG FreeCount; // number of free kcbs
ULONG Reserved; // alignment
PVOID AllocPage; // crud allocations - this member is NOT USED
} CM_ALLOC_PAGE, *PCM_ALLOC_PAGE;
#define CM_KCB_ENTRY_SIZE sizeof( CM_KEY_CONTROL_BLOCK )
#define CM_KCBS_PER_PAGE ((PAGE_SIZE - FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage)) / CM_KCB_ENTRY_SIZE)
#define KCB_TO_PAGE_ADDRESS( kcb ) (PVOID)(((ULONG_PTR)(kcb)) & ~(PAGE_SIZE - 1))
#define KCB_TO_ALLOC_PAGE( kcb ) ((PCM_ALLOC_PAGE)KCB_TO_PAGE_ADDRESS(kcb))
LIST_ENTRY CmpFreeKCBListHead; // list of free kcbs
BOOLEAN CmpAllocInited = FALSE;
KGUARDED_MUTEX CmpAllocBucketLock; // used to protect the bucket
#define LOCK_ALLOC_BUCKET() KeAcquireGuardedMutex(&CmpAllocBucketLock)
#define UNLOCK_ALLOC_BUCKET() KeReleaseGuardedMutex(&CmpAllocBucketLock)
VOID
CmpInitCmPrivateAlloc( )
/*++
Routine Description:
Initialize the CmPrivate pool allocation module
Arguments:
Return Value:
--*/
{
if( CmpAllocInited ) {
//
// already initialized
//
return;
}
InitializeListHead(&(CmpFreeKCBListHead));
//
// init the bucket lock
//
KeInitializeGuardedMutex(&CmpAllocBucketLock);
CmpAllocInited = TRUE;
}
VOID
CmpDestroyCmPrivateAlloc( )
/*++
Routine Description:
Frees memory used byt the CmPrivate pool allocation module
Arguments:
Return Value:
--*/
{
PAGED_CODE();
if( !CmpAllocInited ) {
return;
}
}
PCM_KEY_CONTROL_BLOCK
CmpAllocateKeyControlBlock( )
/*++
Routine Description:
Allocates a kcb; first try from our own allocator.
If it doesn't work (we have maxed out our number of allocs
or private allocator is not initialized)
try from paged pool
Arguments:
Return Value:
The new kcb
--*/
{
USHORT j;
PCM_KEY_CONTROL_BLOCK kcb = NULL;
PCM_ALLOC_PAGE AllocPage;
PAGED_CODE();
if( !CmpAllocInited ) {
//
// not initialized
//
goto AllocFromPool;
}
LOCK_ALLOC_BUCKET();
SearchFreeKcb:
//
// try to find a free one
//
if( IsListEmpty(&CmpFreeKCBListHead) == FALSE ) {
//
// found one
//
kcb = (PCM_KEY_CONTROL_BLOCK)RemoveHeadList(&CmpFreeKCBListHead);
kcb = CONTAINING_RECORD(kcb,
CM_KEY_CONTROL_BLOCK,
FreeListEntry);
AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
ASSERT( AllocPage->FreeCount != 0 );
AllocPage->FreeCount--;
//
// set when page was allocated
//
ASSERT( kcb->PrivateAlloc == 1);
UNLOCK_ALLOC_BUCKET();
return kcb;
}
//
// we need to allocate a new page as we ran out of free kcbs
//
//
// allocate a new page and insert all kcbs in the freelist
//
AllocPage = (PCM_ALLOC_PAGE)ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, CM_ALLOCATE_TAG|PROTECTED_POOL);
if( AllocPage == NULL ) {
//
// we might be low on pool; maybe small pool chunks will work
//
UNLOCK_ALLOC_BUCKET();
goto AllocFromPool;
}
//
// set up the page
//
AllocPage->FreeCount = CM_KCBS_PER_PAGE;
//
// now the dirty job; insert all kcbs inside the page in the free list
//
for(j=0;j<CM_KCBS_PER_PAGE;j++) {
kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
//
// set it here; only once
//
kcb->PrivateAlloc = 1;
kcb->DelayCloseEntry = NULL;
InsertTailList(
&CmpFreeKCBListHead,
&(kcb->FreeListEntry)
);
}
//
// this time will find one for sure
//
goto SearchFreeKcb;
AllocFromPool:
kcb = ExAllocatePoolWithTag(PagedPool,
sizeof(CM_KEY_CONTROL_BLOCK),
CM_KCB_TAG | PROTECTED_POOL);
if( kcb != NULL ) {
//
// clear the private alloc flag
//
kcb->PrivateAlloc = 0;
kcb->DelayCloseEntry = NULL;
}
return kcb;
}
#define LogKCBFree(kcb) //nothing
VOID
CmpFreeKeyControlBlock( PCM_KEY_CONTROL_BLOCK kcb )
/*++
Routine Description:
Frees a kcb; if it's allocated from our own pool put it back in the free list.
If it's allocated from general pool, just free it.
Arguments:
kcb to free
Return Value:
--*/
{
USHORT j;
PCM_ALLOC_PAGE AllocPage;
PAGED_CODE();
ASSERT_KEYBODY_LIST_EMPTY(kcb);
#if defined(_WIN64)
//
// free cached name if any
//
if( (kcb->RealKeyName != NULL) && (kcb->RealKeyName != CMP_KCB_REAL_NAME_UPCASE) ) {
ExFreePoolWithTag(kcb->RealKeyName, CM_NAME_TAG);
}
#endif
if( !kcb->PrivateAlloc ) {
//
// just free it and be done with it
//
ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
return;
}
LOCK_ALLOC_BUCKET();
ASSERT_HASH_ENTRY_LOCKED_EXCLUSIVE(kcb->ConvKey);
LogKCBFree(kcb);
//
// add kcb to freelist
//
InsertTailList(
&CmpFreeKCBListHead,
&(kcb->FreeListEntry)
);
//
// get the page
//
AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
//
// not all are free
//
ASSERT( AllocPage->FreeCount != CM_KCBS_PER_PAGE);
AllocPage->FreeCount++;
if( AllocPage->FreeCount == CM_KCBS_PER_PAGE ) {
//
// entire page is free; let it go
//
//
// first; iterate through the free kcb list and remove all kcbs inside this page
//
for(j=0;j<CM_KCBS_PER_PAGE;j++) {
kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
RemoveEntryList(&(kcb->FreeListEntry));
}
ExFreePoolWithTag(AllocPage, CM_ALLOCATE_TAG|PROTECTED_POOL);
}
UNLOCK_ALLOC_BUCKET();
}
//
// delay deref and delay close private allocator
//
LIST_ENTRY CmpFreeDelayItemsListHead; // list of free delay items
KGUARDED_MUTEX CmpDelayAllocBucketLock; // used to protect the bucket
#define LOCK_DELAY_ALLOC_BUCKET() KeAcquireGuardedMutex(&CmpDelayAllocBucketLock)
#define UNLOCK_DELAY_ALLOC_BUCKET() KeReleaseGuardedMutex(&CmpDelayAllocBucketLock)
#define CM_DELAY_ALLOC_ENTRY_SIZE sizeof( CM_DELAY_ALLOC )
#define CM_DELAYS_PER_PAGE ((PAGE_SIZE - FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage)) / CM_DELAY_ALLOC_ENTRY_SIZE)
#define DELAY_ALLOC_TO_PAGE_ADDRESS( delay ) (PVOID)(((ULONG_PTR)(delay)) & ~(PAGE_SIZE - 1))
#define DELAY_ALLOC_TO_ALLOC_PAGE( delay ) ((PCM_ALLOC_PAGE)DELAY_ALLOC_TO_PAGE_ADDRESS(delay))
VOID
CmpInitCmPrivateDelayAlloc( )
/*++
Routine Description:
Initialize the CmPrivate pool allocation module for delay related allocs
Arguments:
Return Value:
--*/
{
InitializeListHead(&(CmpFreeDelayItemsListHead));
//
// init the bucket lock
//
KeInitializeGuardedMutex(&CmpDelayAllocBucketLock);
}
VOID
CmpDestroyCmPrivateDelayAlloc( )
/*++
Routine Description:
Frees memory used by the CmPrivate pool allocation module
Arguments:
Return Value:
--*/
{
CM_PAGED_CODE();
}
PVOID
CmpAllocateDelayItem( )
/*++
Routine Description:
Allocates a delay item from our own pool;
Arguments:
Return Value:
The new item
--*/
{
USHORT j;
PCM_DELAY_ALLOC DelayItem = NULL;
PCM_ALLOC_PAGE AllocPage;
CM_PAGED_CODE();
LOCK_DELAY_ALLOC_BUCKET();
SearchFreeItem:
//
// try to find a free one
//
if( CmpIsListEmpty(&CmpFreeDelayItemsListHead) == FALSE ) {
//
// found one
//
DelayItem = (PCM_DELAY_ALLOC)RemoveHeadList(&CmpFreeDelayItemsListHead);
DelayItem = CONTAINING_RECORD( DelayItem,
CM_DELAY_ALLOC,
ListEntry);
CmpClearListEntry(&(DelayItem->ListEntry));
AllocPage = (PCM_ALLOC_PAGE)DELAY_ALLOC_TO_ALLOC_PAGE( DelayItem );
ASSERT( AllocPage->FreeCount != 0 );
AllocPage->FreeCount--;
UNLOCK_DELAY_ALLOC_BUCKET();
return DelayItem;
}
//
// we need to allocate a new page as we ran out of free items
//
//
// allocate a new page and insert all kcbs in the freelist
//
AllocPage = (PCM_ALLOC_PAGE)ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, CM_ALLOCATE_TAG|PROTECTED_POOL);
if( AllocPage == NULL ) {
//
// bad luck
//
UNLOCK_DELAY_ALLOC_BUCKET();
return NULL;
}
//
// set up the page
//
AllocPage->FreeCount = CM_DELAYS_PER_PAGE;
//
// now the dirty job; insert all items inside the page in the free list
//
for(j=0;j<CM_DELAYS_PER_PAGE;j++) {
DelayItem = (PCM_DELAY_ALLOC)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_DELAY_ALLOC_ENTRY_SIZE);
InsertTailList(
&CmpFreeDelayItemsListHead,
&(DelayItem->ListEntry)
);
DelayItem->Kcb = NULL;
}
//
// this time will find one for sure
//
goto SearchFreeItem;
}
extern LIST_ENTRY CmpDelayDerefKCBListHead;
extern LIST_ENTRY CmpDelayedLRUListHead;
VOID
CmpFreeDelayItem( PVOID Item )
/*++
Routine Description:
Frees a kcb; if it's allocated from our own pool put it back in the free list.
If it's allocated from general pool, just free it.
Arguments:
kcb to free
Return Value:
--*/
{
USHORT j;
PCM_ALLOC_PAGE AllocPage;
PCM_DELAY_ALLOC DelayItem = (PCM_DELAY_ALLOC)Item;
CM_PAGED_CODE();
LOCK_DELAY_ALLOC_BUCKET();
//
// add kcb to freelist
//
InsertTailList(
&CmpFreeDelayItemsListHead,
&(DelayItem->ListEntry)
);
//
// get the page
//
AllocPage = (PCM_ALLOC_PAGE)DELAY_ALLOC_TO_ALLOC_PAGE( DelayItem );
//
// not all are free
//
ASSERT( AllocPage->FreeCount != CM_DELAYS_PER_PAGE);
AllocPage->FreeCount++;
if( AllocPage->FreeCount == CM_DELAYS_PER_PAGE ) {
//
// entire page is free; let it go
//
//
// first; iterate through the free item list and remove all items inside this page
//
for(j=0;j<CM_DELAYS_PER_PAGE;j++) {
DelayItem = (PCM_DELAY_ALLOC)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_DELAY_ALLOC_ENTRY_SIZE);
CmpRemoveEntryList(&(DelayItem->ListEntry));
}
ExFreePoolWithTag(AllocPage, CM_ALLOCATE_TAG|PROTECTED_POOL);
}
UNLOCK_DELAY_ALLOC_BUCKET();
}

4856
base/ntos/config/cmapi.c Normal file

File diff suppressed because it is too large Load Diff

195
base/ntos/config/cmapi2.c Normal file
View File

@ -0,0 +1,195 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmapi2.c
Abstract:
This module contains CM level entry points for the registry,
particularly those which we don't want to link into tools,
setup, the boot loader, etc.
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmDeleteKey)
#endif
NTSTATUS
CmDeleteKey(
IN PCM_KEY_BODY KeyBody
)
/*++
Routine Description:
Delete a registry key, clean up Notify block.
Arguments:
KeyBody - pointer to key handle object
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PCM_KEY_NODE ptarget;
PHHIVE Hive;
HCELL_INDEX Cell;
HCELL_INDEX Parent;
PCM_KEY_CONTROL_BLOCK KeyControlBlock;
LARGE_INTEGER TimeStamp;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_CM,"CmDeleteKey\n"));
CmpLockRegistry();
//
// If already marked for deletion, storage is gone, so
// do nothing and return success.
//
KeyControlBlock = KeyBody->KeyControlBlock;
if( KeyControlBlock->ParentKcb == NULL ) {
//
// cannot delete \Registry
//
CmpUnlockRegistry();
return STATUS_CANNOT_DELETE;
}
PERFINFO_REG_DELETE_KEY(KeyControlBlock);
//
// serialize access to this key. and its parent
// need to lock them both atomically
//
CmpLockTwoHashEntriesExclusive(KeyControlBlock->ConvKey,KeyControlBlock->ParentKcb->ConvKey);
if (KeyControlBlock->Delete == TRUE) {
status = STATUS_SUCCESS;
goto Exit;
}
Hive = KeyControlBlock->KeyHive;
Cell = KeyControlBlock->KeyCell;
//
// no flush from this point on
//
CmpLockHiveFlusherShared((PCMHIVE)KeyControlBlock->KeyHive);
// Mark the hive as read only
CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive);
ptarget = (PCM_KEY_NODE)HvGetCell(KeyControlBlock->KeyHive, KeyControlBlock->KeyCell);
if( ptarget == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit2;
}
ASSERT( ptarget->Flags == KeyControlBlock->Flags );
if ( ((ptarget->SubKeyCounts[Stable] + ptarget->SubKeyCounts[Volatile]) == 0) &&
((ptarget->Flags & KEY_NO_DELETE) == 0))
{
//
// Cell is NOT marked NO_DELETE and does NOT have children
// Send Notification while key still present, if delete fails,
// we'll have sent a spurious notify, that doesn't matter
// Delete the actual storage
//
Parent = ptarget->Parent;
CmpReportNotify(
KeyControlBlock,
Hive,
Cell,
REG_NOTIFY_CHANGE_NAME
);
status = CmpFreeKeyByCell(Hive, Cell, TRUE);
if (NT_SUCCESS(status)) {
//
// post any waiting notifies
//
CmpFlushNotifiesOnKeyBodyList(KeyControlBlock,FALSE);
//
// Remove kcb out of cache, but do NOT
// free its storage, CmDelete will do that when
// the RefCount becomes zero.
//
// There are two things that can hold the RefCount non-zero.
//
// 1. open handles for this key
// 2. Fake subKeys that are still in DelayClose.
//
// At this point, we have no way of deleting the fake subkeys from cache
// unless we do a search for the whole cache, which is too expensive.
// Thus, we decide to either let the fake keys age out of cache or when
// someone is doing the lookup for the fake key, then we delete it at that point.
// See routine CmpCacheLookup in cmparse.c for more details.
//
// If the parent has the subkey info or hint cached, free it.
// Again, registry is locked exclusively, no need to lock KCB.
//
CmpCleanUpSubKeyInfo(KeyControlBlock->ParentKcb);
ptarget = (PCM_KEY_NODE)HvGetCell(Hive, Parent);
if( ptarget != NULL ) {
//
// this should always be true as CmpFreeKeyByCell always marks the parent dirty on success
//
KeyControlBlock->ParentKcb->KcbMaxNameLen = (USHORT)ptarget->MaxNameLen;
// sanity
ASSERT_CELL_DIRTY(Hive,Parent);
//
// update the LastWriteTime on parent and kcb too
//
KeQuerySystemTime(&TimeStamp);
ptarget->LastWriteTime = TimeStamp;
KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
HvReleaseCell(Hive, Parent);
}
KeyControlBlock->Delete = TRUE;
CmpRemoveKeyControlBlock(KeyControlBlock);
KeyControlBlock->KeyCell = HCELL_NIL;
}
} else {
status = STATUS_CANNOT_DELETE;
}
Exit2:
HvReleaseCell(Hive, Cell);
CmpUnlockHiveFlusher((PCMHIVE)KeyControlBlock->KeyHive);
Exit:
CmpUnlockTwoHashEntries(KeyControlBlock->ConvKey,KeyControlBlock->ParentKcb->ConvKey);
CmpUnlockRegistry();
// Mark the hive as read only
CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive);
return status;
}

2781
base/ntos/config/cmboot.c Normal file

File diff suppressed because it is too large Load Diff

1284
base/ntos/config/cmchek.c Normal file

File diff suppressed because it is too large Load Diff

189
base/ntos/config/cmchek2.c Normal file
View File

@ -0,0 +1,189 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmchek2.c
Abstract:
This module implements consistency checking for the registry.
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpValidateHiveSecurityDescriptors)
#endif
extern ULONG CmpUsedStorage;
BOOLEAN
CmpValidateHiveSecurityDescriptors(
IN PHHIVE Hive,
OUT PBOOLEAN ResetSD
)
/*++
Routine Description:
Walks the list of security descriptors present in the hive and passes
each security descriptor to RtlValidSecurityDescriptor.
Only applies to descriptors in Stable store. Those in Volatile store
cannot have come from disk and therefore do not need this treatment
anyway.
Arguments:
Hive - Supplies pointer to the hive control structure
Return Value:
TRUE - All security descriptors are valid
FALSE - At least one security descriptor is invalid
--*/
{
PCM_KEY_NODE RootNode;
PCM_KEY_SECURITY SecurityCell;
HCELL_INDEX ListAnchor;
HCELL_INDEX NextCell;
HCELL_INDEX LastCell;
BOOLEAN BuildSecurityCache;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpValidateHiveSecurityDescriptor: Hive = %p\n",(ULONG_PTR)Hive));
ASSERT( Hive->ReleaseCellRoutine == NULL );
*ResetSD = FALSE;
if( ((PCMHIVE)Hive)->SecurityCount == 0 ) {
BuildSecurityCache = TRUE;
} else {
BuildSecurityCache = FALSE;
}
if (!HvIsCellAllocated(Hive,Hive->BaseBlock->RootCell)) {
//
// root cell HCELL_INDEX is bogus
//
return(FALSE);
}
RootNode = (PCM_KEY_NODE) HvGetCell(Hive, Hive->BaseBlock->RootCell);
if( RootNode == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return FALSE;
}
if( FALSE ) {
YankSD:
if( CmDoSelfHeal() ) {
//
// reset all security for the entire hive to the root security. There is no reliable way to
// patch the security list
//
if(!HvIsCellAllocated(Hive, RootNode->Security)) {
return FALSE;
}
SecurityCell = (PCM_KEY_SECURITY) HvGetCell(Hive, RootNode->Security);
if( SecurityCell == NULL ) {
return FALSE;
}
if( HvMarkCellDirty(Hive, RootNode->Security,FALSE) ) {
SecurityCell->Flink = SecurityCell->Blink = RootNode->Security;
} else {
return FALSE;
}
//
// destroy existing cache and set up an empty one
//
CmpDestroySecurityCache((PCMHIVE)Hive);
CmpInitSecurityCache((PCMHIVE)Hive);
CmMarkSelfHeal(Hive);
*ResetSD = TRUE;
} else {
return FALSE;
}
}
LastCell = 0;
ListAnchor = NextCell = RootNode->Security;
do {
if (!HvIsCellAllocated(Hive, NextCell)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CM: CmpValidateHiveSecurityDescriptors\n"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC," NextCell: %08lx is invalid HCELL_INDEX\n",NextCell));
goto YankSD;
}
SecurityCell = (PCM_KEY_SECURITY) HvGetCell(Hive, NextCell);
if( SecurityCell == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return FALSE;
}
if (NextCell != ListAnchor) {
//
// Check to make sure that our Blink points to where we just
// came from.
//
if (SecurityCell->Blink != LastCell) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC," Invalid Blink (%08lx) on security cell %08lx\n",SecurityCell->Blink, NextCell));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC," should point to %08lx\n", LastCell));
return(FALSE);
}
}
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SEC,"CmpValidSD: SD shared by %d nodes\n",SecurityCell->ReferenceCount));
if (!SeValidSecurityDescriptor(SecurityCell->DescriptorLength, &SecurityCell->Descriptor)) {
#if DBG
CmpDumpSecurityDescriptor(&SecurityCell->Descriptor,"INVALID DESCRIPTOR");
#endif
goto YankSD;
}
//
// cache this security cell; now that we know it is valid
//
if( BuildSecurityCache == TRUE ) {
if( !NT_SUCCESS(CmpAddSecurityCellToCache ( (PCMHIVE)Hive,NextCell,TRUE,NULL) ) ) {
return FALSE;
}
} else {
//
// just check this cell is there
//
ULONG Index;
if( CmpFindSecurityCellCacheIndex ((PCMHIVE)Hive,NextCell,&Index) == FALSE ) {
//
// bad things happened; maybe an error in our caching code?
//
return FALSE;
}
}
LastCell = NextCell;
NextCell = SecurityCell->Flink;
} while ( NextCell != ListAnchor );
if( BuildSecurityCache == TRUE ) {
//
// adjust the size of the cache in case we allocated too much
//
CmpAdjustSecurityCacheSize ( (PCMHIVE)Hive );
}
return(TRUE);
}

141
base/ntos/config/cmclose.c Normal file
View File

@ -0,0 +1,141 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmclose.c
Abstract:
This module contains the close object method.
--*/
#include "cmp.h"
VOID
CmpDelayedDerefKeys(
PLIST_ENTRY DelayedDeref
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpCloseKeyObject)
#endif
VOID
CmpCloseKeyObject(
IN PEPROCESS Process OPTIONAL,
IN PVOID Object,
IN ACCESS_MASK GrantedAccess,
IN ULONG_PTR ProcessHandleCount,
IN ULONG_PTR SystemHandleCount
)
/*++
Routine Description:
This routine interfaces to the NT Object Manager. It is invoked when
a Key object (or Key Root object) is closed.
It's function is to do cleanup processing by waking up any notifies
pending on the handle. This keeps the key object from hanging around
forever because a synchronous notify is stuck on it somewhere.
All other cleanup, in particular, the freeing of storage, will be
done in CmpDeleteKeyObject.
Arguments:
Process - ignored
Object - supplies a pointer to a KeyRoot or Key, thus -> KEY_BODY.
GrantedAccess, ProcessHandleCount, SystemHandleCount - ignored
Return Value:
NONE.
--*/
{
PCM_KEY_BODY KeyBody;
PCM_NOTIFY_BLOCK NotifyBlock;
CM_PAGED_CODE();
UNREFERENCED_PARAMETER (Process);
UNREFERENCED_PARAMETER (GrantedAccess);
UNREFERENCED_PARAMETER (ProcessHandleCount);
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_POOL,"CmpCloseKeyObject: Object = %p\n", Object));
if( SystemHandleCount > 1 ) {
//
// There are still has open handles on this key. Do nothing
//
return;
}
KeyBody = (PCM_KEY_BODY)Object;
//
// Check the type, it will be something else if we are closing a predefined
// handle key
//
if (KeyBody->Type == KEY_BODY_TYPE) {
if (KeyBody->NotifyBlock == NULL) {
return;
}
CmpLockRegistry();
//
// Clean up any outstanding notifies attached to the KeyBody
//
CmLockHive((PCMHIVE)(KeyBody->KeyControlBlock->KeyHive));
if (KeyBody->NotifyBlock != NULL) {
//
// Post all PostBlocks waiting on the NotifyBlock
//
NotifyBlock = KeyBody->NotifyBlock;
if (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) {
LIST_ENTRY DelayedDeref;
//
// we need to follow the rule here the hive lock
// otherwise we could deadlock down in CmDeleteKeyObject. We don't acquire the kcb lock,
// but we make sure that in subsequent places where we get the hive lock we get it before
// the kcb lock, ie. we follow the precedence rule below.
//
// NB: the order of these locks is First the hive lock, then the kcb lock
//
InitializeListHead(&DelayedDeref);
CmpPostNotify(NotifyBlock,
NULL,
0,
STATUS_NOTIFY_CLEANUP,
FALSE,
&DelayedDeref
#if DBG
,(PCMHIVE)(KeyBody->KeyControlBlock->KeyHive)
#endif
);
//
// finish the job started in CmpPostNotify (i.e. dereference the keybodies
// we prevented. this may cause some notifyblocks to be freed
//
CmpDelayedDerefKeys(&DelayedDeref);
}
}
CmUnlockHive((PCMHIVE)(KeyBody->KeyControlBlock->KeyHive));
CmpUnlockRegistry();
}
return;
}

711
base/ntos/config/cmconfig.c Normal file
View File

@ -0,0 +1,711 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmconfig.c
Abstract:
This module is responsible to build the hardware tree of the
registry data base.
--*/
#include "cmp.h"
//
// Title Index - Never used for Product 1, set to 0 for now.
//
#define TITLE_INDEX_VALUE 0
extern ULONG CmpTypeCount[];
#define EISA_ADAPTER_INDEX EisaAdapter
#define TURBOCHANNEL_ADAPTER_INDEX TcAdapter
//
// The following variables are used to cross-reference multifunction
// adapters to their corresponding NT interface type.
//
extern struct {
PUCHAR AscString;
USHORT InterfaceType;
USHORT Count;
} CmpMultifunctionTypes[];
extern USHORT CmpUnknownBusCount;
//
// CmpConfigurationData - A pointer to the area reserved for the purpose
// of reconstructing Configuration Data.
//
// CmpConfigurationAreaSize - Record the size of the Configuration Data
// area.
extern ULONG CmpConfigurationAreaSize;
extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
//
// Function prototypes for internal references
//
NTSTATUS
CmpSetupConfigurationTree(
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
IN HANDLE ParentHandle,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpInitializeHardwareConfiguration)
#pragma alloc_text(INIT,CmpSetupConfigurationTree)
#pragma alloc_text(INIT,CmpInitializeRegistryNode)
#endif
NTSTATUS
CmpInitializeHardwareConfiguration(
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This routine creates \\Registry\Machine\Hardware node in
the registry and calls SetupTree routine to put the hardware
information to the registry.
Arguments:
LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
OS Loader.
Returns:
NTSTATUS code for success or reason of failure.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE BaseHandle;
PCONFIGURATION_COMPONENT_DATA ConfigurationRoot;
ULONG Disposition;
ConfigurationRoot = (PCONFIGURATION_COMPONENT_DATA)LoaderBlock->ConfigurationRoot;
//
// Create \\Registry\Machine\Hardware\DeviceMap
//
InitializeObjectAttributes(
&ObjectAttributes,
&CmRegistryMachineHardwareDeviceMapName,
0,
(HANDLE)NULL,
NULL
);
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
Status = NtCreateKey( // Paht may already exist
&BaseHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
TITLE_INDEX_VALUE,
NULL,
0,
&Disposition
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
NtClose(BaseHandle);
ASSERT(Disposition == REG_CREATED_NEW_KEY);
//
// Create \\Registry\Machine\Hardware\Description and use the
// returned handle as the BaseHandle to build the hardware tree.
//
InitializeObjectAttributes(
&ObjectAttributes,
&CmRegistryMachineHardwareDescriptionName,
0,
(HANDLE)NULL,
NULL
);
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
Status = NtCreateKey( // Path may already exist
&BaseHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
TITLE_INDEX_VALUE,
NULL,
0,
&Disposition
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
ASSERT(Disposition == REG_CREATED_NEW_KEY);
//
// Allocate 16K bytes memory from paged pool for constructing
// configuration data for controller component.
// NOTE: The configuration Data for controller component
// usually takes less than 100 bytes. But on EISA machine, the
// EISA configuration information takes more than 10K and up to
// 64K. I believe 16K is the reasonable number to handler 99.9%
// of the machines. Therefore, 16K is the initial value.
//
CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
PagedPool,
CmpConfigurationAreaSize
);
if (CmpConfigurationData == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
//
// Call SetupConfigurationTree routine to go over each component
// of the tree and add component information to registry database.
//
if (ConfigurationRoot) {
Status = CmpSetupConfigurationTree(ConfigurationRoot,
BaseHandle,
-1,
(ULONG)-1);
} else {
Status = STATUS_SUCCESS;
}
ExFreePool((PVOID)CmpConfigurationData);
NtClose(BaseHandle);
return(Status);
}
NTSTATUS
CmpSetupConfigurationTree(
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
IN HANDLE ParentHandle,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber
)
/*++
Routine Description:
This routine traverses loader configuration tree and register
the hardware information to the registry data base.
Note to reduce the stack usage on machines with large number of PCI buses,
we do not recursively process the sibling nodes. We only recursively
process the child trees.
Arguments:
CurrentEntry - Supplies a pointer to a loader configuration
tree or subtree.
ParentHandle - Supplies the parent handle of CurrentEntry node.
InterfaceType - Specify the Interface type of the bus that the
CurrentEntry component resides.
BusNumber - Specify the Bus Number of the bus that the CurrentEntry
component resides. If Bus number is -1, it means InterfaceType
and BusNumber are meaningless for this component.
Returns:
None.
--*/
{
NTSTATUS Status;
HANDLE NewHandle;
USHORT i;
CONFIGURATION_COMPONENT *Component;
INTERFACE_TYPE LocalInterfaceType = InterfaceType;
ULONG LocalBusNumber = BusNumber;
USHORT DeviceIndexTable[NUMBER_TYPES];
for (i = 0; i < NUMBER_TYPES; i++) {
DeviceIndexTable[i] = 0;
}
//
// Process current entry and its siblings
//
while (CurrentEntry) {
//
// Register current entry first before going down to its children
//
Component = &CurrentEntry->ComponentEntry;
//
// If the current component is a bus component, we will set up
// its bus number and Interface type and use them to initialize
// its subtree.
//
if (Component->Class == AdapterClass &&
CurrentEntry->Parent->ComponentEntry.Class == SystemClass) {
switch (Component->Type) {
case EisaAdapter:
LocalInterfaceType = Eisa;
LocalBusNumber = CmpTypeCount[EISA_ADAPTER_INDEX]++;
break;
case TcAdapter:
LocalInterfaceType = TurboChannel;
LocalBusNumber = CmpTypeCount[TURBOCHANNEL_ADAPTER_INDEX]++;
break;
case MultiFunctionAdapter:
//
// Here we try to distinguish if the Multifunction adapter is
// Isa, Mca, Internal bus and assign BusNumber based on
// its interface type (bus type.)
//
if (Component->Identifier) {
for (i=0; CmpMultifunctionTypes[i].AscString; i++) {
if (_stricmp((PCHAR)CmpMultifunctionTypes[i].AscString,
Component->Identifier) == 0) {
break;
}
}
LocalInterfaceType = CmpMultifunctionTypes[i].InterfaceType;
LocalBusNumber = CmpMultifunctionTypes[i].Count++;
}
break;
case ScsiAdapter:
//
// Set the bus type to internal.
//
LocalInterfaceType = Internal;
LocalBusNumber = CmpTypeCount[ScsiAdapter]++;
break;
default:
LocalInterfaceType = -1;
LocalBusNumber = CmpUnknownBusCount++;
break;
}
}
//
// Initialize and copy current component to hardware registry
//
Status = CmpInitializeRegistryNode(
CurrentEntry,
ParentHandle,
&NewHandle,
LocalInterfaceType,
LocalBusNumber,
DeviceIndexTable
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// Once we are going one level down, we need to clear the TypeCount
// table for everything under the current component class ...
//
if (CurrentEntry->Child) {
//
// Process the child entry of current entry
//
Status = CmpSetupConfigurationTree(CurrentEntry->Child,
NewHandle,
LocalInterfaceType,
LocalBusNumber
);
if (!NT_SUCCESS(Status)) {
NtClose(NewHandle);
return(Status);
}
}
NtClose(NewHandle);
CurrentEntry = CurrentEntry->Sibling;
}
return(STATUS_SUCCESS);
}
NTSTATUS
CmpInitializeRegistryNode(
IN PCONFIGURATION_COMPONENT_DATA CurrentEntry,
IN HANDLE ParentHandle,
OUT PHANDLE NewHandle,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber,
IN PUSHORT DeviceIndexTable
)
/*++
Routine Description:
This routine creates a node for the current firmware component
and puts component data to the data part of the node.
Arguments:
CurrentEntry - Supplies a pointer to a configuration component.
Handle - Supplies the parent handle of CurrentEntry node.
NewHandle - Supplies a pointer to a HANDLE to receive the handle of
the newly created node.
InterfaceType - Specify the Interface type of the bus that the
CurrentEntry component resides. (See BusNumber also)
BusNumber - Specify the Bus Number of the bus that the CurrentEntry
component resides on. If Bus number is -1, it means InterfaceType
and BusNumber are meaningless for this component.
Returns:
None.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
UNICODE_STRING ValueData;
HANDLE Handle;
HANDLE OldHandle;
ANSI_STRING AnsiString;
CHAR Buffer[12];
WCHAR UnicodeBuffer[12];
CONFIGURATION_COMPONENT *Component;
ULONG Disposition;
ULONG ConfigurationDataLength = 0;
PCM_FULL_RESOURCE_DESCRIPTOR NewArea;
Component = &CurrentEntry->ComponentEntry;
//
// If the component class is SystemClass, we set its Type to be
// ArcSystem. The reason is because the detection code sets
// its type to MaximumType to indicate it is NOT ARC compatible.
// Here, we are only interested in building a System Node. So we
// change its Type to ArcSystem to ease the setup.
//
if (Component->Class == SystemClass) {
Component->Type = ArcSystem;
}
//
// Create a new key to describe the Component.
//
// The type of the component will be used as the keyname of the
// registry node. The class is the class of the component.
//
InitializeObjectAttributes(
&ObjectAttributes,
&(CmTypeName[Component->Type]),
0,
ParentHandle,
NULL
);
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
Status = NtCreateKey( // Paht may already exist
&Handle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition
);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// If this component is NOT a SystemClass component, we will
// create a subkey to identify the component's ordering.
//
if (Component->Class != SystemClass) {
RtlIntegerToChar(
DeviceIndexTable[Component->Type]++,
10,
12,
Buffer
);
RtlInitAnsiString(
&AnsiString,
Buffer
);
KeyName.Buffer = (PWSTR)UnicodeBuffer;
KeyName.Length = 0;
KeyName.MaximumLength = sizeof(UnicodeBuffer);
RtlAnsiStringToUnicodeString(
&KeyName,
&AnsiString,
FALSE
);
OldHandle = Handle;
InitializeObjectAttributes(
&ObjectAttributes,
&KeyName,
0,
OldHandle,
NULL
);
ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
Status = NtCreateKey(
&Handle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
0,
&Disposition
);
NtClose(OldHandle);
if (!NT_SUCCESS(Status)) {
return(Status);
}
ASSERT(Disposition == REG_CREATED_NEW_KEY);
}
//
// Create a value which describes the following component information:
// Flags, Cersion, Key, AffinityMask.
//
RtlInitUnicodeString(
&ValueName,
L"Component Information"
);
Status = NtSetValueKey(
Handle,
&ValueName,
TITLE_INDEX_VALUE,
REG_BINARY,
&Component->Flags,
FIELD_OFFSET(CONFIGURATION_COMPONENT, ConfigurationDataLength) -
FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags)
);
if (!NT_SUCCESS(Status)) {
NtClose(Handle);
return(Status);
}
//
// Create a value which describes the component identifier, if any.
//
if (Component->IdentifierLength) {
RtlInitUnicodeString(
&ValueName,
L"Identifier"
);
RtlInitAnsiString(
&AnsiString,
Component->Identifier
);
Status = RtlAnsiStringToUnicodeString(
&ValueData,
&AnsiString,
TRUE
);
if( NT_SUCCESS(Status) ) {
Status = NtSetValueKey(
Handle,
&ValueName,
TITLE_INDEX_VALUE,
REG_SZ,
ValueData.Buffer,
ValueData.Length + sizeof( UNICODE_NULL )
);
RtlFreeUnicodeString(&ValueData);
}
if (!NT_SUCCESS(Status)) {
NtClose(Handle);
return(Status);
}
}
//
// Create a value entry for component configuration data.
//
RtlInitUnicodeString(
&ValueName,
L"Configuration Data"
);
//
// Create the configuration data based on CM_FULL_RESOURCE_DESCRIPTOR.
//
// Note the configuration data in firmware tree may be in the form of
// CM_PARTIAL_RESOURCE_LIST or nothing. In both cases, we need to
// set up the registry configuration data to be in the form of
// CM_FULL_RESOURCE_DESCRIPTOR.
//
if (CurrentEntry->ConfigurationData) {
//
// This component has configuration data, we copy the data
// to our work area, add some more data items and copy the new
// configuration data to the registry.
//
ConfigurationDataLength = Component->ConfigurationDataLength +
FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
PartialResourceList);
//
// Make sure our reserved area is big enough to hold the data.
//
if (ConfigurationDataLength > CmpConfigurationAreaSize) {
//
// If reserved area is not big enough, we resize our reserved
// area. If, unfortunately, the reallocation fails, we simply
// loss the configuration data of this particular component.
//
NewArea = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
PagedPool,
ConfigurationDataLength
);
if (NewArea) {
CmpConfigurationAreaSize = ConfigurationDataLength;
ExFreePool(CmpConfigurationData);
CmpConfigurationData = NewArea;
RtlCopyMemory(
(PUCHAR)&CmpConfigurationData->PartialResourceList.Version,
CurrentEntry->ConfigurationData,
Component->ConfigurationDataLength
);
} else {
Component->ConfigurationDataLength = 0;
CurrentEntry->ConfigurationData = NULL;
}
} else {
RtlCopyMemory(
(PUCHAR)&CmpConfigurationData->PartialResourceList.Version,
CurrentEntry->ConfigurationData,
Component->ConfigurationDataLength
);
}
}
if (CurrentEntry->ConfigurationData == NULL) {
//
// This component has NO configuration data (or we can't resize
// our reserved area to hold the data), we simple add whatever
// is required to set up a CM_FULL_RESOURCE_LIST.
//
CmpConfigurationData->PartialResourceList.Version = 0;
CmpConfigurationData->PartialResourceList.Revision = 0;
CmpConfigurationData->PartialResourceList.Count = 0;
ConfigurationDataLength = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
PartialResourceList) +
FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
PartialDescriptors);
}
//
// Set up InterfaceType and BusNumber for the component.
//
CmpConfigurationData->InterfaceType = InterfaceType;
CmpConfigurationData->BusNumber = BusNumber;
//
// Write the newly constructed configuration data to the hardware registry
//
Status = NtSetValueKey(
Handle,
&ValueName,
TITLE_INDEX_VALUE,
REG_FULL_RESOURCE_DESCRIPTOR,
CmpConfigurationData,
ConfigurationDataLength
);
if (!NT_SUCCESS(Status)) {
NtClose(Handle);
return(Status);
}
*NewHandle = Handle;
return(STATUS_SUCCESS);
}

409
base/ntos/config/cmcontrl.c Normal file
View File

@ -0,0 +1,409 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmcontrl.c
Abstract:
The module contains CmGetSystemControlValues, see cmdat.c for data.
--*/
#include "cmp.h"
extern WCHAR CmDefaultLanguageId[];
extern ULONG CmDefaultLanguageIdLength;
extern ULONG CmDefaultLanguageIdType;
extern WCHAR CmInstallUILanguageId[];
extern ULONG CmInstallUILanguageIdLength;
extern ULONG CmInstallUILanguageIdType;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("INITDATA")
#endif
CMHIVE CmControlHive;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif
HCELL_INDEX
CmpWalkPath(
PHHIVE SystemHive,
HCELL_INDEX ParentCell,
PWSTR Path
);
LANGID
CmpConvertLangId(
PWSTR LangIdString,
ULONG LangIdStringLength
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmGetSystemControlValues)
#pragma alloc_text(INIT,CmpWalkPath)
#pragma alloc_text(INIT,CmpConvertLangId)
#endif
VOID
CmGetSystemControlValues(
__in PVOID SystemHiveBuffer,
__inout PCM_SYSTEM_CONTROL_VECTOR ControlVector
)
/*++
Routine Description:
Look for registry values in current control set, as specified
by entries in ControlVector. Report data for value entries
(if any) to variables ControlVector points to.
Arguments:
SystemHiveBuffer - pointer to flat image of the system hive
ControlVector - pointer to structure that describes what values
to pull out and store
Return Value:
NONE.
--*/
{
NTSTATUS status;
PHHIVE SystemHive;
HCELL_INDEX RootCell;
HCELL_INDEX BaseCell;
UNICODE_STRING Name;
HCELL_INDEX KeyCell;
HCELL_INDEX ValueCell;
PCM_KEY_VALUE ValueBody;
ULONG Length;
BOOLEAN AutoSelect;
BOOLEAN small;
ULONG tmplength;
PCM_KEY_NODE Node;
//
// set up to read flat system hive image loader passes us
//
RtlZeroMemory((PVOID)&CmControlHive, sizeof(CmControlHive));
SystemHive = &(CmControlHive.Hive);
CmpInitHiveViewList((PCMHIVE)SystemHive);
CmpInitSecurityCache((PCMHIVE)SystemHive);
status = HvInitializeHive(
SystemHive,
HINIT_FLAT,
HIVE_VOLATILE,
HFILE_TYPE_PRIMARY,
SystemHiveBuffer,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
1,
NULL
);
if (!NT_SUCCESS(status)) {
CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_CONTROL_VALUES,1,SystemHive,status);
}
//
// don't bother locking/releasing cells
//
ASSERT( SystemHive->ReleaseCellRoutine == NULL );
//
// get hive.cell of root of current control set
//
RootCell = ((PHBASE_BLOCK)SystemHiveBuffer)->RootCell;
RtlInitUnicodeString(&Name, L"current");
BaseCell = CmpFindControlSet(
SystemHive,
RootCell,
&Name,
&AutoSelect
);
if (BaseCell == HCELL_NIL) {
CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_CONTROL_VALUES,2,SystemHive,&Name);
}
Node = (PCM_KEY_NODE)HvGetCell(SystemHive,BaseCell);
if( Node == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return;
}
RtlInitUnicodeString(&Name, L"control");
BaseCell = CmpFindSubKeyByName(SystemHive,
Node,
&Name);
if (BaseCell == HCELL_NIL) {
CM_BUGCHECK(BAD_SYSTEM_CONFIG_INFO,BAD_SYSTEM_CONTROL_VALUES,3,Node,&Name);
}
//
// SystemHive.BaseCell = \registry\machine\system\currentcontrolset\control
//
//
// step through vector, trying to fetch each value
//
while (ControlVector->KeyPath != NULL) {
//
// Assume we will fail to find the key or value.
//
Length = (ULONG)-1;
KeyCell = CmpWalkPath(SystemHive, BaseCell, ControlVector->KeyPath);
if (KeyCell != HCELL_NIL) {
//
// found the key, look for the value entry
//
Node = (PCM_KEY_NODE)HvGetCell(SystemHive,KeyCell);
if( Node == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return;
}
RtlInitUnicodeString(&Name, ControlVector->ValueName);
ValueCell = CmpFindValueByName(SystemHive,
Node,
&Name);
if (ValueCell != HCELL_NIL) {
//
// SystemHive.ValueCell is value entry body
//
if (ControlVector->BufferLength == NULL) {
tmplength = sizeof(ULONG);
} else {
tmplength = *(ControlVector->BufferLength);
}
ValueBody = (PCM_KEY_VALUE)HvGetCell(SystemHive, ValueCell);
if( ValueBody == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return;
}
small = CmpIsHKeyValueSmall(Length, ValueBody->DataLength);
if (tmplength < Length) {
Length = tmplength;
}
if (Length > 0) {
PCELL_DATA Buffer;
BOOLEAN BufferAllocated;
ULONG realsize;
HCELL_INDEX CellToRelease;
ASSERT((small ? (Length <= CM_KEY_VALUE_SMALL) : TRUE));
//
// get the data from source, regardless of the size
//
if( CmpGetValueData(SystemHive,ValueBody,&realsize,&Buffer,&BufferAllocated,&CellToRelease) == FALSE ) {
//
// insufficient resources; return NULL
//
ASSERT( BufferAllocated == FALSE );
ASSERT( Buffer == NULL );
return;
}
RtlCopyMemory(
ControlVector->Buffer,
Buffer,
Length
);
//
// cleanup the temporary buffer
//
if( BufferAllocated == TRUE ) {
ExFreePool( Buffer );
}
if( CellToRelease != HCELL_NIL ) {
HvReleaseCell(SystemHive,CellToRelease);
}
}
if (ControlVector->Type != NULL) {
*(ControlVector->Type) = ValueBody->Type;
}
}
}
//
// Stash the length of result (-1 if nothing was found)
//
if (ControlVector->BufferLength != NULL) {
*(ControlVector->BufferLength) = Length;
}
ControlVector++;
}
//
// Get the default locale ID for the system from the registry.
//
if (CmDefaultLanguageIdType == REG_SZ) {
PsDefaultSystemLocaleId = (LCID) CmpConvertLangId(
CmDefaultLanguageId,
CmDefaultLanguageIdLength);
} else {
PsDefaultSystemLocaleId = 0x00000409;
}
//
// Get the install (native UI) language ID for the system from the registry.
//
if (CmInstallUILanguageIdType == REG_SZ) {
PsInstallUILanguageId = CmpConvertLangId(
CmInstallUILanguageId,
CmInstallUILanguageIdLength);
} else {
PsInstallUILanguageId = LANGIDFROMLCID(PsDefaultSystemLocaleId);
}
//
// Set the default thread locale to the default system locale
// for now. This will get changed as soon as somebody logs in.
// Use the install (native) language id as our default UI language id.
// This also will get changed as soon as somebody logs in.
//
PsDefaultThreadLocaleId = PsDefaultSystemLocaleId;
PsDefaultUILanguageId = PsInstallUILanguageId;
}
HCELL_INDEX
CmpWalkPath(
PHHIVE SystemHive,
HCELL_INDEX ParentCell,
PWSTR Path
)
/*++
Routine Description:
Walk the path.
Arguments:
SystemHive - hive
ParentCell - where to start
Path - string to walk
Return Value:
HCELL_INDEX of found key cell, or HCELL_NIL for error
--*/
{
UNICODE_STRING PathString;
UNICODE_STRING NextName;
BOOLEAN Last;
HCELL_INDEX KeyCell;
PCM_KEY_NODE Node;
//
// don't bother counting/releasing used cells
//
ASSERT( SystemHive->ReleaseCellRoutine == NULL );
KeyCell = ParentCell;
RtlInitUnicodeString(&PathString, Path);
while (TRUE) {
CmpGetNextName(&PathString, &NextName, &Last);
if (NextName.Length == 0) {
return KeyCell;
}
Node = (PCM_KEY_NODE)HvGetCell(SystemHive,KeyCell);
if( Node == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return HCELL_NIL;
}
KeyCell = CmpFindSubKeyByName(SystemHive,
Node,
&NextName);
if (KeyCell == HCELL_NIL) {
return HCELL_NIL;
}
}
}
LANGID
CmpConvertLangId(
PWSTR LangIdString,
ULONG LangIdStringLength
)
{
USHORT i, Digit;
WCHAR c;
LANGID LangId;
LangId = 0;
LangIdStringLength = LangIdStringLength / sizeof( WCHAR );
for (i=0; i < LangIdStringLength; i++) {
c = LangIdString[ i ];
if (c >= L'0' && c <= L'9') {
Digit = c - L'0';
} else if (c >= L'A' && c <= L'F') {
Digit = c - L'A' + 10;
} else if (c >= L'a' && c <= L'f') {
Digit = c - L'a' + 10;
} else {
break;
}
if (Digit >= 16) {
break;
}
LangId = (LangId << 4) | Digit;
}
return LangId;
}

393
base/ntos/config/cmdat.c Normal file
View File

@ -0,0 +1,393 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmdat.c
Abstract:
This module contains registry "static" data, except for data
also used by setup, which is in cmdat2.c.
--*/
#include "cmp.h"
//
// ***** INIT *****
//
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("INITDATA")
#pragma const_seg("INITCONST")
#endif
//
// ---------------------------
//
UNICODE_STRING CmpLoadOptions = { 0 }; // sys options from FW or boot.ini
//
// CmpClassString - contains strings which are used as the class
// strings in the keynode.
// The associated enumerated type is CONFIGURATION_CLASS in arc.h
//
UNICODE_STRING CmClassName[MaximumClass + 1] = { 0 };
const PWCHAR CmClassString[MaximumClass + 1] = {
L"System",
L"Processor",
L"Cache",
L"Adapter",
L"Controller",
L"Peripheral",
L"MemoryClass",
L"Undefined"
};
struct {
PCHAR AscString;
USHORT InterfaceType;
USHORT Count;
} CmpMultifunctionTypes[] = {
"ISA", Isa, 0,
"MCA", MicroChannel, 0,
"PCI", PCIBus, 0,
"VME", VMEBus, 0,
"PCMCIA", PCMCIABus, 0,
"CBUS", CBus, 0,
"MPIPI", MPIBus, 0,
"MPSA", MPSABus, 0,
NULL, Internal, 0
};
USHORT CmpUnknownBusCount = 0;
ULONG CmpConfigurationAreaSize = 0x4000; // Initialize size = 16K
PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData = { 0 };
//
// The following strings will be used as the keynames for registry
// nodes.
// The associated enumerated type is CONFIGURATION_TYPE in arc.h
//
UNICODE_STRING CmTypeName[MaximumType + 1] = { 0 };
//
// ***** PAGE *****
//
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#pragma const_seg("PAGECONST")
#endif
const PWCHAR CmTypeString[MaximumType + 1] = {
L"System",
L"CentralProcessor",
L"FloatingPointProcessor",
L"PrimaryICache",
L"PrimaryDCache",
L"SecondaryICache",
L"SecondaryDCache",
L"SecondaryCache",
L"EisaAdapter",
L"TcAdapter",
L"ScsiAdapter",
L"DtiAdapter",
L"MultifunctionAdapter",
L"DiskController",
L"TapeController",
L"CdRomController",
L"WormController",
L"SerialController",
L"NetworkController",
L"DisplayController",
L"ParallelController",
L"PointerController",
L"KeyboardController",
L"AudioController",
L"OtherController",
L"DiskPeripheral",
L"FloppyDiskPeripheral",
L"TapePeripheral",
L"ModemPeripheral",
L"MonitorPeripheral",
L"PrinterPeripheral",
L"PointerPeripheral",
L"KeyboardPeripheral",
L"TerminalPeripheral",
L"OtherPeripheral",
L"LinePeripheral",
L"NetworkPeripheral",
L"SystemMemory",
L"DockingInformation",
L"RealModeIrqRoutingTable",
L"RealModePCIEnumeration",
L"Undefined"
};
//
// CmpTypeCount[] - For each 'type', a count is used to keep track how many
// keys have been created.
//
ULONG CmpTypeCount[NUMBER_TYPES] = {
0, // ArcSystem
0, // CentralProcessor",
0, // FloatingPointProcessor",
0, // PrimaryICache",
0, // PrimaryDCache",
0, // SecondaryICache",
0, // SecondaryDCache",
0, // SecondaryCache",
0, // EisaAdapter", (8)
0, // TcAdapter", (9)
0, // ScsiAdapter",
0, // DtiAdapter",
0, // MultifunctionAdapter", (12)
0, // DiskController", (13)
0, // TapeController",
0, // CdRomController",
0, // WormController",
0, // SerialController",
0, // NetworkController",
0, // DisplayController",
0, // ParallelController",
0, // PointerController",
0, // KeyboardController",
0, // AudioController",
0, // OtherController",
0, // DiskPeripheral",
0, // FloppyDiskPeripheral",
0, // TapePeripheral",
0, // ModemPeripheral",
0, // MonitorPeripheral",
0, // PrinterPeripheral",
0, // PointerPeripheral",
0, // KeyboardPeripheral",
0, // TerminalPeripheral",
0, // OtherPeripheral",
0, // LinePeripheral",
0, // NetworkPeripheral",
0, // SystemMemory",
0, // DockingInformation,
0, // RealModeIrqRoutingTable
0 // Undefined"
};
const UNICODE_STRING nullclass = { 0, 0, NULL };
//
// All names used by the registry
//
UNICODE_STRING CmRegistryRootName = { 0 };
UNICODE_STRING CmRegistryMachineName = { 0 };
UNICODE_STRING CmRegistryMachineHardwareName = { 0 };
UNICODE_STRING CmRegistryMachineHardwareDescriptionName = { 0 };
UNICODE_STRING CmRegistryMachineHardwareDescriptionSystemName = { 0 };
UNICODE_STRING CmRegistryMachineHardwareDeviceMapName = { 0 };
UNICODE_STRING CmRegistryMachineHardwareResourceMapName = { 0 };
UNICODE_STRING CmRegistryMachineHardwareOwnerMapName = { 0 };
UNICODE_STRING CmRegistryMachineSystemName = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSet = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetEnumName = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetEnumRootName = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetServices = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetControlClass = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetControlSafeBoot = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagement = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetControlBootLog = { 0 };
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetServicesEventLog = { 0 };
UNICODE_STRING CmRegistryUserName = { 0 };
UNICODE_STRING CmRegistrySystemCloneName = { 0 };
UNICODE_STRING CmpSystemFileName = { 0 };
UNICODE_STRING CmSymbolicLinkValueName = { 0 };
#ifdef _WANT_MACHINE_IDENTIFICATION
UNICODE_STRING CmRegistryMachineSystemCurrentControlSetControlBiosInfo = { 0 };
#endif
const PWCHAR CmpRegistryRootString = L"\\REGISTRY";
const PWCHAR CmpRegistryMachineString = L"\\REGISTRY\\MACHINE";
const PWCHAR CmpRegistryMachineHardwareString =
L"\\REGISTRY\\MACHINE\\HARDWARE";
const PWCHAR CmpRegistryMachineHardwareDescriptionString =
L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION";
const PWCHAR CmpRegistryMachineHardwareDescriptionSystemString =
L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM";
const PWCHAR CmpRegistryMachineHardwareDeviceMapString =
L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP";
const PWCHAR CmpRegistryMachineHardwareResourceMapString =
L"\\REGISTRY\\MACHINE\\HARDWARE\\RESOURCEMAP";
const PWCHAR CmpRegistryMachineHardwareOwnerMapString =
L"\\REGISTRY\\MACHINE\\HARDWARE\\OWNERMAP";
const PWCHAR CmpRegistryMachineSystemString =
L"\\REGISTRY\\MACHINE\\SYSTEM";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetEnumString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetEnumRootString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM\\ROOT";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetServicesString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetHardwareProfilesCurrentString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlClassString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\CONTROL\\CLASS";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlSafeBootString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\CONTROL\\SAFEBOOT";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagementString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\CONTROL\\SESSION MANAGER\\MEMORY MANAGEMENT";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlBootLogString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\CONTROL\\BOOTLOG";
const PWCHAR CmpRegistryMachineSystemCurrentControlSetServicesEventLogString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES\\EVENTLOG";
const PWCHAR CmpRegistryUserString = L"\\REGISTRY\\USER";
const PWCHAR CmpRegistrySystemCloneString = L"\\REGISTRY\\MACHINE\\CLONE";
const PWCHAR CmpRegistrySystemFileNameString = L"SYSTEM";
const PWCHAR CmpRegistryPerflibString = L"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS NT\\CURRENTVERSION\\PERFLIB";
const PWCHAR CmpProcessorControl = L"ProcessorControl";
const PWCHAR CmpControlSessionManager = L"Control\\Session Manager";
const PWCHAR CmpSymbolicLinkValueName = L"SymbolicLinkValue";
#ifdef _WANT_MACHINE_IDENTIFICATION
const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlBiosInfoString =
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\CONTROL\\BIOSINFO";
#endif
//
// N.B. The CLONE hive is left out of the machine Hive list if
// we will not be using it to clone the current control set,
// since that is that Hive's only purpose.
//
HIVE_LIST_ENTRY CmpMachineHiveList[] = {
{ L"HARDWARE", L"MACHINE\\", NULL, HIVE_VOLATILE , 0 , NULL, FALSE, FALSE, FALSE},
{ L"SECURITY", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE},
{ L"SOFTWARE", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE},
{ L"SYSTEM", L"MACHINE\\", NULL, 0 , 0 , NULL, FALSE, FALSE, FALSE},
{ L"DEFAULT", L"USER\\.DEFAULT", NULL, 0 , CM_CMHIVE_FLAG_UNTRUSTED , NULL, FALSE, FALSE, FALSE},
{ L"SAM", L"MACHINE\\", NULL, HIVE_NOLAZYFLUSH , 0 , NULL, FALSE, FALSE, FALSE},
{ NULL, NULL, 0, 0 , 0 , NULL, FALSE, FALSE, FALSE}
};
UCHAR SystemHiveFullPathBuffer[MAX_NAME];
UNICODE_STRING SystemHiveFullPathName;
//
// Master Hive
//
// The KEY_NODEs for \REGISTRY, \REGISTRY\MACHINE, and \REGISTRY\USER
// are stored in a small memory only hive called the Master Hive.
// All other hives have link nodes in this hive which point to them.
//
PCMHIVE CmpMasterHive = { 0 };
BOOLEAN CmpNoMasterCreates = FALSE; // Set TRUE after we're done to
// prevent random creates in the
// master hive, which is not backed
// by a file.
LIST_ENTRY CmpHiveListHead = { 0 }; // List of CMHIVEs
EX_PUSH_LOCK CmpHiveListHeadLock; // used to protect the list above
EX_PUSH_LOCK CmpLoadHiveLock;
//
// Addresses of object type descriptors:
//
POBJECT_TYPE CmpKeyObjectType = { 0 };
//
// Write-Control:
// CmpNoWrite is initially true. When set this way write and flush
// do nothing, simply returning success. When cleared to FALSE, I/O
// is enabled. This change is made after the I/O system is started
// AND autocheck (chkdsk) has done its thing.
//
BOOLEAN CmpNoWrite = TRUE;
//
// NtInitializeRegistry global status flags
//
//
// If CmFirstTime is TRUE, then NtInitializeRegistry has not yet been
// called to perform basic registry initialization
//
BOOLEAN CmFirstTime = TRUE;
//
// trick to allow parallel threads to access the registry
//
BOOLEAN CmpSpecialBootCondition = FALSE;
//
// If CmBootAcceptFirstTime is TRUE, then NtInitializeRegistry has not
// yet been called to accept the current Boot and save the boot
// control set as the LKG control set.
//
BOOLEAN CmBootAcceptFirstTime = TRUE;
//
// CmpWasSetupBoot indicates whether or not the boot
// is into text mode setup. If so, we do not turn
// on global quotas.
//
BOOLEAN CmpWasSetupBoot;
//
// Indicates whether the hives need to be loaded in memory
// and in scratch mode
//
BOOLEAN CmpMiniNTBoot = FALSE;
//
// Indicates whether the system hives need to be opened in a
// shared mode. Generally needed if we are booting WinPE (MiniNT)
// on network
//
BOOLEAN CmpShareSystemHives = FALSE;
//
// Where are we booting from
//
ULONG CmpBootType;
//
// Self healing hives control switch
//
BOOLEAN CmpSelfHeal = TRUE;
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg()
#pragma data_seg()
#endif

151
base/ntos/config/cmdat2.c Normal file
View File

@ -0,0 +1,151 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmdat2.c
Abstract:
This module contains data strings that describes the registry space
and that are exported to the rest of the system.
--*/
#include "cmp.h"
//
// ***** PAGE *****
//
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
//
// control values/overrides read from registry
//
ULONG CmRegistrySizeLimit = { 0 };
ULONG CmRegistrySizeLimitLength = 4;
ULONG CmRegistrySizeLimitType = { 0 };
//
// Maximum number of bytes of Global Quota the registry may use.
// Set to largest positive number for use in boot. Will be set down
// based on pool and explicit registry values.
//
SIZE_T CmpGlobalQuotaAllowed = CM_WRAP_LIMIT;
SIZE_T CmpGlobalQuota = CM_WRAP_LIMIT;
SIZE_T CmpGlobalQuotaWarning = CM_WRAP_LIMIT;
BOOLEAN CmpQuotaWarningPopupDisplayed = FALSE;
BOOLEAN CmpSystemQuotaWarningPopupDisplayed = FALSE;
//
// the "disk full" popup has already been displayed
//
BOOLEAN CmpDiskFullWorkerPopupDisplayed = FALSE;
BOOLEAN CmpCannotWriteConfiguration = FALSE;
//
// GQ actually in use
//
SIZE_T CmpGlobalQuotaUsed = 0;
//
// State flag to remember when to turn it on
//
BOOLEAN CmpProfileLoaded = FALSE;
PUCHAR CmpStashBuffer = NULL;
ULONG CmpStashBufferSize = 0;
EX_PUSH_LOCK CmpStashBufferLock;
//
// Shutdown control
//
BOOLEAN HvShutdownComplete = FALSE; // Set to true after shutdown
// to disable any further I/O
PCM_KEY_CONTROL_BLOCK CmpKeyControlBlockRoot = NULL;
HANDLE CmpRegistryRootHandle = NULL;
struct {
PHHIVE Hive;
ULONG Status;
} CmCheckRegistryDebug = { 0 };
//
// The last I/O error status code
//
struct {
ULONG Action;
HANDLE Handle;
NTSTATUS Status;
} CmRegistryIODebug = { 0 };
//
// globals private to check code
//
struct {
PHHIVE Hive;
ULONG Status;
} CmpCheckRegistry2Debug = { 0 };
struct {
PHHIVE Hive;
ULONG Status;
HCELL_INDEX Cell;
PCELL_DATA CellPoint;
PVOID RootPoint;
ULONG Index;
} CmpCheckKeyDebug = { 0 };
struct {
PHHIVE Hive;
ULONG Status;
PCELL_DATA List;
ULONG Index;
HCELL_INDEX Cell;
PCELL_DATA CellPoint;
} CmpCheckValueListDebug = { 0 };
ULONG CmpUsedStorage = { 0 };
// hivechek.c
struct {
PHHIVE Hive;
ULONG Status;
ULONG Space;
HCELL_INDEX MapPoint;
PHBIN BinPoint;
} HvCheckHiveDebug = { 0 };
struct {
PHBIN Bin;
ULONG Status;
PHCELL CellPoint;
} HvCheckBinDebug = { 0 };
struct {
PHHIVE Hive;
ULONG FileOffset;
ULONG FailPoint; // look in HvpRecoverData for exact point of failure
} HvRecoverDataDebug = { 0 };
//
// when a local hive cannot be loaded, set this to it's index
// and the load hive worker thread responsible for it will be held of
// until all the others finish; We can then debug the offending hive
//
ULONG CmpCheckHiveIndex = CM_NUMBER_OF_MACHINE_HIVES;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif

200
base/ntos/config/cmdatini.c Normal file
View File

@ -0,0 +1,200 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmdatini.c
Abstract:
contains code to init static STRING structures for registry name space.
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,CmpInitializeRegistryNames)
#endif
extern UNICODE_STRING CmRegistryRootName;
extern UNICODE_STRING CmRegistryMachineName;
extern UNICODE_STRING CmRegistryMachineHardwareName;
extern UNICODE_STRING CmRegistryMachineHardwareDescriptionName;
extern UNICODE_STRING CmRegistryMachineHardwareDescriptionSystemName;
extern UNICODE_STRING CmRegistryMachineHardwareDeviceMapName;
extern UNICODE_STRING CmRegistryMachineHardwareResourceMapName;
extern UNICODE_STRING CmRegistryMachineHardwareOwnerMapName;
extern UNICODE_STRING CmRegistryMachineSystemName;
extern UNICODE_STRING CmRegistryMachineSystemCurrentControlSet;
extern UNICODE_STRING CmRegistryUserName;
extern UNICODE_STRING CmRegistrySystemCloneName;
extern UNICODE_STRING CmpSystemFileName;
extern UNICODE_STRING CmRegistryMachineSystemCurrentControlSetEnumName;
extern UNICODE_STRING CmRegistryMachineSystemCurrentControlSetEnumRootName;
extern UNICODE_STRING CmRegistryMachineSystemCurrentControlSetServices;
extern UNICODE_STRING CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent;
extern UNICODE_STRING CmRegistryMachineSystemCurrentControlSetControlClass;
extern UNICODE_STRING CmSymbolicLinkValueName;
#ifdef _WANT_MACHINE_IDENTIFICATION
extern UNICODE_STRING CmRegistryMachineSystemCurrentControlSetControlBiosInfo;
#endif
extern const PWCHAR CmpRegistryRootString;
extern const PWCHAR CmpRegistryMachineString;
extern const PWCHAR CmpRegistryMachineHardwareString;
extern const PWCHAR CmpRegistryMachineHardwareDescriptionString;
extern const PWCHAR CmpRegistryMachineHardwareDescriptionSystemString;
extern const PWCHAR CmpRegistryMachineHardwareDeviceMapString;
extern const PWCHAR CmpRegistryMachineHardwareResourceMapString;
extern const PWCHAR CmpRegistryMachineHardwareOwnerMapString;
extern const PWCHAR CmpRegistryMachineSystemString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetString;
extern const PWCHAR CmpRegistryUserString;
extern const PWCHAR CmpRegistrySystemCloneString;
extern const PWCHAR CmpRegistrySystemFileNameString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetEnumString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetEnumRootString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetServicesString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetHardwareProfilesCurrentString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlClassString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlSafeBootString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagementString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlBootLogString;
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetServicesEventLogString;
extern const PWCHAR CmpSymbolicLinkValueName;
#ifdef _WANT_MACHINE_IDENTIFICATION
extern const PWCHAR CmpRegistryMachineSystemCurrentControlSetControlBiosInfoString;
#endif
VOID
CmpInitializeRegistryNames(
VOID
)
/*++
Routine Description:
This routine creates all the Unicode strings for the various names used
in and by the registry
Arguments:
None.
Returns:
None.
--*/
{
ULONG i;
RtlInitUnicodeString( &CmRegistryRootName,
CmpRegistryRootString );
RtlInitUnicodeString( &CmRegistryMachineName,
CmpRegistryMachineString );
RtlInitUnicodeString( &CmRegistryMachineHardwareName,
CmpRegistryMachineHardwareString );
RtlInitUnicodeString( &CmRegistryMachineHardwareDescriptionName,
CmpRegistryMachineHardwareDescriptionString );
RtlInitUnicodeString( &CmRegistryMachineHardwareDescriptionSystemName,
CmpRegistryMachineHardwareDescriptionSystemString );
RtlInitUnicodeString( &CmRegistryMachineHardwareDeviceMapName,
CmpRegistryMachineHardwareDeviceMapString );
RtlInitUnicodeString( &CmRegistryMachineHardwareResourceMapName,
CmpRegistryMachineHardwareResourceMapString );
RtlInitUnicodeString( &CmRegistryMachineHardwareOwnerMapName,
CmpRegistryMachineHardwareOwnerMapString );
RtlInitUnicodeString( &CmRegistryMachineSystemName,
CmpRegistryMachineSystemString );
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSet,
CmpRegistryMachineSystemCurrentControlSetString);
RtlInitUnicodeString( &CmRegistryUserName,
CmpRegistryUserString );
RtlInitUnicodeString( &CmRegistrySystemCloneName,
CmpRegistrySystemCloneString );
RtlInitUnicodeString( &CmpSystemFileName,
CmpRegistrySystemFileNameString );
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetEnumName,
CmpRegistryMachineSystemCurrentControlSetEnumString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetEnumRootName,
CmpRegistryMachineSystemCurrentControlSetEnumRootString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetServices,
CmpRegistryMachineSystemCurrentControlSetServicesString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetHardwareProfilesCurrent,
CmpRegistryMachineSystemCurrentControlSetHardwareProfilesCurrentString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetControlClass,
CmpRegistryMachineSystemCurrentControlSetControlClassString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetControlSafeBoot,
CmpRegistryMachineSystemCurrentControlSetControlSafeBootString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagement,
CmpRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagementString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetControlBootLog,
CmpRegistryMachineSystemCurrentControlSetControlBootLogString);
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetServicesEventLog,
CmpRegistryMachineSystemCurrentControlSetServicesEventLogString);
RtlInitUnicodeString( &CmSymbolicLinkValueName,
CmpSymbolicLinkValueName);
#ifdef _WANT_MACHINE_IDENTIFICATION
RtlInitUnicodeString( &CmRegistryMachineSystemCurrentControlSetControlBiosInfo,
CmpRegistryMachineSystemCurrentControlSetControlBiosInfoString);
#endif
//
// Initialize the type names for the hardware tree.
//
for (i = 0; i <= MaximumType; i++) {
RtlInitUnicodeString( &(CmTypeName[i]),
CmTypeString[i] );
}
//
// Initialize the class names for the hardware tree.
//
for (i = 0; i <= MaximumClass; i++) {
RtlInitUnicodeString( &(CmClassName[i]),
CmClassString[i] );
}
return;
}

855
base/ntos/config/cmdelay.c Normal file
View File

@ -0,0 +1,855 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmdelay.c
Abstract:
This module implements the new algorithm (LRU style) for the
Delayed Close KCB table.
Functions in this module are thread safe protected by the kcb lock.
When kcb lock is converted to a resource, we should assert (enforce)
exclusivity of that resource here !!!
Note:
We might want to convert these functions to macros after enough testing
provides that they work well
--*/
#include "cmp.h"
ULONG CmpDelayedCloseSize = 2048; // !!!! Cannot be bigger that 4094 !!!!!
ULONG CmpDelayedCloseElements = 0;
#define MAX_DELAY_WORKER_ITERATIONS ( CmpDelayedCloseSize / 4 )
VOID
CmpDelayDerefKCBWorker(
IN PVOID Parameter
);
VOID
CmpDelayCloseWorker(
IN PVOID Parameter
);
typedef struct _CM_DELAY_DEREF_KCB_ITEM {
LIST_ENTRY ListEntry;
PCM_KEY_CONTROL_BLOCK Kcb;
} CM_DELAY_DEREF_KCB_ITEM, *PCM_DELAY_DEREF_KCB_ITEM;
VOID
CmpDelayCloseDpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
VOID
CmpDelayDerefKCBDpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
VOID
CmpDoQueueLateUnloadWorker(IN PCMHIVE CmHive);
VOID
CmpArmDelayedCloseTimer(VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpInitializeDelayedCloseTable)
#pragma alloc_text(PAGE,CmpRemoveFromDelayedClose)
#pragma alloc_text(PAGE,CmpAddToDelayedClose)
#pragma alloc_text(PAGE,CmpInitDelayDerefKCBEngine)
#pragma alloc_text(PAGE,CmpRunDownDelayDerefKCBEngine)
#pragma alloc_text(PAGE,CmpDelayDerefKeyControlBlock)
#pragma alloc_text(PAGE,CmpDelayDerefKCBWorker)
#pragma alloc_text(PAGE,CmpArmDelayedCloseTimer)
#endif
WORK_QUEUE_ITEM CmpDelayCloseWorkItem;
BOOLEAN CmpDelayCloseWorkItemActive = FALSE;
KGUARDED_MUTEX CmpDelayedCloseTableLock;
LIST_ENTRY CmpDelayedLRUListHead; // head of the LRU list of Delayed Close Table entries
KTIMER CmpDelayCloseTimer;
KDPC CmpDelayCloseDpc;
ULONG CmpDelayCloseIntervalInSeconds = 5;
#define LOCK_DELAY_CLOSE() KeAcquireGuardedMutex(&CmpDelayedCloseTableLock)
#define UNLOCK_DELAY_CLOSE() KeReleaseGuardedMutex(&CmpDelayedCloseTableLock)
VOID
CmpDelayCloseDpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This is the DPC routine triggered by the delayclose timer.
is queue a work item to an executive worker thread.
Arguments:
Dpc - Supplies a pointer to the DPC object.
DeferredContext - not used
SystemArgument1 - not used
SystemArgument2 - not used
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER (Dpc);
UNREFERENCED_PARAMETER (DeferredContext);
UNREFERENCED_PARAMETER (SystemArgument1);
UNREFERENCED_PARAMETER (SystemArgument2);
ASSERT(CmpDelayCloseWorkItemActive);
ExQueueWorkItem(&CmpDelayCloseWorkItem, DelayedWorkQueue);
}
#define CmpDelayCloseAllocNewEntry() (PCM_DELAYED_CLOSE_ENTRY)CmpAllocateDelayItem()
#define CmpDelayCloseFreeEntry(Item) CmpFreeDelayItem((PVOID)(Item))
VOID
CmpInitializeDelayedCloseTable()
/*++
Routine Description:
Initialize delayed close table; allocation + LRU list initialization.
Arguments:
Return Value:
NONE.
--*/
{
ExInitializeWorkItem(&CmpDelayCloseWorkItem, CmpDelayCloseWorker, NULL);
KeInitializeGuardedMutex(&CmpDelayedCloseTableLock);
InitializeListHead(&(CmpDelayedLRUListHead));
KeInitializeDpc(&CmpDelayCloseDpc,
CmpDelayCloseDpcRoutine,
NULL);
KeInitializeTimer(&CmpDelayCloseTimer);
}
VOID
CmpDelayCloseWorker(
IN PVOID Parameter
)
/*++
Routine Description:
The fun part. We need to walk the cache and look for kcbs with refcount == 0
Get the oldest one and kick it out of cache.
Arguments:
Parameter - not used.
Return Value:
None.
--*/
{
PCM_DELAYED_CLOSE_ENTRY DelayedEntry;
ULONG ConvKey;
ULONG MaxIterations = MAX_DELAY_WORKER_ITERATIONS;
CM_PAGED_CODE();
UNREFERENCED_PARAMETER (Parameter);
ASSERT(CmpDelayCloseWorkItemActive);
BEGIN_LOCK_CHECKPOINT;
CmpLockRegistry();
//
// process kick out every entry with RefCount == 0 && DelayCloseIndex == 0
// ignore the others; we only do this while there is excess of delay - close kcbs
//
LOCK_DELAY_CLOSE();
while( (CmpDelayedCloseElements > CmpDelayedCloseSize) && (MaxIterations--) ) {
ASSERT( !CmpIsListEmpty(&CmpDelayedLRUListHead) );
//
// We first need to get the hash entry and attempt to lock it.
//
DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)(CmpDelayedLRUListHead.Blink);
DelayedEntry = CONTAINING_RECORD( DelayedEntry,
CM_DELAYED_CLOSE_ENTRY,
DelayedLRUList);
ConvKey = DelayedEntry->KeyControlBlock->ConvKey;
UNLOCK_DELAY_CLOSE();
//
// now lock the hash then recheck if the entry is still first on the list
//
CmpLockHashEntryExclusive(ConvKey);
LOCK_DELAY_CLOSE();
if( CmpDelayedCloseElements <= CmpDelayedCloseSize ) {
//
// just bail out; no need to kick them out
//
CmpUnlockHashEntry(ConvKey);
break;
}
DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)(CmpDelayedLRUListHead.Blink);
DelayedEntry = CONTAINING_RECORD( DelayedEntry,
CM_DELAYED_CLOSE_ENTRY,
DelayedLRUList);
if( ConvKey == DelayedEntry->KeyControlBlock->ConvKey ) {
//
// same hash entry; proceed
// pull it out of the list
//
DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)RemoveTailList(&CmpDelayedLRUListHead);
DelayedEntry = CONTAINING_RECORD( DelayedEntry,
CM_DELAYED_CLOSE_ENTRY,
DelayedLRUList);
CmpClearListEntry(&(DelayedEntry->DelayedLRUList));
if( (DelayedEntry->KeyControlBlock->RefCount == 0) && (DelayedEntry->KeyControlBlock->DelayedCloseIndex == 0) ){
//
// free this kcb and the entry
//
UNLOCK_DELAY_CLOSE();
DelayedEntry->KeyControlBlock->DelayCloseEntry = NULL;
CmpCleanUpKcbCacheWithLock(DelayedEntry->KeyControlBlock,FALSE);
CmpDelayCloseFreeEntry(DelayedEntry);
InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
} else {
//
// put it back at the top
//
InsertHeadList( &CmpDelayedLRUListHead,
&(DelayedEntry->DelayedLRUList)
);
UNLOCK_DELAY_CLOSE();
}
} else {
UNLOCK_DELAY_CLOSE();
}
CmpUnlockHashEntry(ConvKey);
LOCK_DELAY_CLOSE();
}
if( CmpDelayedCloseElements > CmpDelayedCloseSize ) {
//
// iteration run was too short, there are more elements to process, queue ourselves for later
//
CmpArmDelayedCloseTimer();
} else {
//
// signal that we have finished our work.
//
CmpDelayCloseWorkItemActive = FALSE;
}
UNLOCK_DELAY_CLOSE();
CmpUnlockRegistry();
END_LOCK_CHECKPOINT;
}
VOID
CmpArmDelayedCloseTimer( )
/*++
Routine Description:
Arms timer for DelayClose worker procession
NB: this routine should be called with CmpDelayedCloseTableLock held.
If not --> change CmpDelayCloseWorkItemActive to a ULONG and do an InterlockedCompareExchange on it
before setting the timer
Arguments:
Note:
Return Value:
NONE.
--*/
{
LARGE_INTEGER DueTime;
CM_PAGED_CODE();
CmpDelayCloseWorkItemActive = TRUE;
//
// queue a timer for 5 secs later to do the actual delay close
//
DueTime.QuadPart = Int32x32To64(CmpDelayCloseIntervalInSeconds,
- SECOND_MULT);
//
// Indicate relative time
//
KeSetTimer(&CmpDelayCloseTimer,
DueTime,
&CmpDelayCloseDpc);
}
VOID
CmpRemoveFromDelayedClose(
IN PCM_KEY_CONTROL_BLOCK kcb
)
/*++
Routine Description:
Removes a KCB from the delayed close table;
Arguments:
kcb - the kcb in question
Note:
kcb lock/resource should be acquired exclusively when this function is called
Return Value:
NONE.
--*/
{
PCM_DELAYED_CLOSE_ENTRY DelayedEntry;
CM_PAGED_CODE();
ASSERT( (CmpIsKCBLockedExclusive(kcb) == TRUE) || // this kcb is owned exclusive
(CmpTestRegistryLockExclusive() == TRUE) ); // or the entire registry is locked exclusive
// not on delay close; don't try to remove it.
if (kcb->DelayedCloseIndex == CmpDelayedCloseSize) { // see if we really need this
ASSERT( FALSE );
return;
}
DelayedEntry = (PCM_DELAYED_CLOSE_ENTRY)kcb->DelayCloseEntry;
if( DelayedEntry != NULL ) {
LOCK_DELAY_CLOSE();
CmpRemoveEntryList(&(DelayedEntry->DelayedLRUList));
UNLOCK_DELAY_CLOSE();
//
// give back the entry
//
CmpDelayCloseFreeEntry(DelayedEntry);
InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
#if DBG
if( kcb->InDelayClose == 0 ) {
ASSERT( FALSE );
}
{
LONG OldRefCount;
LONG NewRefCount;
OldRefCount = *(PLONG)&kcb->InDelayClose; //get entire dword
ASSERT( OldRefCount == 1 );
NewRefCount = 0;
if( InterlockedCompareExchange((PLONG)&kcb->InDelayClose,NewRefCount,OldRefCount)
!= OldRefCount ) {
ASSERT( FALSE );
}
}
#endif //DBG
}
//
// easy enough huh ?
//
kcb->DelayedCloseIndex = CmpDelayedCloseSize; // see if we really need this
kcb->DelayCloseEntry = NULL;
}
VOID
CmpAddToDelayedClose(
IN PCM_KEY_CONTROL_BLOCK kcb,
IN BOOLEAN RegLockHeldEx
)
/*++
Routine Description:
Adds a kcb to the delayed close table
Arguments:
kcb - the kcb in question
Note:
kcb lock/resource should be acquired exclusively when this function is called
Return Value:
NONE.
--*/
{
PCM_DELAYED_CLOSE_ENTRY DelayedEntry = NULL;
CM_PAGED_CODE();
ASSERT( (CmpIsKCBLockedExclusive(kcb) == TRUE) || // this kcb is owned exclusive
(CmpTestRegistryLockExclusive() == TRUE) ); // or the entire registry is locked exclusive
// Already on delayed close, don't try to put on again
if (kcb->DelayedCloseIndex != CmpDelayedCloseSize) { // see if we really need this
ASSERT( FALSE );
return;
}
ASSERT(kcb->RefCount == 0);
//
// now materialize a new entry for this kcb
//
ASSERT_KEYBODY_LIST_EMPTY(kcb);
DelayedEntry = CmpDelayCloseAllocNewEntry();
if( !DelayedEntry ) {
//
// this is bad luck; we need to free the kcb in place
//
CmpCleanUpKcbCacheWithLock(kcb,RegLockHeldEx);
return;
}
#if DBG
if( kcb->InDelayClose != 0 ) {
ASSERT( FALSE );
}
{
LONG OldRefCount;
LONG NewRefCount;
OldRefCount = *(PLONG)&kcb->InDelayClose; //get entire dword
ASSERT( OldRefCount == 0 );
NewRefCount = 1;
if( InterlockedCompareExchange((PLONG)&kcb->InDelayClose,NewRefCount,OldRefCount)
!= OldRefCount ) {
ASSERT( FALSE );
}
}
#endif //DBG
//
// populate the entry and insert it into the LRU list (at the top).
//
kcb->DelayedCloseIndex = 0; // see if we really need this
kcb->DelayCloseEntry = (PVOID)DelayedEntry; // need this for removing it back from here
DelayedEntry->KeyControlBlock = kcb;
InterlockedIncrement((PLONG)&CmpDelayedCloseElements);
LOCK_DELAY_CLOSE();
InsertHeadList(
&CmpDelayedLRUListHead,
&(DelayedEntry->DelayedLRUList)
);
//
// check if limit hit and arm timer if not already armed
//
if( (CmpDelayedCloseElements > CmpDelayedCloseSize) && (!CmpDelayCloseWorkItemActive) ) {
CmpArmDelayedCloseTimer();
}
UNLOCK_DELAY_CLOSE();
//
// we're done here
//
}
//-----------------------------------------------------------------------------------------------------------//
// //
// Delayed KCB deref. Used when we hit a symlink or when we simply cannot safely acquire the kcb lock //
// //
//-----------------------------------------------------------------------------------------------------------//
LIST_ENTRY CmpDelayDerefKCBListHead;
KGUARDED_MUTEX CmpDelayDerefKCBLock;
WORK_QUEUE_ITEM CmpDelayDerefKCBWorkItem;
BOOLEAN CmpDelayDerefKCBWorkItemActive = FALSE;
KTIMER CmpDelayDerefKCBTimer;
KDPC CmpDelayDerefKCBDpc;
ULONG CmpDelayDerefKCBIntervalInSeconds = 5;
#define LOCK_KCB_DELAY_DEREF_LIST() KeAcquireGuardedMutex(&CmpDelayDerefKCBLock)
#define UNLOCK_KCB_DELAY_DEREF_LIST() KeReleaseGuardedMutex(&CmpDelayDerefKCBLock)
VOID
CmpDelayDerefKCBDpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This is the DPC routine triggered by the delayclose timer.
is queue a work item to an executive worker thread.
Arguments:
Dpc - Supplies a pointer to the DPC object.
DeferredContext - not used
SystemArgument1 - not used
SystemArgument2 - not used
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER (Dpc);
UNREFERENCED_PARAMETER (DeferredContext);
UNREFERENCED_PARAMETER (SystemArgument1);
UNREFERENCED_PARAMETER (SystemArgument2);
ASSERT(CmpDelayDerefKCBWorkItemActive);
ExQueueWorkItem(&CmpDelayDerefKCBWorkItem, DelayedWorkQueue);
}
#define CmpDelayDerefKCBAllocNewEntry() (PCM_DELAY_DEREF_KCB_ITEM)CmpAllocateDelayItem()
#define CmpDelayDerefKCBFreeEntry(Item) CmpFreeDelayItem((PVOID)(Item))
//#define CmpDelayDerefKCBAllocNewEntry() (PCM_DELAY_DEREF_KCB_ITEM)ExAllocatePool(PagedPool,sizeof(CM_DELAY_DEREF_KCB_ITEM))
//#define CmpDelayDerefKCBFreeEntry(Item) ExFreePool(Item)
VOID
CmpInitDelayDerefKCBEngine()
{
InitializeListHead(&CmpDelayDerefKCBListHead);
KeInitializeGuardedMutex(&CmpDelayDerefKCBLock);
ExInitializeWorkItem(&CmpDelayDerefKCBWorkItem, CmpDelayDerefKCBWorker, NULL);
KeInitializeDpc(&CmpDelayDerefKCBDpc,
CmpDelayDerefKCBDpcRoutine,
NULL);
KeInitializeTimer(&CmpDelayDerefKCBTimer);
}
VOID
CmpRunDownDelayDerefKCBEngine( PCM_KEY_CONTROL_BLOCK KeyControlBlock,
BOOLEAN RegLockHeldEx)
{
PCM_DELAY_DEREF_KCB_ITEM DelayItem;
ULONG NewIndex;
ULONG Index1 = CmpHashTableSize;
ULONG Index2 = CmpHashTableSize;
PCMHIVE CmHive = NULL;
BOOLEAN DoUnloadCheck = FALSE;
CM_PAGED_CODE();
ASSERT_CM_LOCK_OWNED();
ASSERT( (KeyControlBlock && CmpIsKCBLockedExclusive(KeyControlBlock)) || (CmpTestRegistryLockExclusive() == TRUE) );
if( KeyControlBlock ) {
Index1 = GET_HASH_INDEX(KeyControlBlock->ConvKey);
if( KeyControlBlock->ParentKcb ) {
Index2 = GET_HASH_INDEX(KeyControlBlock->ParentKcb->ConvKey);
}
}
LOCK_KCB_DELAY_DEREF_LIST();
while( !CmpIsListEmpty(&CmpDelayDerefKCBListHead) ) {
//
// pull it out of the list
//
DelayItem = (PCM_DELAY_DEREF_KCB_ITEM)RemoveHeadList(&CmpDelayDerefKCBListHead);
UNLOCK_KCB_DELAY_DEREF_LIST();
DelayItem = CONTAINING_RECORD( DelayItem,
CM_DELAY_DEREF_KCB_ITEM,
ListEntry);
CmpClearListEntry(&(DelayItem->ListEntry));
//
// take additional precaution in the case the hive has been unloaded and this is the root
//
DoUnloadCheck = FALSE;
if( !DelayItem->Kcb->Delete ) {
CmHive = (PCMHIVE)CONTAINING_RECORD(DelayItem->Kcb->KeyHive, CMHIVE, Hive);
if( IsHiveFrozen(CmHive) ) {
//
// unload is pending for this hive;
//
DoUnloadCheck = TRUE;
}
}
NewIndex = GET_HASH_INDEX(DelayItem->Kcb->ConvKey);
//
// now deref and free
//
if( (NewIndex == Index1) || (NewIndex == Index2) ) {
//
// we already hold the lock
//
ASSERT_KCB_LOCKED_EXCLUSIVE(DelayItem->Kcb);
CmpDereferenceKeyControlBlockWithLock(DelayItem->Kcb,RegLockHeldEx);
} else {
//
// we can't afford to force acquire; try to acquire and if it fails bail out
//
if( CmpKCBLockForceAcquireAllowed(Index1,Index2,NewIndex) ) {
CmpLockHashEntryByIndexExclusive(NewIndex);
} else if( CmpTryToLockHashEntryByIndexExclusive(NewIndex) == FALSE ) {
//
// add the item back to the list and bail out
//
ASSERT( CmpTestRegistryLockExclusive() == FALSE );
LOCK_KCB_DELAY_DEREF_LIST();
InsertHeadList(&CmpDelayDerefKCBListHead,&(DelayItem->ListEntry));
UNLOCK_KCB_DELAY_DEREF_LIST();
return;
}
ASSERT_KCB_LOCKED_EXCLUSIVE(DelayItem->Kcb);
CmpDereferenceKeyControlBlockWithLock(DelayItem->Kcb,RegLockHeldEx);
CmpUnlockHashEntryByIndex(NewIndex);
}
CmpDelayDerefKCBFreeEntry(DelayItem);
//
// if we dropped a reference inside a frozen hive, we may need to unload the hive
//
if( DoUnloadCheck == TRUE ) {
CmpDoQueueLateUnloadWorker(CmHive);
}
LOCK_KCB_DELAY_DEREF_LIST();
}
UNLOCK_KCB_DELAY_DEREF_LIST();
}
VOID
CmpDelayDerefKCBWorker(
IN PVOID Parameter
)
/*++
Routine Description:
Arguments:
Parameter - not used.
Return Value:
None.
--*/
{
PCM_DELAY_DEREF_KCB_ITEM DelayItem;
PCMHIVE CmHive = NULL;
BOOLEAN DoUnloadCheck = FALSE;
CM_PAGED_CODE();
UNREFERENCED_PARAMETER (Parameter);
ASSERT(CmpDelayDerefKCBWorkItemActive);
BEGIN_LOCK_CHECKPOINT;
CmpLockRegistry();
LOCK_KCB_DELAY_DEREF_LIST();
while( !CmpIsListEmpty(&CmpDelayDerefKCBListHead) ) {
//
// pull it out of the list
//
DelayItem = (PCM_DELAY_DEREF_KCB_ITEM)RemoveHeadList(&CmpDelayDerefKCBListHead);
UNLOCK_KCB_DELAY_DEREF_LIST();
DelayItem = CONTAINING_RECORD( DelayItem,
CM_DELAY_DEREF_KCB_ITEM,
ListEntry);
CmpClearListEntry(&(DelayItem->ListEntry));
//
// take additional precaution in the case the hive has been unloaded and this is the root
//
DoUnloadCheck = FALSE;
if( !DelayItem->Kcb->Delete ) {
CmHive = (PCMHIVE)CONTAINING_RECORD(DelayItem->Kcb->KeyHive, CMHIVE, Hive);
if( IsHiveFrozen(CmHive) ) {
//
// unload is pending for this hive;
//
DoUnloadCheck = TRUE;
}
}
//
// now deref and free
//
CmpDereferenceKeyControlBlock(DelayItem->Kcb);
CmpDelayDerefKCBFreeEntry(DelayItem);
//
// if we dropped a reference inside a frozen hive, we may need to unload the hive
//
if( DoUnloadCheck == TRUE ) {
CmpDoQueueLateUnloadWorker(CmHive);
}
LOCK_KCB_DELAY_DEREF_LIST();
}
//
// signal that we have finished our work.
//
CmpDelayDerefKCBWorkItemActive = FALSE;
UNLOCK_KCB_DELAY_DEREF_LIST();
CmpUnlockRegistry();
END_LOCK_CHECKPOINT;
}
VOID
CmpDelayDerefKeyControlBlock( PCM_KEY_CONTROL_BLOCK KeyControlBlock )
/*++
Routine Description:
Adds kcb to a list to be deref in a workitem
Arguments:
kcb - the kcb in question
Note:
kcb lock/resource should be acquired exclusively when this function is called
Return Value:
NONE.
--*/
{
PCM_DELAY_DEREF_KCB_ITEM DelayItem;
LONG OldRefCount;
LONG NewRefCount;
CM_PAGED_CODE();
//
// try the fast path first; we only need to take the work item approach when we drop to 0
//
OldRefCount = *(PLONG)&KeyControlBlock->RefCount; //get entire dword
NewRefCount = OldRefCount - 1;
if( (NewRefCount & 0xffff) > 0 &&
InterlockedCompareExchange((PLONG)&KeyControlBlock->RefCount,NewRefCount,OldRefCount)
== OldRefCount ) {
LogKCBReference(KeyControlBlock,2);
return;
}
DelayItem = CmpDelayDerefKCBAllocNewEntry();
if( DelayItem == NULL ) {
//
// nothing to do here ; we'll leak a reference on this kcb
//
return;
}
DelayItem->Kcb = KeyControlBlock;
LOCK_KCB_DELAY_DEREF_LIST();
InsertTailList( &CmpDelayDerefKCBListHead,&(DelayItem->ListEntry));
//
// if worker is not already up; queue it
//
if( !CmpDelayDerefKCBWorkItemActive ) {
LARGE_INTEGER DueTime;
CmpDelayDerefKCBWorkItemActive = TRUE;
//
// queue a timer for 5 secs later to do the actual delay close
//
DueTime.QuadPart = Int32x32To64(CmpDelayDerefKCBIntervalInSeconds,
- SECOND_MULT);
//
// Indicate relative time
//
KeSetTimer(&CmpDelayDerefKCBTimer,
DueTime,
&CmpDelayDerefKCBDpc);
}
UNLOCK_KCB_DELAY_DEREF_LIST();
}

320
base/ntos/config/cmdelete.c Normal file
View File

@ -0,0 +1,320 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmdelete.c
Abstract:
This module contains the delete object method (used to delete key
control blocks when last handle to a key is closed, and to delete
keys marked for deletetion when last reference to them goes away.)
--*/
#include "cmp.h"
extern BOOLEAN HvShutdownComplete;
VOID
CmpLateUnloadHiveWorker(
IN PVOID Hive
);
VOID
CmpDoQueueLateUnloadWorker(IN PCMHIVE CmHive);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpDeleteKeyObject)
#pragma alloc_text(PAGE,CmpLateUnloadHiveWorker)
#pragma alloc_text(PAGE,CmpDoQueueLateUnloadWorker)
#endif
VOID
CmpDeleteKeyObject(
IN PVOID Object
)
/*++
Routine Description:
This routine interfaces to the NT Object Manager. It is invoked when
the last reference to a particular Key object (or Key Root object)
is destroyed.
If the Key object going away holds the last reference to
the extension it is associated with, that extension is destroyed.
Arguments:
Object - supplies a pointer to a KeyRoot or Key, thus -> KEY_BODY.
Return Value:
NONE.
--*/
{
PCM_KEY_CONTROL_BLOCK KeyControlBlock;
PCM_KEY_BODY KeyBody;
PCMHIVE CmHive = NULL;
BOOLEAN DoUnloadCheck = FALSE;
CM_PAGED_CODE();
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"CmpDeleteKeyObject: Object = %p\n", Object));
//
// HandleClose callback
//
if ( CmAreCallbacksRegistered() ) {
REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo;
KeyHandleCloseInfo.Object = Object;
CmpCallCallBacks(RegNtPreKeyHandleClose,&KeyHandleCloseInfo,TRUE,RegNtPostKeyHandleClose,Object);
}
KeyBody = (PCM_KEY_BODY)Object;
BEGIN_LOCK_CHECKPOINT;
CmpLockRegistry();
if (KeyBody->Type==KEY_BODY_TYPE) {
KeyControlBlock = KeyBody->KeyControlBlock;
//
// the keybody should be initialized; when kcb is null, something went wrong
// between the creation and the dereferenciation of the object
//
if( KeyControlBlock != NULL ) {
//
// Clean up any outstanding notifies attached to the KeyBody
//
CmpFlushNotify(KeyBody,FALSE);
//
// Remove our reference to the KeyControlBlock, clean it up, perform any
// pend-till-final-close operations.
//
// NOTE: Delete notification is seen at the parent of the deleted key,
// not the deleted key itself. If any notify was outstanding on
// this key, it was cleared away above us. Only parent/ancestor
// keys will see the report.
//
//
// The dereference will free the KeyControlBlock. If the key was deleted, it
// has already been removed from the hash table, and relevant notifications
// posted then as well. All we are doing is freeing the tombstone.
//
// If it was not deleted, we're both cutting the kcb out of
// the kcb list/tree, AND freeing its storage.
//
//
// Replace this with the definition so we avoid dropping and reacquiring the lock
DelistKeyBodyFromKCB(KeyBody,FALSE);
//
// take additional precaution in the case the hive has been unloaded and this is the root
//
if( !KeyControlBlock->Delete ) {
CmHive = (PCMHIVE)CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive);
if( IsHiveFrozen(CmHive) ) {
//
// unload is pending for this hive;
//
DoUnloadCheck = TRUE;
}
}
CmpDelayDerefKeyControlBlock(KeyControlBlock);
}
} else {
//
// This must be a predefined handle
// some sanity asserts
//
KeyControlBlock = KeyBody->KeyControlBlock;
ASSERT( KeyBody->Type&REG_PREDEF_HANDLE_MASK);
ASSERT( KeyControlBlock->Flags&KEY_PREDEF_HANDLE );
if( KeyControlBlock != NULL ) {
CmHive = (PCMHIVE)CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive);
if( IsHiveFrozen(CmHive) ) {
//
// unload is pending for this hive; we shouldn't put the kcb in the delay
// close table
//
DoUnloadCheck = TRUE;
}
CmpDereferenceKeyControlBlock(KeyControlBlock);
}
}
//
// if a handle inside a frozen hive has been closed, we may need to unload the hive
//
if( DoUnloadCheck == TRUE ) {
CmpDoQueueLateUnloadWorker(CmHive);
}
CmpUnlockRegistry();
END_LOCK_CHECKPOINT;
//
// just a notification; disregard the return status
//
CmPostCallbackNotification(RegNtPostKeyHandleClose,NULL,STATUS_SUCCESS);
return;
}
VOID
CmpDoQueueLateUnloadWorker(IN PCMHIVE CmHive)
{
PWORK_QUEUE_ITEM WorkItem;
CM_PAGED_CODE();
ASSERT( CmHive->RootKcb != NULL );
//
// NB: Hive lock has higher precedence; We don't need the kcb lock as we are only checking the refcount
//
CmLockHive(CmHive);
if( (CmHive->RootKcb->RefCount == 1) && (CmHive->UnloadWorkItem == NULL) ) {
//
// the only reference on the rookcb is the one that we artificially created
// queue a work item to late unload the hive
//
WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
if( InterlockedCompareExchangePointer(&(CmHive->UnloadWorkItem),WorkItem,NULL) == NULL ) {
ExInitializeWorkItem(CmHive->UnloadWorkItem,
CmpLateUnloadHiveWorker,
CmHive);
ExQueueWorkItem(CmHive->UnloadWorkItem, DelayedWorkQueue);
} else {
ExFreePool(WorkItem);
}
}
CmUnlockHive(CmHive);
}
VOID
CmpLateUnloadHiveWorker(
IN PVOID Hive
)
/*++
Routine Description:
"Late" unloads the hive; If nothing goes badly wrong (i.e. insufficient resources),
this function should succeed
Arguments:
CmHive - the frozen hive to be unloaded
Return Value:
NONE.
--*/
{
NTSTATUS Status;
HCELL_INDEX Cell;
PCM_KEY_CONTROL_BLOCK RootKcb;
PCMHIVE CmHive;
CM_PAGED_CODE();
//
// first, load the registry exclusive
//
CmpLockRegistryExclusive();
//
// hive is the parameter to this worker; make sure we free the work item
// allocated by CmpDeleteKeyObject
//
CmHive = (PCMHIVE)Hive;
ASSERT( CmHive->UnloadWorkItem != NULL );
ExFreePool( CmHive->UnloadWorkItem );
//
// if this attempt doesn't succeed, mark that we can try another
//
CmHive->UnloadWorkItem = NULL;
ASSERT( !(CmHive->Hive.HiveFlags & HIVE_IS_UNLOADING) );
if( CmHive->Frozen == FALSE ) {
//
// another thread mounted the exact same hive in the exact same place, hence unfreezing the hive
// we've done the cleanup part (free the workitem) nothing more to do.
// or hive is already in process of being unloaded
//
ASSERT( CmHive->RootKcb == NULL );
CmpUnlockRegistry();
return;
}
//
// this is just about the only possible way the hive can get corrupted in between
//
if( HvShutdownComplete == TRUE ) {
// too late to do anything
CmpUnlockRegistry();
return;
}
//
// hive should be frozen, otherwise we wouldn't get here
//
ASSERT( CmHive->Frozen == TRUE );
RootKcb = CmHive->RootKcb;
//
// root kcb must be valid and has only our "artificial" refcount on it
//
ASSERT( RootKcb != NULL );
if( RootKcb->RefCount > 1 ) {
//
// somebody else must've gotten in between dropping/reacquiring the reglock
// and opened a handle inside this hive; bad luck, we can't unload
//
CmpUnlockRegistry();
return;
}
ASSERT_KCB(RootKcb);
Cell = RootKcb->KeyCell;
Status = CmUnloadKey(RootKcb,0,CM_UNLOAD_REG_LOCKED_EX);
ASSERT( (Status != STATUS_CANNOT_DELETE) && (Status != STATUS_INVALID_PARAMETER) );
if(NT_SUCCESS(Status)) {
// CmUnloadKey already released the lock
CmpLockRegistry();
CmpDereferenceKeyControlBlock(RootKcb);
}
CmpUnlockRegistry();
}

349
base/ntos/config/cmdown.c Normal file
View File

@ -0,0 +1,349 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmdown.c
Abstract:
This module cleans up all the memory used by CM.
This routine is intended to be called at system shutdown
in order to detect memory leaks. It is supposed to free
all registry data that is not freed by CmShutdownSystem.
--*/
#include "cmp.h"
//
// externals
//
extern PUCHAR CmpStashBuffer;
extern ULONG CmpDelayedCloseSize;
extern BOOLEAN HvShutdownComplete;
extern BOOLEAN CmFirstTime;
extern HIVE_LIST_ENTRY CmpMachineHiveList[];
VOID
CmpFreeAllMemory(
VOID
);
VOID
CmpDereferenceNameControlBlockWithLock(
PCM_NAME_CONTROL_BLOCK Ncb
);
VOID
CmpDumpKeyBodyList(
IN PCM_KEY_CONTROL_BLOCK kcb,
IN PULONG Count,
IN PVOID Context
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpFreeAllMemory)
#pragma alloc_text(PAGE,CmShutdownSystem)
#endif
VOID
CmpFreeAllMemory(
VOID
)
/*++
Routine Description:
- All hives are freed
- KCB table is freed
- Name hash table is freed
- delay close table is freed - question: We need to clean/free all delayed close KCBs
- all notifications/postblocks-aso.
* equivalent with MmReleaseAllMemory
Arguments:
Return Value:
--*/
{
PCMHIVE CmHive;
LONG i;
PCM_KEY_CONTROL_BLOCK KeyControlBlock;
PLIST_ENTRY NotifyPtr;
PCM_NOTIFY_BLOCK NotifyBlock;
PCM_POST_BLOCK PostBlock;
PCM_KEY_HASH Current;
PLIST_ENTRY AnchorAddr;
ULONG Count;
BOOLEAN MessageDisplayed;
CmpRunDownDelayDerefKCBEngine(NULL,TRUE);
//
// Iterate through the list of the hives in the system
//
while (IsListEmpty(&CmpHiveListHead) == FALSE) {
//
// Remove the hive from the list
//
CmHive = (PCMHIVE)RemoveHeadList(&CmpHiveListHead);
CmHive = (PCMHIVE)CONTAINING_RECORD(CmHive,
CMHIVE,
HiveList);
//
// close hive handles (the ones that are open)
//
for (i=0; i<HFILE_TYPE_MAX; i++) {
// these should be closed by CmShutdownSystem
ASSERT( CmHive->FileHandles[i] == NULL );
}
//
// free the hive lock and view lock
//
CmpFreeMutex(CmHive->ViewLock);
#if DBG
CmpFreeResource(CmHive->FlusherLock);
#endif
//
// Spew in the debugger the names of the keynodes having notifies still set
//
NotifyPtr = &(CmHive->NotifyList);
NotifyPtr = NotifyPtr->Flink;
MessageDisplayed = FALSE;
while( NotifyPtr != NULL ) {
NotifyBlock = CONTAINING_RECORD(NotifyPtr, CM_NOTIFY_BLOCK, HiveList);
AnchorAddr = &(NotifyBlock->PostList);
PostBlock = (PCM_POST_BLOCK)(NotifyBlock->PostList.Flink);
//
// walk through the list and spew the keynames and postblock types.
//
while ( PostBlock != (PCM_POST_BLOCK)AnchorAddr ) {
PostBlock = CONTAINING_RECORD(PostBlock,
CM_POST_BLOCK,
NotifyList);
if( PostBlock->PostKeyBody ) {
if( MessageDisplayed == FALSE ){
MessageDisplayed = TRUE;
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Dumping untriggered notifications for hive (%lx) (%.*S) \n\n",CmHive,
HBASE_NAME_ALLOC / sizeof(WCHAR),CmHive->Hive.BaseBlock->FileName);
}
switch (PostBlockType(PostBlock)) {
case PostSynchronous:
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Synchronous ");
break;
case PostAsyncUser:
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"AsyncUser ");
break;
case PostAsyncKernel:
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"AsyncKernel ");
break;
}
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Notification, PostBlock %p not triggered on KCB %p\n",PostBlock,
PostBlock->PostKeyBody->KeyBody->KeyControlBlock);
}
//
// skip to the next element
//
PostBlock = (PCM_POST_BLOCK)(PostBlock->NotifyList.Flink);
}
NotifyPtr = NotifyPtr->Flink;
}
//
// free security cache
//
CmpDestroySecurityCache (CmHive);
//
// free the hv level structure
//
HvFreeHive(&(CmHive->Hive));
//
// free the cm level structure
//
CmpFree(CmHive, sizeof(CMHIVE));
}
//
// Now free the CM globals
//
// the stash buffer
if( CmpStashBuffer != NULL ) {
ExFreePool( CmpStashBuffer );
}
//
// Spew open handles and associated processes
//
Count = 0;
MessageDisplayed = FALSE;
for (i=0; i<(LONG)CmpHashTableSize; i++) {
Current = CmpCacheTable[i].Entry;
while (Current) {
KeyControlBlock = CONTAINING_RECORD(Current, CM_KEY_CONTROL_BLOCK, KeyHash);
if( MessageDisplayed == FALSE ){
MessageDisplayed = TRUE;
DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\nDumping open handles : \n\n");
}
CmpDumpKeyBodyList(KeyControlBlock,&Count,NULL);
Current = Current->NextHash;
}
}
if( Count != 0 ) {
//
// there some open handles; bugcheck
//
CM_BUGCHECK( REGISTRY_ERROR,HANDLES_STILL_OPEN_AT_SHUTDOWN,1,Count,0);
}
//
// in case of private alloc, free pages
//
CmpDestroyCmPrivateAlloc();
CmpDestroyCmPrivateDelayAlloc();
//
// For the 3 tables below, the objects actually pointed from inside
// should be cleaned up (freed) at the last handle closure time
// the related handles are closed
//
// KCB cache table
ASSERT( CmpCacheTable != NULL );
ExFreePool(CmpCacheTable);
// NameCacheTable
ASSERT( CmpNameCacheTable != NULL );
ExFreePool( CmpNameCacheTable );
}
VOID
CmShutdownSystem(
VOID
)
/*++
Routine Description:
Shuts down the registry.
Arguments:
NONE
Return Value:
NONE
--*/
{
PLIST_ENTRY p;
PCMHIVE CmHive;
NTSTATUS Status;
PVOID RegistryRoot;
CM_PAGED_CODE();
if (CmpRegistryRootHandle) {
Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
KEY_READ,
NULL,
KernelMode,
&RegistryRoot,
NULL);
if (NT_SUCCESS(Status)) {
// We want to dereference the object twice -- once for the
// reference we just made, and once for the reference
// fromCmpCreateRegistryRoot.
ObDereferenceObject(RegistryRoot);
ObDereferenceObject(RegistryRoot);
}
ObCloseHandle(CmpRegistryRootHandle, KernelMode);
}
CmpLockRegistryExclusive();
//
// Stop the workers; only if registry has been initializeed
//
if( CmFirstTime == FALSE ) {
CmpShutdownWorkers();
}
//
// shut down the registry
//
CmpDoFlushAll(TRUE);
//
// try to compress the system hive
//
CmCompressKey( &(CmpMachineHiveList[SYSTEM_HIVE_INDEX].CmHive->Hive) );
//
// close all the hive files
//
p = CmpHiveListHead.Flink;
while(p != &CmpHiveListHead) {
CmHive = CONTAINING_RECORD(p, CMHIVE, HiveList);
//
// we need to unmap all views mapped for this hive first
//
CmpDestroyHiveViewList(CmHive);
CmpUnJoinClassOfTrust(CmHive);
//
// dereference the fileobject (if any).
//
CmpDropFileObjectForHive(CmHive);
//
// now we can safely close all the handles
//
CmpCmdHiveClose(CmHive);
p=p->Flink;
}
HvShutdownComplete = TRUE; // Tell HvSyncHive to ignore all further requests
if((PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_REGISTRY) && (CmFirstTime == FALSE)){
//
// Free aux memory used internally by CM
//
CmpFreeAllMemory();
}
CmpUnlockRegistry();
return;
}

852
base/ntos/config/cmgquota.c Normal file
View File

@ -0,0 +1,852 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmgquota.c
Abstract:
The module contains CM routines to support Global Quota
Global Quota has little to do with NT's standard per-process/user
quota system. Global Quota is waying of controlling the aggregate
resource usage of the entire registry. It is used to manage space
consumption by objects which user apps create, but which are persistent
and therefore cannot be assigned to the quota of a user app.
Global Quota prevents the registry from consuming all of paged
pool, and indirectly controls how much disk it can consume.
Like the release 1 file systems, a single app can fill all the
space in the registry, but at least it cannot kill the system.
Memory objects used for known short times and protected by
serialization, or billable as quota objects, are not counted
in the global quota.
--*/
#include "cmp.h"
VOID
CmpSystemHiveHysteresisWorker(
IN PVOID WorkItem
);
VOID
CmpRaiseSelfHealWarningWorker(
IN PVOID Arg
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpClaimGlobalQuota)
#pragma alloc_text(PAGE,CmpReleaseGlobalQuota)
#pragma alloc_text(PAGE,CmpSetGlobalQuotaAllowed)
#pragma alloc_text(PAGE,CmpQuotaWarningWorker)
#pragma alloc_text(PAGE,CmQueryRegistryQuotaInformation)
#pragma alloc_text(PAGE,CmSetRegistryQuotaInformation)
#pragma alloc_text(PAGE,CmpCanGrowSystemHive)
#pragma alloc_text(PAGE,CmpSystemQuotaWarningWorker)
#pragma alloc_text(INIT,CmpComputeGlobalQuotaAllowed)
#pragma alloc_text(PAGE,CmpSystemHiveHysteresisWorker)
#pragma alloc_text(PAGE,CmpUpdateSystemHiveHysteresis)
#pragma alloc_text(PAGE,CmRegisterSystemHiveLimitCallback)
#pragma alloc_text(PAGE,CmpRaiseSelfHealWarning)
#pragma alloc_text(PAGE,CmpRaiseSelfHealWarningForSystemHives)
#pragma alloc_text(PAGE,CmpRaiseSelfHealWarningWorker)
#endif
//
// Registry control values
//
#define CM_DEFAULT_RATIO (3)
#define CM_LIMIT_RATIO(x) ((x / 10) * 8)
#define CM_MINIMUM_GLOBAL_QUOTA (16 *1024 * 1024)
//
// Percent of used registry quota that triggers a hard error
// warning popup.
//
#define CM_REGISTRY_WARNING_LEVEL (95)
//
// System hive hard quota limit
//
// For an x86 3GB system we set the limit at 12MB for now. Needs some MM changes before we
// bump this up.
// For an x86 non-3GB system, we set the limit at 1/4 of physical memory
// For IA-64 we set the limit at 32MB
//
#define _200MB (200 *1024 * 1024)
#if defined(_X86_)
#define CM_SYSTEM_HIVE_LIMIT_SIZE (min(MmNumberOfPhysicalPages / 4, _200MB >> PAGE_SHIFT) * PAGE_SIZE)
#else
#define CM_SYSTEM_HIVE_LIMIT_SIZE (32 * 1024 * 1024)
#endif
#define CM_SYSTEM_HIVE_WARNING_SIZE ((CM_SYSTEM_HIVE_LIMIT_SIZE*9)/10)
extern ULONG CmRegistrySizeLimit;
extern ULONG CmRegistrySizeLimitLength;
extern ULONG CmRegistrySizeLimitType;
//
// Maximum number of bytes of Global Quota the registry may use.
// Set to largest positive number for use in boot. Will be set down
// based on pool and explicit registry values.
//
extern SIZE_T CmpGlobalQuota;
extern SIZE_T CmpGlobalQuotaAllowed;
//
// Mark that will trigger the low-on-quota popup
//
extern SIZE_T CmpGlobalQuotaWarning;
extern SIZE_T MmSizeOfPagedPoolInBytes;
//
// Indicate whether the popup has been triggered yet or not.
//
extern BOOLEAN CmpQuotaWarningPopupDisplayed;
extern BOOLEAN CmpSystemQuotaWarningPopupDisplayed;
//
// GQ actually in use
//
extern SIZE_T CmpGlobalQuotaUsed;
extern HIVE_LIST_ENTRY CmpMachineHiveList[];
VOID
CmQueryRegistryQuotaInformation(
__inout PSYSTEM_REGISTRY_QUOTA_INFORMATION RegistryQuotaInformation
)
/*++
Routine Description:
Returns the registry quota information
Arguments:
RegistryQuotaInformation - Supplies pointer to buffer that will return
the registry quota information.
Return Value:
None.
--*/
{
RegistryQuotaInformation->RegistryQuotaAllowed = (ULONG) CmpGlobalQuota;
RegistryQuotaInformation->RegistryQuotaUsed = (ULONG) CmpGlobalQuotaUsed;
RegistryQuotaInformation->PagedPoolSize = MmSizeOfPagedPoolInBytes;
}
VOID
CmSetRegistryQuotaInformation(
__in PSYSTEM_REGISTRY_QUOTA_INFORMATION RegistryQuotaInformation
)
/*++
Routine Description:
Sets the registry quota information. The caller is assumed to have
completed the necessary security checks already.
Arguments:
RegistryQuotaInformation - Supplies pointer to buffer that provides
the new registry quota information.
Return Value:
None.
--*/
{
CmpGlobalQuota = RegistryQuotaInformation->RegistryQuotaAllowed;
//
// Sanity checks against insane values
//
if (CmpGlobalQuota > CM_WRAP_LIMIT) {
CmpGlobalQuota = CM_WRAP_LIMIT;
}
if (CmpGlobalQuota < CM_MINIMUM_GLOBAL_QUOTA) {
CmpGlobalQuota = CM_MINIMUM_GLOBAL_QUOTA;
}
//
// Recompute the warning level
//
CmpGlobalQuotaWarning = CM_REGISTRY_WARNING_LEVEL * (CmpGlobalQuota / 100);
CmpGlobalQuotaAllowed = CmpGlobalQuota;
}
VOID
CmpQuotaWarningWorker(
IN PVOID WorkItem
)
/*++
Routine Description:
Displays hard error popup that indicates the registry quota is
running out.
Arguments:
WorkItem - Supplies pointer to the work item. This routine will
free the work item.
Return Value:
None.
--*/
{
NTSTATUS Status;
ULONG Response;
ExFreePool(WorkItem);
Status = ExRaiseHardError(STATUS_REGISTRY_QUOTA_LIMIT,
0,
0,
NULL,
OptionOk,
&Response);
}
BOOLEAN
CmpClaimGlobalQuota(
IN ULONG Size
)
/*++
Routine Description:
If CmpGlobalQuotaUsed + Size >= CmpGlobalQuotaAllowed, return
false. Otherwise, increment CmpGlobalQuotaUsed, in effect claiming
the requested GlobalQuota.
Arguments:
Size - number of bytes of GlobalQuota caller wants to claim
Return Value:
TRUE - Claim succeeded, and has been counted in Used GQ
FALSE - Claim failed, nothing counted in GQ.
--*/
{
InterlockedExchangeAdd((PLONG)&CmpGlobalQuotaUsed, Size);
return TRUE;
}
VOID
CmpReleaseGlobalQuota(
IN ULONG Size
)
/*++
Routine Description:
If Size <= CmpGlobalQuotaUsed, then decrement it. Else BugCheck.
Arguments:
Size - number of bytes of GlobalQuota caller wants to release
Return Value:
NONE.
--*/
{
if (Size > CmpGlobalQuotaUsed) {
CM_BUGCHECK(REGISTRY_ERROR,QUOTA_ERROR,1,0,0);
}
InterlockedExchangeAdd((PLONG)&CmpGlobalQuotaUsed, -(LONG)Size);
}
VOID
CmpComputeGlobalQuotaAllowed(
VOID
)
/*++
Routine Description:
Compute CmpGlobalQuota based on:
(a) Size of paged pool
(b) Explicit user registry commands to set registry GQ
Return Value:
NONE.
--*/
{
SIZE_T PagedLimit;
PagedLimit = (ULONG)(CM_LIMIT_RATIO(MmSizeOfPagedPoolInBytes));
if ((CmRegistrySizeLimitLength != 4) ||
(CmRegistrySizeLimitType != REG_DWORD) ||
(CmRegistrySizeLimit == 0))
{
//
// If no value at all, or value of wrong type, or set to
// zero, use internally computed default
//
CmpGlobalQuota = (ULONG)(MmSizeOfPagedPoolInBytes / CM_DEFAULT_RATIO);
} else if (CmRegistrySizeLimit >= PagedLimit) {
//
// If more than computed upper bound, use computed upper bound
//
CmpGlobalQuota = PagedLimit;
} else {
//
// Use the set size
//
CmpGlobalQuota = CmRegistrySizeLimit;
}
if (CmpGlobalQuota > CM_WRAP_LIMIT) {
CmpGlobalQuota = CM_WRAP_LIMIT;
}
if (CmpGlobalQuota < CM_MINIMUM_GLOBAL_QUOTA) {
CmpGlobalQuota = CM_MINIMUM_GLOBAL_QUOTA;
}
CmpGlobalQuotaWarning = CM_REGISTRY_WARNING_LEVEL * (CmpGlobalQuota / 100);
return;
}
VOID
CmpSetGlobalQuotaAllowed(
VOID
)
/*++
Routine Description:
Enables registry quota
NOTE: Do NOT put this in init segment, we call it after
that code has been freed!
Return Value:
NONE.
--*/
{
CmpGlobalQuotaAllowed = CmpGlobalQuota;
}
BOOLEAN
CmpCanGrowSystemHive(
IN PHHIVE Hive,
IN ULONG NewLength
)
/*++
Routine Description:
Checks if the system hive is allowed to grow with the specified amount
of data (using the hard quota limit on the system hive)
Return Value:
NONE.
--*/
{
PCMHIVE CmHive;
PWORK_QUEUE_ITEM WorkItem;
PAGED_CODE();
CmHive = (PCMHIVE)CONTAINING_RECORD(Hive,CMHIVE,Hive);
if( CmHive != CmpMachineHiveList[SYSTEM_HIVE_INDEX].CmHive ) {
//
// not the system hive, bail out
//
return TRUE;
}
// account for the header.
NewLength += HBLOCK_SIZE;
if( NewLength > CM_SYSTEM_HIVE_LIMIT_SIZE ) {
//
// this is bad; we may not be able to boot next time !!!
//
return FALSE;
}
if( (NewLength > CM_SYSTEM_HIVE_WARNING_SIZE) &&
(!CmpSystemQuotaWarningPopupDisplayed) &&
(ExReadyForErrors)
) {
//
// we're above the warning level, queue work item to display popup
//
WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
if (WorkItem != NULL) {
CmpSystemQuotaWarningPopupDisplayed = TRUE;
ExInitializeWorkItem(WorkItem,
CmpSystemQuotaWarningWorker,
WorkItem);
ExQueueWorkItem(WorkItem, DelayedWorkQueue);
}
}
return TRUE;
}
VOID
CmpSystemQuotaWarningWorker(
IN PVOID WorkItem
)
/*++
Routine Description:
Displays hard error popup that indicates the hard quota limit
on the system hive is running out.
Arguments:
WorkItem - Supplies pointer to the work item. This routine will
free the work item.
Return Value:
None.
--*/
{
NTSTATUS Status;
ULONG Response;
ExFreePool(WorkItem);
Status = ExRaiseHardError(STATUS_REGISTRY_QUOTA_LIMIT,
0,
0,
NULL,
OptionOk,
&Response);
}
//
// Pnp API
//
ULONG CmpSystemHiveHysteresisLow = 0;
ULONG CmpSystemHiveHysteresisHigh = 0;
PVOID CmpSystemHiveHysteresisContext = NULL;
PCM_HYSTERESIS_CALLBACK CmpSystemHiveHysteresisCallback = NULL;
ULONG CmpSystemHiveHysteresisHitRatio = 0;
BOOLEAN CmpSystemHiveHysteresisLowSeen = FALSE;
BOOLEAN CmpSystemHiveHysteresisHighSeen = FALSE;
VOID
CmpSystemHiveHysteresisWorker(
IN PVOID WorkItem
)
/*++
Routine Description:
Calls the hysteresis callback
Arguments:
WorkItem - Supplies pointer to the work item. This routine will
free the work item.
Return Value:
None.
--*/
{
PCM_HYSTERESIS_CALLBACK Callback;
ExFreePool(WorkItem);
Callback = CmpSystemHiveHysteresisCallback;
if( Callback ) {
(*Callback)(CmpSystemHiveHysteresisContext,CmpSystemHiveHysteresisHitRatio);
}
}
VOID
CmpUpdateSystemHiveHysteresis( PHHIVE Hive,
ULONG NewLength,
ULONG OldLength
)
{
PCMHIVE CmHive;
PWORK_QUEUE_ITEM WorkItem;
ULONG CurrentRatio;
BOOLEAN DoWorkItem = FALSE;
PAGED_CODE();
CmHive = (PCMHIVE)CONTAINING_RECORD(Hive,CMHIVE,Hive);
if( (!CmpSystemHiveHysteresisCallback) || (CmHive != CmpMachineHiveList[SYSTEM_HIVE_INDEX].CmHive) ) {
//
// not the system hive, bail out
//
return;
}
ASSERT( NewLength != OldLength );
//
// compute current ratio; account for the header first
//
CurrentRatio = NewLength + HBLOCK_SIZE;
CurrentRatio *= 100;
CurrentRatio /= CM_SYSTEM_HIVE_LIMIT_SIZE;
if( NewLength > OldLength ) {
//
// hive is growing
//
if( (CmpSystemHiveHysteresisHighSeen == FALSE) && (CurrentRatio > CmpSystemHiveHysteresisHigh) ) {
//
// we reached high; see if low has already been hit and queue work item
//
CmpSystemHiveHysteresisHighSeen = TRUE;
if( TRUE == CmpSystemHiveHysteresisLowSeen ) {
//
// low to high; queue workitem
//
CmpSystemHiveHysteresisHitRatio = CurrentRatio;
DoWorkItem = TRUE;
}
}
} else {
//
// hive is shrinking
//
if( (FALSE == CmpSystemHiveHysteresisLowSeen) && (CurrentRatio < CmpSystemHiveHysteresisLow ) ) {
//
// we reached low; see if low has been hit and queue work item
//
CmpSystemHiveHysteresisLowSeen = TRUE;
if( TRUE == CmpSystemHiveHysteresisHighSeen ) {
//
// high to low; queue workitem
//
CmpSystemHiveHysteresisHitRatio = CurrentRatio;
DoWorkItem = TRUE;
}
}
}
if( DoWorkItem ) {
ASSERT( CmpSystemHiveHysteresisLowSeen && CmpSystemHiveHysteresisHighSeen );
WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
if (WorkItem != NULL) {
ExInitializeWorkItem(WorkItem,
CmpSystemHiveHysteresisWorker,
WorkItem);
ExQueueWorkItem(WorkItem, DelayedWorkQueue);
}
//
// reset state so we can fire again later
//
CmpSystemHiveHysteresisLowSeen = FALSE;
CmpSystemHiveHysteresisHighSeen = FALSE;
}
}
ULONG
CmRegisterSystemHiveLimitCallback(
__in ULONG Low,
__in ULONG High,
__in PVOID Ref,
__in PCM_HYSTERESIS_CALLBACK Callback
)
/*++
Routine Description:
This routine registers a hysteresis for the system hive limit ratio.
We will call the callback :
a. the system hive goes above High from below Low
b. the system hive goes below Low from above High
Arguments:
Low, High - specifies the hysteresis
Ref - Context to give back to the callback
Callback - callback routine.
Return Value:
current ratio 0 - 100
--*/
{
ULONG Length;
PAGED_CODE();
if( CmpMachineHiveList[SYSTEM_HIVE_INDEX].CmHive ) {
Length = CmpMachineHiveList[SYSTEM_HIVE_INDEX].CmHive->Hive.BaseBlock->Length + HBLOCK_SIZE;
Length *= 100;
Length /= CM_SYSTEM_HIVE_LIMIT_SIZE;
} else {
Length = 0;
}
//
// allow only one call per system uptime.
//
if( CmpSystemHiveHysteresisCallback == NULL ) {
CmpSystemHiveHysteresisLow = Low;
CmpSystemHiveHysteresisHigh = High;
CmpSystemHiveHysteresisContext = Ref;
CmpSystemHiveHysteresisCallback = Callback;
//
// set state vars
//
if( Length <= Low ) {
CmpSystemHiveHysteresisLowSeen = TRUE;
} else {
CmpSystemHiveHysteresisLowSeen = FALSE;
}
if( Length >= High) {
CmpSystemHiveHysteresisHighSeen = TRUE;
} else {
CmpSystemHiveHysteresisHighSeen = FALSE;
}
}
return Length;
}
VOID
CmpHysteresisTest(PVOID Ref, ULONG Level)
{
UNREFERENCED_PARAMETER (Ref);
DbgPrint("CmpHysteresisTest called with level = %lu \n",Level);
}
LIST_ENTRY CmpSelfHealQueueListHead;
KGUARDED_MUTEX CmpSelfHealQueueLock;
BOOLEAN CmpSelfHealWorkerActive = FALSE;
#define LOCK_SELF_HEAL_QUEUE() KeAcquireGuardedMutex(&CmpSelfHealQueueLock)
#define UNLOCK_SELF_HEAL_QUEUE() KeReleaseGuardedMutex(&CmpSelfHealQueueLock)
typedef struct {
PWORK_QUEUE_ITEM WorkItem;
LIST_ENTRY SelfHealQueueListEntry;
UNICODE_STRING HiveName;
//
// variable length; name goes here
//
} CM_SELF_HEAL_WORK_ITEM_PARAMETER, *PCM_SELF_HEAL_WORK_ITEM_PARAMETER;
VOID
CmpRaiseSelfHealWarningWorker(
IN PVOID Arg
)
{
PVOID ErrorParameters;
ULONG ErrorResponse;
PCM_SELF_HEAL_WORK_ITEM_PARAMETER Param;
Param = (PCM_SELF_HEAL_WORK_ITEM_PARAMETER)Arg;
ErrorParameters = &(Param->HiveName);
ExRaiseHardError(
STATUS_REGISTRY_HIVE_RECOVERED,
1,
1,
(PULONG_PTR)&ErrorParameters,
OptionOk,
&ErrorResponse
);
//
// free what we have allocated
//
ExFreePool(Param->WorkItem);
ExFreePool(Param);
//
// see if there are other self heal warnings to be posted.
//
LOCK_SELF_HEAL_QUEUE();
CmpSelfHealWorkerActive = FALSE;
if( IsListEmpty(&CmpSelfHealQueueListHead) == FALSE ) {
//
// remove head and queue it.
//
Param = (PCM_SELF_HEAL_WORK_ITEM_PARAMETER)RemoveHeadList(&CmpSelfHealQueueListHead);
Param = CONTAINING_RECORD(
Param,
CM_SELF_HEAL_WORK_ITEM_PARAMETER,
SelfHealQueueListEntry
);
ExQueueWorkItem(Param->WorkItem, DelayedWorkQueue);
CmpSelfHealWorkerActive = TRUE;
}
UNLOCK_SELF_HEAL_QUEUE();
}
VOID
CmpRaiseSelfHealWarning(
IN PUNICODE_STRING HiveName
)
/*++
Routine Description:
Raise a hard error informing the use the specified hive has been self healed and
it might not be entirely consitent
Arguments:
Parameter - the hive name.
Return Value:
None.
--*/
{
PCM_SELF_HEAL_WORK_ITEM_PARAMETER Param;
PAGED_CODE();
//
// we're above the warning level, queue work item to display popup
//
Param = ExAllocatePool(NonPagedPool, sizeof(CM_SELF_HEAL_WORK_ITEM_PARAMETER) + HiveName->Length);
if( Param ) {
Param->WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
if(Param->WorkItem != NULL) {
Param->HiveName.Length = Param->HiveName.MaximumLength = HiveName->Length;
Param->HiveName.Buffer = (PWSTR)(((PUCHAR)Param) + sizeof(CM_SELF_HEAL_WORK_ITEM_PARAMETER));
RtlCopyMemory(Param->HiveName.Buffer,HiveName->Buffer,HiveName->Length);
ExInitializeWorkItem(Param->WorkItem,
CmpRaiseSelfHealWarningWorker,
Param);
LOCK_SELF_HEAL_QUEUE();
if( !CmpSelfHealWorkerActive ) {
//
// no work item currently; ok to queue one.
//
ExQueueWorkItem(Param->WorkItem, DelayedWorkQueue);
CmpSelfHealWorkerActive = TRUE;
} else {
//
// add it to the end of the list. It'll be picked up when the current work item
// completes
//
InsertTailList(
&CmpSelfHealQueueListHead,
&(Param->SelfHealQueueListEntry)
);
}
UNLOCK_SELF_HEAL_QUEUE();
} else {
ExFreePool(Param);
}
}
}
VOID
CmpRaiseSelfHealWarningForSystemHives( )
/*++
Routine Description:
Walks the system hivelist and raises a hard error in the event one of the hives has been self healed.
Intended to be called after controlset has been saved, from inside NtInitializeRegistry
(i.e. we have an UI available so it will not stop the machine).
Arguments:
Return Value:
None.
--*/
{
ULONG i;
UNICODE_STRING Name;
PAGED_CODE();
for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) {
if( !(CmpMachineHiveList[i].HHiveFlags & HIVE_VOLATILE) && (((PHHIVE)(CmpMachineHiveList[i].CmHive2))->BaseBlock->BootType & HBOOT_SELFHEAL) ) {
RtlInitUnicodeString(
&Name,
CmpMachineHiveList[i].Name
);
CmpRaiseSelfHealWarning( &Name );
}
}
}

405
base/ntos/config/cmhook.c Normal file
View File

@ -0,0 +1,405 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmhook.c
Abstract:
Provides routines for implementing callbacks into the registry code.
Callbacks are to be used by the virus filter drivers and cluster
replication engine.
--*/
#include "cmp.h"
#define CM_MAX_CALLBACKS 100
typedef struct _CM_CALLBACK_CONTEXT_BLOCK {
LARGE_INTEGER Cookie; // to identify a specific callback for deregistration purposes
LIST_ENTRY ThreadListHead; // Active threads inside this callback
EX_PUSH_LOCK ThreadListLock; // synchronize access to the above
PVOID CallerContext;
} CM_CALLBACK_CONTEXT_BLOCK, *PCM_CALLBACK_CONTEXT_BLOCK;
typedef struct _CM_ACTIVE_NOTIFY_THREAD {
LIST_ENTRY ThreadList;
PETHREAD Thread;
} CM_ACTIVE_NOTIFY_THREAD, *PCM_ACTIVE_NOTIFY_THREAD;
#define CmpLockContext(Context) ExAcquirePushLockExclusive(&((Context)->ThreadListLock))
#define CmpUnlockContext(Context) ExReleasePushLock(&((Context)->ThreadListLock))
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
ULONG CmpCallBackCount = 0;
EX_CALLBACK CmpCallBackVector[CM_MAX_CALLBACKS] = {0};
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif
VOID
CmpInitCallback(VOID);
BOOLEAN
CmpCheckRecursionAndRecordThreadInfo(
PCM_CALLBACK_CONTEXT_BLOCK CallbackBlock,
PCM_ACTIVE_NOTIFY_THREAD ActiveThreadInfo
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmRegisterCallback)
#pragma alloc_text(PAGE,CmUnRegisterCallback)
#pragma alloc_text(PAGE,CmpInitCallback)
#pragma alloc_text(PAGE,CmpCallCallBacks)
#pragma alloc_text(PAGE,CmpCheckRecursionAndRecordThreadInfo)
#endif
NTSTATUS
CmRegisterCallback(__in PEX_CALLBACK_FUNCTION Function,
__in_opt PVOID Context,
__out PLARGE_INTEGER Cookie
)
/*++
Routine Description:
Registers a new callback.
Arguments:
Return Value:
--*/
{
PEX_CALLBACK_ROUTINE_BLOCK RoutineBlock;
ULONG i;
PCM_CALLBACK_CONTEXT_BLOCK CmCallbackContext;
PAGED_CODE();
CmCallbackContext = (PCM_CALLBACK_CONTEXT_BLOCK)ExAllocatePoolWithTag (PagedPool,
sizeof (CM_CALLBACK_CONTEXT_BLOCK),
'bcMC');
if( CmCallbackContext == NULL ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RoutineBlock = ExAllocateCallBack (Function,CmCallbackContext);
if( RoutineBlock == NULL ) {
ExFreePool(CmCallbackContext);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// init the context
//
KeQuerySystemTime(&(CmCallbackContext->Cookie));
*Cookie = CmCallbackContext->Cookie;
InitializeListHead(&(CmCallbackContext->ThreadListHead));
ExInitializePushLock(&(CmCallbackContext->ThreadListLock));
CmCallbackContext->CallerContext = Context;
//
// find a spot where we could add this callback
//
for( i=0;i<CM_MAX_CALLBACKS;i++) {
if( ExCompareExchangeCallBack (&CmpCallBackVector[i],RoutineBlock,NULL) ) {
InterlockedExchangeAdd ((PLONG) &CmpCallBackCount, 1);
return STATUS_SUCCESS;
}
}
//
// no more callbacks
//
ExFreePool(CmCallbackContext);
ExFreeCallBack(RoutineBlock);
return STATUS_INSUFFICIENT_RESOURCES;
}
NTSTATUS
CmUnRegisterCallback(__in LARGE_INTEGER Cookie)
/*++
Routine Description:
Unregisters a callback.
Arguments:
Return Value:
--*/
{
ULONG i;
PCM_CALLBACK_CONTEXT_BLOCK CmCallbackContext;
PEX_CALLBACK_ROUTINE_BLOCK RoutineBlock;
PAGED_CODE();
//
// Search for this cookie
//
for( i=0;i<CM_MAX_CALLBACKS;i++) {
RoutineBlock = ExReferenceCallBackBlock(&(CmpCallBackVector[i]) );
if( RoutineBlock ) {
CmCallbackContext = (PCM_CALLBACK_CONTEXT_BLOCK)ExGetCallBackBlockContext(RoutineBlock);
if( CmCallbackContext && (CmCallbackContext->Cookie.QuadPart == Cookie.QuadPart) ) {
//
// found it
//
if( ExCompareExchangeCallBack (&CmpCallBackVector[i],NULL,RoutineBlock) ) {
InterlockedExchangeAdd ((PLONG) &CmpCallBackCount, -1);
ExDereferenceCallBackBlock (&(CmpCallBackVector[i]),RoutineBlock);
//
// wait for others to release their reference, then tear down the structure
//
ExWaitForCallBacks (RoutineBlock);
ExFreePool(CmCallbackContext);
ExFreeCallBack(RoutineBlock);
return STATUS_SUCCESS;
}
} else {
ExDereferenceCallBackBlock (&(CmpCallBackVector[i]),RoutineBlock);
}
}
}
return STATUS_INVALID_PARAMETER;
}
//
// Cm internals
//
NTSTATUS
CmpCallCallBacks (
IN REG_NOTIFY_CLASS Type,
IN PVOID Argument,
IN BOOLEAN Wind,
IN REG_NOTIFY_CLASS PostType,
IN PVOID Object
)
/*++
Routine Description:
This function calls the callback thats inside a callback structure
Arguments:
Type - Nt call selector
Argument - Caller provided argument to pass on (one of the REG_*_INFORMATION )
Wind - tells if this is a pre or a post callback
PostType - matching post notify class
Object - to be used in case we fail part through.
Return Value:
NTSTATUS - STATUS_SUCCESS or error status returned by the first callback
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
LONG i;
LONG Direction;
PEX_CALLBACK_ROUTINE_BLOCK RoutineBlock;
PCM_CALLBACK_CONTEXT_BLOCK CmCallbackContext;
BOOLEAN InternalUnWind = FALSE;
PAGED_CODE();
if( Wind == TRUE ) {
Direction = 1;
i = 0;
} else {
Direction = -1;
i = CM_MAX_CALLBACKS - 1;
}
for(;(i >= 0) && (i < CM_MAX_CALLBACKS);i += Direction) {
RoutineBlock = ExReferenceCallBackBlock(&(CmpCallBackVector[i]) );
if( RoutineBlock != NULL ) {
//
// we have a safe reference on this block.
//
//
// record thread on a stack struct, so we don't need to allocate pool for it. We unlink
// it from our lists prior to this function exit, so we are on the safe side.
//
CM_ACTIVE_NOTIFY_THREAD ActiveThreadInfo;
//
// get context info
//
CmCallbackContext = (PCM_CALLBACK_CONTEXT_BLOCK)ExGetCallBackBlockContext(RoutineBlock);
ASSERT( CmCallbackContext != NULL );
ActiveThreadInfo.Thread = PsGetCurrentThread();
#if DBG
InitializeListHead(&(ActiveThreadInfo.ThreadList));
#endif //DBG
if( CmpCheckRecursionAndRecordThreadInfo(CmCallbackContext,&ActiveThreadInfo) ) {
if( InternalUnWind == TRUE ) {
//
// this is an internal unwind due to fail part through. need to call posts manually
//
REG_POST_OPERATION_INFORMATION PostInfo;
PostInfo.Object = Object;
PostInfo.Status = Status;
ExGetCallBackBlockRoutine(RoutineBlock)(CmCallbackContext->CallerContext,(PVOID)(ULONG_PTR)PostType,&PostInfo);
// ignore return status.
} else {
//
// regular callback call
//
Status = ExGetCallBackBlockRoutine(RoutineBlock)(CmCallbackContext->CallerContext,(PVOID)(ULONG_PTR)Type,Argument);
if( Wind == FALSE ) {
//
// always ignore post return calls so they all get a chance to run
//
Status = STATUS_SUCCESS;
}
}
//
// now that we're down, remove ourselves from the thread list
//
CmpLockContext(CmCallbackContext);
RemoveEntryList(&(ActiveThreadInfo.ThreadList));
CmpUnlockContext(CmCallbackContext);
} else {
ASSERT( IsListEmpty(&(ActiveThreadInfo.ThreadList)) );
}
ExDereferenceCallBackBlock (&(CmpCallBackVector[i]),RoutineBlock);
if( !NT_SUCCESS(Status) ) {
if( Wind == TRUE ) {
//
// switch direction and start calling the posts
//
Wind = FALSE;
Direction *= -1;
InternalUnWind = TRUE;
} else if( InternalUnWind == FALSE ) {
return Status;
}
//
// else fall through so the unwind completes
//
}
}
}
return Status;
}
VOID
CmpInitCallback(VOID)
/*++
Routine Description:
Init the callback module
Arguments:
Return Value:
--*/
{
ULONG i;
PAGED_CODE();
CmpCallBackCount = 0;
for( i=0;i<CM_MAX_CALLBACKS;i++) {
ExInitializeCallBack (&(CmpCallBackVector[i]));
}
}
BOOLEAN
CmpCheckRecursionAndRecordThreadInfo(
PCM_CALLBACK_CONTEXT_BLOCK CallbackBlock,
PCM_ACTIVE_NOTIFY_THREAD ActiveThreadInfo
)
/*++
Routine Description:
Checks if current thread is already inside the callback (recursion avoidance)
Arguments:
Return Value:
--*/
{
PLIST_ENTRY AnchorAddr;
PCM_ACTIVE_NOTIFY_THREAD CurrentThreadInfo;
PAGED_CODE();
CmpLockContext(CallbackBlock);
//
// walk the ActiveThreadList and see if we are already active
//
AnchorAddr = &(CallbackBlock->ThreadListHead);
CurrentThreadInfo = (PCM_ACTIVE_NOTIFY_THREAD)(CallbackBlock->ThreadListHead.Flink);
while ( CurrentThreadInfo != (PCM_ACTIVE_NOTIFY_THREAD)AnchorAddr ) {
CurrentThreadInfo = CONTAINING_RECORD(
CurrentThreadInfo,
CM_ACTIVE_NOTIFY_THREAD,
ThreadList
);
if( CurrentThreadInfo->Thread == ActiveThreadInfo->Thread ) {
//
// already there!
//
CmpUnlockContext(CallbackBlock);
return FALSE;
}
//
// skip to the next element
//
CurrentThreadInfo = (PCM_ACTIVE_NOTIFY_THREAD)(CurrentThreadInfo->ThreadList.Flink);
}
//
// add this thread
//
InsertTailList(&(CallbackBlock->ThreadListHead), &(ActiveThreadInfo->ThreadList));
CmpUnlockContext(CallbackBlock);
return TRUE;
}

364
base/ntos/config/cmhvlist.c Normal file
View File

@ -0,0 +1,364 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmhvlist.c
Abstract:
Code to maintain registry node that lists where the roots of
hives are and what files they map to.
--*/
#include "cmp.h"
#define HIVE_LIST L"\\registry\\machine\\system\\currentcontrolset\\control\\hivelist"
BOOLEAN
CmpGetHiveName(
PCMHIVE CmHive,
PUNICODE_STRING HiveName
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpAddToHiveFileList)
#pragma alloc_text(PAGE,CmpRemoveFromHiveFileList)
#pragma alloc_text(PAGE,CmpGetHiveName)
#endif
NTSTATUS
CmpAddToHiveFileList(
PCMHIVE CmHive
)
/*++
Routine Description:
Add Hive to list of hives and their files in
\registry\machine\system\currentcontrolset\control\hivelist
Arguments:
HivePath - path to root of hive (e.g. \registry\machine\system)
CmHive - pointer to CM_HIVE structure for hive.
Return Value:
ntstatus
--*/
{
#define NAME_BUFFER_SIZE 512
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
NTSTATUS Status;
PUCHAR Buffer;
ULONG Length;
PWSTR FilePath;
WCHAR UnicodeNull=UNICODE_NULL;
UNICODE_STRING TempName;
UNICODE_STRING HivePath;
//
// create/open the hive list key
//
RtlInitUnicodeString(
&TempName,
HIVE_LIST
);
InitializeObjectAttributes(
&ObjectAttributes,
&TempName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL
);
Status = ZwCreateKey(
&KeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_VOLATILE,
NULL
);
if (!NT_SUCCESS(Status)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpAddToHiveFileList: "));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Create/Open of Hive list failed status = %08lx\n", Status));
return Status;
}
//
// allocate work buffers
//
Buffer = ExAllocatePool(PagedPool, NAME_BUFFER_SIZE + sizeof(WCHAR));
if (Buffer == NULL) {
NtClose(KeyHandle);
return STATUS_NO_MEMORY;
}
//
// compute name of hive
//
if (! CmpGetHiveName(CmHive, &HivePath)) {
NtClose(KeyHandle);
ExFreePool(Buffer);
return STATUS_NO_MEMORY;
}
//
// get name of file
//
if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) {
Status = ZwQueryObject(
CmHive->FileHandles[HFILE_TYPE_PRIMARY],
ObjectNameInformation,
(PVOID)Buffer,
NAME_BUFFER_SIZE,
&Length
);
Length -= sizeof(UNICODE_STRING);
if (!NT_SUCCESS(Status)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpAddToHiveFileList: "));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Query of name2 failed status = %08lx\n", Status));
NtClose(KeyHandle);
ExFreePool(HivePath.Buffer);
ExFreePool(Buffer);
return Status;
}
FilePath = ((POBJECT_NAME_INFORMATION)Buffer)->Name.Buffer;
FilePath[Length/sizeof(WCHAR)] = UNICODE_NULL;
Length+=sizeof(WCHAR);
} else {
FilePath = &UnicodeNull;
Length = sizeof(UnicodeNull);
}
//
// set entry in list
//
Status = ZwSetValueKey(
KeyHandle,
&HivePath,
0,
REG_SZ,
FilePath,
Length
);
if (!NT_SUCCESS(Status)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpAddToHiveFileList: "));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"Set of entry in Hive list failed status = %08lx\n", Status));
}
NtClose(KeyHandle);
ExFreePool(HivePath.Buffer);
ExFreePool(Buffer);
return Status;
}
VOID
CmpRemoveFromHiveFileList(
PUNICODE_STRING EntryName
)
/*++
Routine Description:
Remove hive name from hive file list key
Arguments:
CmHive - pointer to CM_HIVE structure for hive.
Return Value:
ntstatus
--*/
{
NTSTATUS Status;
UNICODE_STRING TempName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
//
// open the hive list key
//
RtlInitUnicodeString(
&TempName,
HIVE_LIST
);
InitializeObjectAttributes(
&ObjectAttributes,
&TempName,
OBJ_CASE_INSENSITIVE,
(HANDLE)NULL,
NULL
);
Status = ZwOpenKey(
&KeyHandle,
KEY_READ | KEY_WRITE,
&ObjectAttributes
);
if (!NT_SUCCESS(Status)) {
return;
}
ZwDeleteValueKey(KeyHandle, EntryName);
NtClose(KeyHandle);
return;
}
BOOLEAN
CmpGetHiveName(
PCMHIVE CmHive,
PUNICODE_STRING HiveName
)
/*++
Routine Description:
Compute full path to a hive.
Arguments:
CmHive - pointer to CmHive structure
HiveName - supplies pointer to unicode string structure that
will be filled in with pointer to name.
CALL IS EXPECTED TO FREE BUFFER
Return Value:
TRUE = it worked, FALSE = it failed (memory)
--*/
{
HCELL_INDEX RootCell;
HCELL_INDEX LinkCell;
PCM_KEY_NODE LinkKey;
PCM_KEY_NODE LinkParent;
SIZE_T size;
SIZE_T rsize;
ULONG KeySize;
ULONG ParentSize;
PWCHAR p;
PCM_KEY_NODE EntryKey;
//
// First find the link cell.
//
RootCell = CmHive->Hive.BaseBlock->RootCell;
EntryKey = (PCM_KEY_NODE)HvGetCell((PHHIVE)CmHive, RootCell);
if( EntryKey == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return FALSE;
}
LinkCell = EntryKey->Parent;
HvReleaseCell((PHHIVE)CmHive, RootCell);
// for master we don't need to count cell usage
ASSERT( ((PHHIVE)CmpMasterHive)->ReleaseCellRoutine == NULL );
//
// Compute the value entry name, which is of the form:
// \registry\<parent of link node name>\<link node name>
//
LinkKey = (PCM_KEY_NODE)HvGetCell((PHHIVE)CmpMasterHive, LinkCell);
if( LinkKey == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return FALSE;
}
LinkParent = (PCM_KEY_NODE)HvGetCell(
(PHHIVE)CmpMasterHive,
LinkKey->Parent
);
if( LinkParent == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return FALSE;
}
rsize = wcslen(L"\\REGISTRY\\");
KeySize = CmpHKeyNameLen(LinkKey);
ParentSize = CmpHKeyNameLen(LinkParent);
size = KeySize + ParentSize +
(rsize * sizeof(WCHAR)) + sizeof(WCHAR);
HiveName->Buffer = ExAllocatePool(PagedPool, size);
if (HiveName->Buffer == NULL) {
return FALSE;
}
#pragma prefast(suppress:12005, "no overflow. size is bounded by max key length (512)")
HiveName->Length = (USHORT)size;
HiveName->MaximumLength = (USHORT)size;
p = HiveName->Buffer;
RtlCopyMemory(
(PVOID)p,
(PVOID)L"\\REGISTRY\\",
rsize * sizeof(WCHAR)
);
p += rsize;
if (LinkParent->Flags & KEY_COMP_NAME) {
CmpCopyCompressedName(p,
ParentSize,
LinkParent->Name,
LinkParent->NameLength);
} else {
RtlCopyMemory(
(PVOID)p,
(PVOID)&(LinkParent->Name[0]),
ParentSize
);
}
p += ParentSize / sizeof(WCHAR);
*p = OBJ_NAME_PATH_SEPARATOR;
p++;
if (LinkKey->Flags & KEY_COMP_NAME) {
CmpCopyCompressedName(p,
KeySize,
LinkKey->Name,
LinkKey->NameLength);
} else {
RtlCopyMemory(
(PVOID)p,
(PVOID)&(LinkKey->Name[0]),
KeySize
);
}
return TRUE;
}

3093
base/ntos/config/cmindex.c Normal file

File diff suppressed because it is too large Load Diff

966
base/ntos/config/cminit.c Normal file
View File

@ -0,0 +1,966 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cminit.c
Abstract:
This module contains init support for the CM level of the
config manager/hive.
--*/
#include "cmp.h"
//
// Prototypes local to this module
//
NTSTATUS
CmpOpenFileWithExtremePrejudice(
OUT PHANDLE Primary,
IN POBJECT_ATTRIBUTES Obja,
IN ULONG IoFlags,
IN ULONG AttributeFlags
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpOpenHiveFiles)
#pragma alloc_text(PAGE,CmpInitializeHive)
#pragma alloc_text(PAGE,CmpDestroyHive)
#pragma alloc_text(PAGE,CmpOpenFileWithExtremePrejudice)
#endif
extern PCMHIVE CmpMasterHive;
extern LIST_ENTRY CmpHiveListHead;
NTSTATUS
CmpOpenHiveFiles(
PUNICODE_STRING BaseName,
PWSTR Extension OPTIONAL,
PHANDLE Primary,
PHANDLE Secondary,
PULONG PrimaryDisposition,
PULONG SecondaryDisposition,
BOOLEAN CreateAllowed,
BOOLEAN MarkAsSystemHive,
BOOLEAN NoBuffering,
OUT OPTIONAL PULONG ClusterSize
)
/*++
Routine Description:
Open/Create Primary, and Log files for Hives.
BaseName is some name like "\winnt\system32\config\system".
Extension is ".alt" or ".log" or NULL.
If extension is NULL skip secondary work.
If extension is .alt or .log, open/create a secondary file
(e.g. "\winnt\system32\config\system.alt")
If extension is .log, open secondary for buffered I/O, else,
open for non-buffered I/O. Primary always uses non-buffered I/O.
If primary is newly created, supersede secondary. If secondary
does not exist, simply create (other code will complain if Log
is needed but does not exist.)
WARNING: If Secondary handle is NULL, you have no log
or alternate!
Arguments:
BaseName - unicode string of base hive file, must have space for
extension if that is used.
Extension - unicode type extension of secondary file, including
the leading "."
Primary - will get handle to primary file
Secondary - will get handle to secondary, or NULL
PrimaryDisposition - STATUS_SUCCESS or STATUS_CREATED, of primary file.
SecondaryDisposition - STATUS_SUCCESS or STATUS_CREATED, of secondary file.
CreateAllowed - if TRUE will create nonexistent primary, if FALSE will
fail if primary does not exist. no effect on log
MarkAsSystemHive - if TRUE will call into file system to mark this
as a critical system hive.
ClusterSize - if not NULL, will compute and return the appropriate
cluster size for the primary file.
Return Value:
status - if status is success, Primary succeeded, check Secondary
value to see if it succeeded.
--*/
{
IO_STATUS_BLOCK IoStatus;
IO_STATUS_BLOCK FsctlIoStatus;
FILE_FS_SIZE_INFORMATION FsSizeInformation;
ULONG Cluster;
ULONG CreateDisposition;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS status;
UNICODE_STRING ExtName;
UNICODE_STRING WorkName;
PVOID WorkBuffer;
USHORT NameSize;
ULONG IoFlags;
ULONG AttributeFlags;
ULONG ShareMode;
ULONG DesiredAccess;
USHORT CompressionState;
HANDLE hEvent;
PKEVENT pEvent;
//
// Allocate an event to use for our overlapped I/O
//
status = CmpCreateEvent(NotificationEvent, &hEvent, &pEvent);
if (!NT_SUCCESS(status)) {
return(status);
}
//
// Allocate a buffer big enough to hold the full name
//
WorkName.Length = 0;
WorkName.MaximumLength = 0;
WorkName.Buffer = NULL;
NameSize = BaseName->Length;
if (ARGUMENT_PRESENT(Extension)) {
NameSize = (USHORT)(NameSize + (wcslen(Extension)+1) * sizeof(WCHAR));
WorkBuffer = ExAllocatePool(PagedPool, NameSize);
if (WorkBuffer == NULL) {
ObDereferenceObject(pEvent);
ZwClose(hEvent);
return STATUS_NO_MEMORY;
}
WorkName.Buffer = WorkBuffer;
WorkName.MaximumLength = NameSize;
RtlAppendStringToString((PSTRING)&WorkName, (PSTRING)BaseName);
} else {
WorkName = *BaseName;
WorkBuffer = NULL;
}
//
// Open/Create the primary
//
InitializeObjectAttributes(
&ObjectAttributes,
&WorkName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
if (CreateAllowed && !CmpShareSystemHives) {
CreateDisposition = FILE_OPEN_IF;
} else {
CreateDisposition = FILE_OPEN;
}
ASSERT_PASSIVE_LEVEL();
AttributeFlags = FILE_OPEN_FOR_BACKUP_INTENT | FILE_NO_COMPRESSION | FILE_RANDOM_ACCESS;
if( NoBuffering == TRUE ) {
AttributeFlags |= FILE_NO_INTERMEDIATE_BUFFERING;
}
//
// Share the file if needed
//
if (CmpMiniNTBoot && CmpShareSystemHives) {
DesiredAccess = FILE_READ_DATA;
ShareMode = FILE_SHARE_READ;
} else {
ShareMode = 0;
DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA;
}
status = ZwCreateFile(
Primary,
DesiredAccess,
&ObjectAttributes,
&IoStatus,
NULL, // alloc size = none
FILE_ATTRIBUTE_NORMAL,
ShareMode, // share nothing
CreateDisposition,
AttributeFlags,
NULL, // eabuffer
0 // ealength
);
if (status == STATUS_ACCESS_DENIED) {
//
// This means some person has put a read-only attribute
// on one of the critical system hive files. Remove it so they
// don't hurt themselves.
//
status = CmpOpenFileWithExtremePrejudice(Primary,
&ObjectAttributes,
AttributeFlags,
FILE_ATTRIBUTE_NORMAL);
}
if (!CmpShareSystemHives && (MarkAsSystemHive) &&
(NT_SUCCESS(status))) {
ASSERT_PASSIVE_LEVEL();
status = ZwFsControlFile(*Primary,
hEvent,
NULL,
NULL,
&FsctlIoStatus,
FSCTL_MARK_AS_SYSTEM_HIVE,
NULL,
0,
NULL,
0);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(pEvent,
Executive,
KernelMode,
FALSE,
NULL);
status = FsctlIoStatus.Status;
}
//
// STATUS_INVALID_DEVICE_REQUEST is OK.
//
if (status == STATUS_INVALID_DEVICE_REQUEST) {
status = STATUS_SUCCESS;
} else if (!NT_SUCCESS(status)) {
ZwClose(*Primary);
}
}
if (!NT_SUCCESS(status)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CMINIT: CmpOpenHiveFile: "));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tPrimary Open/Create failed for:\n"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\t%wZ\n", &WorkName));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tstatus = %08lx\n", status));
if (WorkBuffer != NULL) {
ExFreePool(WorkBuffer);
}
ObDereferenceObject(pEvent);
ZwClose(hEvent);
return status;
}
//
// Make sure the file is uncompressed in order to prevent the filesystem
// from failing our updates due to disk full conditions.
//
// Do not fail to open the file if this fails, we don't want to prevent
// people from booting just because their disk is full. Although they
// will not be able to update their registry, they will at lease be
// able to delete some files.
//
CompressionState = 0;
ASSERT_PASSIVE_LEVEL();
status = ZwFsControlFile(*Primary,
hEvent,
NULL,
NULL,
&FsctlIoStatus,
FSCTL_SET_COMPRESSION,
&CompressionState,
sizeof(CompressionState),
NULL,
0);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(pEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
*PrimaryDisposition = (ULONG) IoStatus.Information;
if( *PrimaryDisposition != FILE_CREATED ) {
//
// 0-length file case
//
FILE_STANDARD_INFORMATION FileInformation;
NTSTATUS status2;
status2 = ZwQueryInformationFile(*Primary,
&IoStatus,
(PVOID)&FileInformation,
sizeof( FileInformation ),
FileStandardInformation
);
if (NT_SUCCESS( status2 )) {
if(FileInformation.EndOfFile.QuadPart == 0) {
//
// treat it as a non-existent one.
//
*PrimaryDisposition = FILE_CREATED;
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Primary file is zero-length => treat it as non-existent\n"));
}
}
}
if (ARGUMENT_PRESENT(ClusterSize)) {
ASSERT_PASSIVE_LEVEL();
status = ZwQueryVolumeInformationFile(*Primary,
&IoStatus,
&FsSizeInformation,
sizeof(FILE_FS_SIZE_INFORMATION),
FileFsSizeInformation);
if (!NT_SUCCESS(status)) {
ObDereferenceObject(pEvent);
ZwClose(hEvent);
return(status);
}
if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpOpenHiveFiles: sectorsize %lx > HBLOCK_SIZE\n"));
ObDereferenceObject(pEvent);
ZwClose(hEvent);
return(STATUS_CANNOT_LOAD_REGISTRY_FILE);
}
Cluster = FsSizeInformation.BytesPerSector / HSECTOR_SIZE;
*ClusterSize = (Cluster < 1) ? 1 : Cluster;
}
if ( ! ARGUMENT_PRESENT(Extension)) {
if (WorkBuffer != NULL) {
ExFreePool(WorkBuffer);
}
ObDereferenceObject(pEvent);
ZwClose(hEvent);
return STATUS_SUCCESS;
}
//
// Open/Create the secondary
//
CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF;
if (*PrimaryDisposition == FILE_CREATED) {
CreateDisposition = FILE_SUPERSEDE;
}
RtlInitUnicodeString(&ExtName,Extension);
status = RtlAppendStringToString((PSTRING)&WorkName, (PSTRING)&ExtName);
InitializeObjectAttributes(&ObjectAttributes,
&WorkName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
//
// non-cached log files (or alternates)
//
IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING;
if (_wcsnicmp(Extension, L".log", 4) != 0) {
AttributeFlags = FILE_ATTRIBUTE_NORMAL;
} else {
AttributeFlags = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN;
}
ASSERT_PASSIVE_LEVEL();
status = ZwCreateFile(
Secondary,
DesiredAccess,
&ObjectAttributes,
&IoStatus,
NULL, // alloc size = none
AttributeFlags,
ShareMode,
CreateDisposition,
IoFlags,
NULL, // eabuffer
0 // ealength
);
if (status == STATUS_ACCESS_DENIED) {
//
// This means some person has put a read-only attribute
// on one of the critical system hive files. Remove it so they
// don't hurt themselves.
//
status = CmpOpenFileWithExtremePrejudice(Secondary,
&ObjectAttributes,
IoFlags,
AttributeFlags);
}
if (!CmpShareSystemHives && (MarkAsSystemHive) &&
(NT_SUCCESS(status))) {
ASSERT_PASSIVE_LEVEL();
status = ZwFsControlFile(*Secondary,
hEvent,
NULL,
NULL,
&FsctlIoStatus,
FSCTL_MARK_AS_SYSTEM_HIVE,
NULL,
0,
NULL,
0);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(pEvent,
Executive,
KernelMode,
FALSE,
NULL);
status = FsctlIoStatus.Status;
}
//
// STATUS_INVALID_DEVICE_REQUEST is OK.
//
if (status == STATUS_INVALID_DEVICE_REQUEST) {
status = STATUS_SUCCESS;
} else if (!NT_SUCCESS(status)) {
ZwClose(*Secondary);
}
}
if (!NT_SUCCESS(status)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CMINIT: CmpOpenHiveFile: "));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tSecondary Open/Create failed for:\n"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\t%wZ\n", &WorkName));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tstatus = %08lx\n", status));
*Secondary = NULL;
} else {
*SecondaryDisposition = (ULONG) IoStatus.Information;
//
// Make sure the file is uncompressed in order to prevent the filesystem
// from failing our updates due to disk full conditions.
//
// Do not fail to open the file if this fails, we don't want to prevent
// people from booting just because their disk is full. Although they
// will not be able to update their registry, they will at least be
// able to delete some files.
//
CompressionState = 0;
ASSERT_PASSIVE_LEVEL();
status = ZwFsControlFile(*Secondary,
hEvent,
NULL,
NULL,
&FsctlIoStatus,
FSCTL_SET_COMPRESSION,
&CompressionState,
sizeof(CompressionState),
NULL,
0);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(pEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
}
if (WorkBuffer != NULL) {
ExFreePool(WorkBuffer);
}
ObDereferenceObject(pEvent);
ZwClose(hEvent);
return STATUS_SUCCESS;
}
NTSTATUS
CmpInitializeHive(
PCMHIVE *CmHive,
ULONG OperationType,
ULONG HiveFlags,
ULONG FileType,
PVOID HiveData OPTIONAL,
HANDLE Primary,
HANDLE Log,
HANDLE External,
PUNICODE_STRING FileName OPTIONAL,
ULONG CheckFlags
)
/*++
Routine Description:
Initialize a hive.
Arguments:
CmHive - pointer to a variable to receive a pointer to the CmHive structure
OperationType - specifies whether to create a new hive from scratch,
from a memory image, or by reading a file from disk.
[HINIT_CREATE | HINIT_MEMORY | HINIT_FILE | HINIT_MAPFILE]
HiveFlags - HIVE_VOLATILE - Entire hive is to be volatile, regardless
of the types of cells allocated
HIVE_NO_LAZY_FLUSH - Data in this hive is never written
to disk except by an explicit FlushKey
FileType - HFILE_TYPE_*, HFILE_TYPE_LOG set up for logging support
HiveData - if present, supplies a pointer to an in memory image of
from which to init the hive. Only useful when OperationType
is set to HINIT_MEMORY.
Primary - File handle for primary hive file (e.g. SYSTEM)
Log - File handle for log hive file (e.g. SOFTWARE.LOG)
External - File handle for primary hive file (e.g. BACKUP.REG)
FileName - some path like "...\system32\config\system", which will
be written into the base block as an aid to debugging.
may be NULL.
CheckFlags - Flags to be passed to CmCheckRegistry
usually this is CM_CHECK_REGISTRY_CHECK_CLEAN, except for the system hive
where CM_CHECK_REGISTRY_FORCE_CLEAN is passed
Return Value:
NTSTATUS
--*/
{
FILE_FS_SIZE_INFORMATION FsSizeInformation;
IO_STATUS_BLOCK IoStatusBlock;
ULONG Cluster;
NTSTATUS Status;
PCMHIVE cmhive2;
ULONG rc;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmpInitializeHive:\t\n"));
//
// Reject illegal parms
//
if ( (External && (Primary || Log)) ||
(Log && !Primary) ||
(!CmpShareSystemHives && (HiveFlags & HIVE_VOLATILE) && (Primary || External || Log)) ||
((OperationType == HINIT_MEMORY) && (!ARGUMENT_PRESENT(HiveData))) ||
(Log && (FileType != HFILE_TYPE_LOG))
)
{
return (STATUS_INVALID_PARAMETER);
}
//
// compute control
//
if (Primary) {
ASSERT_PASSIVE_LEVEL();
Status = ZwQueryVolumeInformationFile(
Primary,
&IoStatusBlock,
&FsSizeInformation,
sizeof(FILE_FS_SIZE_INFORMATION),
FileFsSizeInformation
);
if (!NT_SUCCESS(Status)) {
return (Status);
}
if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) {
return (STATUS_REGISTRY_IO_FAILED);
}
Cluster = FsSizeInformation.BytesPerSector / HSECTOR_SIZE;
Cluster = (Cluster < 1) ? 1 : Cluster;
} else {
Cluster = 1;
}
cmhive2 = CmpAllocate(sizeof(CMHIVE), FALSE,CM_FIND_LEAK_TAG10);
if (cmhive2 == NULL) {
return (STATUS_INSUFFICIENT_RESOURCES);
}
cmhive2->UnloadEvent = NULL;
cmhive2->RootKcb = NULL;
cmhive2->Frozen = FALSE;
cmhive2->UnloadWorkItem = NULL;
cmhive2->GrowOnlyMode = FALSE;
cmhive2->GrowOffset = 0;
#if DBG
cmhive2->HiveIsLoading = TRUE;
#endif
cmhive2->CreatorOwner = NULL;
InitializeListHead(&(cmhive2->KcbConvertListHead));
InitializeListHead(&(cmhive2->KnodeConvertListHead));
cmhive2->CellRemapArray = NULL;
//
// Allocate the mutex from NonPagedPool so it will not be swapped to the disk
//
cmhive2->ViewLock = (PKGUARDED_MUTEX)ExAllocatePoolWithTag(NonPagedPool, sizeof(KGUARDED_MUTEX), CM_POOL_TAG );
if( cmhive2->ViewLock == NULL ) {
CmpFree(cmhive2, sizeof(CMHIVE));
return (STATUS_INSUFFICIENT_RESOURCES);
}
#if DBG
cmhive2->FlusherLock = (PERESOURCE)ExAllocatePoolWithTag(NonPagedPool, sizeof(ERESOURCE), CM_POOL_TAG );
if( cmhive2->FlusherLock == NULL ) {
CmpFreeMutex(cmhive2->ViewLock);
CmpFree(cmhive2, sizeof(CMHIVE));
return (STATUS_INSUFFICIENT_RESOURCES);
}
#endif
// need to do this consistently!!!
cmhive2->FileObject = NULL;
cmhive2->FileFullPath.Buffer = NULL;
cmhive2->FileFullPath.Length = 0;
cmhive2->FileFullPath.MaximumLength = 0;
cmhive2->FileUserName.Buffer = NULL;
cmhive2->FileUserName.Length = 0;
cmhive2->FileUserName.MaximumLength = 0;
//
// Initialize the Cm hive control block
//
//
ASSERT((HFILE_TYPE_EXTERNAL+1) == HFILE_TYPE_MAX);
cmhive2->FileHandles[HFILE_TYPE_PRIMARY] = Primary;
cmhive2->FileHandles[HFILE_TYPE_LOG] = Log;
cmhive2->FileHandles[HFILE_TYPE_EXTERNAL] = External;
cmhive2->NotifyList.Flink = NULL;
cmhive2->NotifyList.Blink = NULL;
ExInitializePushLock(&(cmhive2->HiveLock));
#if DBG
cmhive2->HiveLockOwner = NULL;
KeInitializeGuardedMutex(cmhive2->ViewLock);
cmhive2->ViewLockOwner = NULL;
ExInitializePushLock(&(cmhive2->WriterLock));
cmhive2->WriterLockOwner = NULL;
ExInitializeResourceLite(cmhive2->FlusherLock);
ExInitializePushLock(&(cmhive2->SecurityLock));
cmhive2->HiveSecurityLockOwner = NULL;
#else
KeInitializeGuardedMutex(cmhive2->ViewLock);
ExInitializePushLock(&(cmhive2->WriterLock));
ExInitializePushLock(&(cmhive2->FlusherLock));
ExInitializePushLock(&(cmhive2->SecurityLock));
#endif
CmpInitHiveViewList(cmhive2);
cmhive2->Flags = 0;
InitializeListHead(&(cmhive2->TrustClassEntry));
cmhive2->FlushCount = 0;
//
// Initialize the view list
//
#if DBG
if( FileName ) {
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Initializing HiveViewList for hive (%p) (%.*S) \n\n",cmhive2,FileName->Length / sizeof(WCHAR),FileName->Buffer));
}
#endif
//
// Initialize the security cache
//
CmpInitSecurityCache(cmhive2);
//
// Initialize the Hv hive control block
//
Status = HvInitializeHive(
&(cmhive2->Hive),
OperationType,
HiveFlags,
FileType,
HiveData,
CmpAllocate,
CmpFree,
CmpFileSetSize,
CmpFileWrite,
CmpFileRead,
CmpFileFlush,
Cluster,
FileName
);
if (!NT_SUCCESS(Status)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeHive: "));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"HvInitializeHive failed, Status = %08lx\n", Status));
if( !(cmhive2->Hive.HiveFlags & HIVE_HAS_BEEN_FREED) ) {
HvpFreeHiveFreeDisplay((PHHIVE)cmhive2);
HvpCleanMap((PHHIVE)cmhive2);
}
CmpFreeMutex(cmhive2->ViewLock);
#if DBG
CmpFreeResource(cmhive2->FlusherLock);
#endif
CmpDestroyHiveViewList(cmhive2);
CmpDestroySecurityCache (cmhive2);
CmpDropFileObjectForHive(cmhive2);
CmpUnJoinClassOfTrust(cmhive2);
CmpCheckForOrphanedKcbs((PHHIVE)cmhive2);
CmpFree(cmhive2, sizeof(CMHIVE));
return (Status);
}
if ( (OperationType == HINIT_FILE) ||
(OperationType == HINIT_MAPFILE) ||
(OperationType == HINIT_MEMORY) ||
(OperationType == HINIT_MEMORY_INPLACE))
{
rc = CmCheckRegistry(cmhive2, CheckFlags);
if (rc != 0) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeHive: "));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmCheckRegistry failed, rc = %08lx\n",rc));
//
// we have dirtied some cells (by clearing the volatile information)
// we need first to unpin all the views
CmpDestroyHiveViewList(cmhive2);
CmpDestroySecurityCache(cmhive2);
CmpDropFileObjectForHive(cmhive2);
CmpUnJoinClassOfTrust(cmhive2);
CmpCheckForOrphanedKcbs((PHHIVE)cmhive2);
HvFreeHive((PHHIVE)cmhive2);
CmpFreeMutex(cmhive2->ViewLock);
#if DBG
CmpFreeResource(cmhive2->FlusherLock);
#endif
CmpFree(cmhive2, sizeof(CMHIVE));
return(STATUS_REGISTRY_CORRUPT);
}
}
#if DBG
cmhive2->HiveIsLoading = FALSE;
#endif
if( !(CheckFlags&CM_DONT_ADD_TO_HIVE_LIST) ) {
CmpLockHiveListExclusive(); // at the end so system hive is first during the lazy flush iteration
InsertTailList(&CmpHiveListHead, &(cmhive2->HiveList));
CmpUnlockHiveList();
}
*CmHive = cmhive2;
return (STATUS_SUCCESS);
}
LOGICAL
CmpDestroyHive(
IN PHHIVE Hive,
IN HCELL_INDEX Cell
)
/*++
Routine Description:
This routine tears down a cmhive.
Arguments:
Hive - Supplies a pointer to the hive to be freed.
Cell - Supplies index of the hive's root cell.
Return Value:
TRUE if successful
FALSE if some failure occurred
--*/
{
PCELL_DATA CellData;
HCELL_INDEX LinkCell;
NTSTATUS Status;
//
// First find the link cell.
//
CellData = HvGetCell(Hive, Cell);
if( CellData == NULL ) {
//
// we couldn't map the bin containing this cell
//
return FALSE;
}
LinkCell = CellData->u.KeyNode.Parent;
HvReleaseCell(Hive, Cell);
//
// Now delete the link cell.
//
ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
CmpLockHiveFlusherExclusive(CmpMasterHive);
Status = CmpFreeKeyByCell((PHHIVE)CmpMasterHive, LinkCell, TRUE);
CmpUnlockHiveFlusher(CmpMasterHive);
if (NT_SUCCESS(Status)) {
//
// Take the hive out of the hive list
//
CmpLockHiveListExclusive();
CmpRemoveEntryList(&( ((PCMHIVE)Hive)->HiveList));
CmpUnlockHiveList();
return(TRUE);
} else {
return(FALSE);
}
}
NTSTATUS
CmpOpenFileWithExtremePrejudice(
OUT PHANDLE Primary,
IN POBJECT_ATTRIBUTES Obja,
IN ULONG IoFlags,
IN ULONG AttributeFlags
)
/*++
Routine Description:
This routine opens a hive file that some person has put a
read-only attribute on. It is used to prevent people from hurting
themselves by making the critical system hive files read-only.
Arguments:
Primary - Returns handle to file
Obja - Supplies Object Attributes of file.
IoFlags - Supplies flags to pass to ZwCreateFile
Return Value:
NTSTATUS
--*/
{
NTSTATUS Status;
HANDLE Handle;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION FileInfo;
RtlZeroMemory(&FileInfo, sizeof(FileInfo));
//
// Get the current file attributes
//
ASSERT_PASSIVE_LEVEL();
Status = ZwQueryAttributesFile(Obja, &FileInfo);
if (!NT_SUCCESS(Status)) {
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"ZwQueryAttributesFile failed with IO status %lx\n",Status));
return(Status);
}
//
// Clear the readonly bit.
//
FileInfo.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
//
// Open the file
//
Status = ZwOpenFile(&Handle,
FILE_WRITE_ATTRIBUTES,
Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS(Status)) {
return(Status);
}
//
// Set the new attributes
//
Status = ZwSetInformationFile(Handle,
&IoStatusBlock,
&FileInfo,
sizeof(FileInfo),
FileBasicInformation);
ZwClose(Handle);
if (NT_SUCCESS(Status)) {
//
// Reopen the file with the access that we really need.
//
Status = ZwCreateFile(Primary,
FILE_READ_DATA | FILE_WRITE_DATA,
Obja,
&IoStatusBlock,
NULL,
AttributeFlags,
0,
FILE_OPEN,
IoFlags,
NULL,
0);
}
#if DBG
else {
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"ZwSetInformationFile failed with IO status %lx\n",Status));
}
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpOpenFileWithExtremePrejudice returns with IO status %lx\n",Status));
#endif
return(Status);
}

2026
base/ntos/config/cmmapvw.c Normal file

File diff suppressed because it is too large Load Diff

397
base/ntos/config/cmname.c Normal file
View File

@ -0,0 +1,397 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmname.c
Abstract:
Provides routines for handling name comparisons and converting to/from the registry
compressed name format.
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpNameSize)
#pragma alloc_text(PAGE,CmpCopyName)
#pragma alloc_text(PAGE,CmpCompressedNameSize)
#pragma alloc_text(PAGE,CmpCopyCompressedName)
#pragma alloc_text(PAGE,CmpCompareCompressedName)
#pragma alloc_text(PAGE,CmpCompareUnicodeString)
#pragma alloc_text(PAGE,CmpCompareTwoCompressedNames)
#endif
USHORT
CmpNameSize(
IN PHHIVE Hive,
IN PUNICODE_STRING Name
)
/*++
Routine Description:
Determines the space needed to store a given string in the registry. May apply
any relevant compression to compute the length, but the compression used is
guaranteed to be the same as CmpCopyName.
Arguments:
Hive - supplies the hive control structure (for version checking)
Name - Supplies the unicode string to be copied into the registry.
Return Value:
The number of bytes of storage required to store this name.
--*/
{
ULONG i;
if (Hive->Version == 1) {
return(Name->Length);
}
for (i=0;i<Name->Length/sizeof(WCHAR);i++) {
if ((USHORT)Name->Buffer[i] > (UCHAR)-1) {
return(Name->Length);
}
}
return(Name->Length / sizeof(WCHAR));
}
USHORT
CmpCopyName(
IN PHHIVE Hive,
IN PWCHAR Destination,
IN PUNICODE_STRING Source
)
/*++
Routine Description:
Copies the given unicode name into the registry, applying any relevant compression
at the same time.
Arguments:
Hive - supplies the hive control structure (For version checking)
Destination - Supplies the destination of the given string.
Source - Supplies the unicode string to copy into the registry.
Return Value:
Number of bytes of storage copied
--*/
{
ULONG i;
if (Hive->Version==1) {
RtlCopyMemory(Destination,Source->Buffer, Source->Length);
return(Source->Length);
}
for (i=0;i<Source->Length/sizeof(WCHAR);i++) {
if ((USHORT)Source->Buffer[i] > (UCHAR)-1) {
RtlCopyMemory(Destination,Source->Buffer, Source->Length);
return(Source->Length);
}
((PUCHAR)Destination)[i] = (UCHAR)(Source->Buffer[i]);
}
return(Source->Length / sizeof(WCHAR));
}
USHORT
CmpCompressedNameSize(
IN PWCHAR Name,
IN ULONG Length
)
/*++
Routine Description:
Computes the length of the unicode string that the given compressed name
expands into.
Arguments:
Name - Supplies the compressed name.
Length - Supplies the length in bytes of the compressed name
Return Value:
The number of bytes of storage required to hold the Unicode expanded name.
--*/
{
UNREFERENCED_PARAMETER (Name);
return((USHORT)Length*sizeof(WCHAR));
}
VOID
CmpCopyCompressedName(
IN PWCHAR Destination,
IN ULONG DestinationLength,
IN PWCHAR Source,
IN ULONG SourceLength
)
/*++
Routine Description:
Copies a compressed name from the registry and expands it to Unicode.
Arguments:
Destination - Supplies the destination Unicode buffer
DestinationLength - Supplies the max length of the destination buffer in bytes
Source - Supplies the compressed string.
SourceLength - Supplies the length of the compressed string in bytes
Return Value:
None.
--*/
{
ULONG i;
ULONG Chars;
Chars = (DestinationLength/sizeof(WCHAR) < SourceLength)
? DestinationLength/sizeof(WCHAR)
: SourceLength;
for (i=0;i<Chars;i++) {
Destination[i] = (WCHAR)(((PUCHAR)Source)[i]);
}
}
LONG
CmpCompareCompressedName(
IN PUNICODE_STRING SearchName,
IN PWCHAR CompressedName,
IN ULONG NameLength,
IN ULONG CompareFlags
)
/*++
Routine Description:
Compares a compressed registry string to a Unicode string. Does a case-insensitive
comparison.
Arguments:
SearchName - Supplies the Unicode string to be compared
CompressedName - Supplies the compressed string to be compared
NameLength - Supplies the length of the compressed string
Return Value:
0 = SearchName == CompressedName (of Cell)
< 0 = SearchName < CompressedName
> 0 = SearchName > CompressedName
--*/
{
WCHAR *s1;
UCHAR *s2;
USHORT n1, n2;
WCHAR c1;
WCHAR c2;
LONG cDiff;
s1 = SearchName->Buffer;
s2 = (UCHAR *)CompressedName;
n1 = (USHORT )(SearchName->Length / sizeof(WCHAR));
n2 = (USHORT )(NameLength);
while (n1 && n2) {
c1 = *s1++;
c2 = (WCHAR)(*s2++);
//
// there is a 2/3 chance they match without doing the uppercase comparison.
//
if( c1 != c2 ) {
c1 = (CompareFlags&CMP_SOURCE_UP)?c1:CmUpcaseUnicodeChar(c1);
c2 = (CompareFlags&CMP_DEST_UP)?c2:CmUpcaseUnicodeChar(c2);
if ((cDiff = ((LONG)c1 - (LONG)c2)) != 0) {
return( cDiff );
}
}
n1--;
n2--;
}
return( n1 - n2 );
}
LONG
CmpCompareUnicodeString(
IN PUNICODE_STRING SourceName,
IN PUNICODE_STRING DestName,
IN ULONG CompareFlags
)
/*++
Routine Description:
Compares 2 unicode strings; Case insensitive comparison.
Uses flags to avoid UpCasing strings again.
Arguments:
SourceName - Supplies the Unicode string to be compared
DestName - Supplies the compressed string to be compared
CompareFlags - Supplies the flags to control comparison (see cmp.h)
Return Value:
0 = SearchName == CompressedName (of Cell)
< 0 = SearchName < CompressedName
> 0 = SearchName > CompressedName
--*/
{
WCHAR *s1, *s2;
USHORT n1, n2;
WCHAR c1, c2;
LONG cDiff;
s1 = SourceName->Buffer;
s2 = DestName->Buffer;
n1 = (USHORT )(SourceName->Length / sizeof(WCHAR));
n2 = (USHORT )(DestName->Length / sizeof(WCHAR));
while (n1 && n2) {
c1 = *s1++;
c2 = *s2++;
//
// there is a 2/3 chance of being the same case
//
if( c1 != c2 ){
c1 = (CompareFlags&CMP_SOURCE_UP)?c1:CmUpcaseUnicodeChar(c1);
c2 = (CompareFlags&CMP_DEST_UP)?c2:CmUpcaseUnicodeChar(c2);
if ((cDiff = ((LONG)c1 - (LONG)c2)) != 0) {
return( cDiff );
}
}
n1--;
n2--;
}
return( n1 - n2 );
}
LONG
CmpCompareTwoCompressedNames(
IN PWCHAR CompressedName1,
IN ULONG NameLength1,
IN PWCHAR CompressedName2,
IN ULONG NameLength2
)
/*++
Routine Description:
Compares 2 compressed registry strings. Does a case-insensitive
comparison.
Arguments:
CompressedName1 - Supplies the compressed string to be compared
NameLength2 - Supplies the length of the compressed string
CompressedName1 - Supplies the compressed string to be compared
NameLength2 - Supplies the length of the compressed string
Return Value:
0 = CompressedName1 == CompressedName2 (of Cell)
< 0 = CompressedName1 < CompressedName2
> 0 = CompressedName1 > CompressedName2
--*/
{
UCHAR *s1;
UCHAR *s2;
USHORT n1, n2;
WCHAR c1;
WCHAR c2;
LONG cDiff;
s1 = (UCHAR *)CompressedName1;
s2 = (UCHAR *)CompressedName2;
n1 = (USHORT )(NameLength1);
n2 = (USHORT )(NameLength2);
while (n1 && n2) {
c1 = (WCHAR)(*s1++);
c2 = (WCHAR)(*s2++);
//
// there is a 2/3 chance they match without doing the upercpase comparison.
//
if( c1 != c2 ) {
c1 = CmUpcaseUnicodeChar(c1);
c2 = CmUpcaseUnicodeChar(c2);
if ((cDiff = ((LONG)c1 - (LONG)c2)) != 0) {
return( cDiff );
}
}
n1--;
n2--;
}
return( n1 - n2 );
}

1933
base/ntos/config/cmnotify.c Normal file

File diff suppressed because it is too large Load Diff

2988
base/ntos/config/cmp.h Normal file

File diff suppressed because it is too large Load Diff

3449
base/ntos/config/cmparse.c Normal file

File diff suppressed because it is too large Load Diff

761
base/ntos/config/cmparse2.c Normal file
View File

@ -0,0 +1,761 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmparse2.c
Abstract:
This module contains parse routines for the configuration manager, particularly
the registry.
--*/
#include "cmp.h"
BOOLEAN
CmpOKToFollowLink( IN PCMHIVE OrigHive,
IN PCMHIVE DestHive
);
ULONG
CmpUnLockKcbArray(IN PULONG LockedKcbs,
IN ULONG Exempt);
VOID
CmpReLockKcbArray(IN PULONG LockedKcbs,
IN BOOLEAN LockExclusive);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpDoCreate)
#pragma alloc_text(PAGE,CmpDoCreateChild)
#endif
extern PCM_KEY_CONTROL_BLOCK CmpKeyControlBlockRoot;
NTSTATUS
CmpDoCreate(
IN PHHIVE Hive,
IN HCELL_INDEX Cell,
IN PACCESS_STATE AccessState,
IN PUNICODE_STRING Name,
IN KPROCESSOR_MODE AccessMode,
IN PCM_PARSE_CONTEXT Context,
IN PCM_KEY_CONTROL_BLOCK ParentKcb,
IN PCMHIVE OriginatingHive OPTIONAL,
OUT PVOID *Object
)
/*++
Routine Description:
Performs the first step in the creation of a registry key. This
routine checks to make sure the caller has the proper access to
create a key here, and allocates space for the child in the parent
cell. It then calls CmpDoCreateChild to initialize the key and
create the key object.
This two phase creation allows us to share the child creation code
with the creation of link nodes.
Arguments:
Hive - supplies a pointer to the hive control structure for the hive
Cell - supplies index of node to create child under.
AccessState - Running security access state information for operation.
Name - supplies pointer to a UNICODE string which is the name of
the child to be created.
AccessMode - Access mode of the original caller.
Context - pointer to CM_PARSE_CONTEXT structure passed through
the object manager
BaseName - Name of object create is relative to
KeyName - Relative name (to BaseName)
Object - The address of a variable to receive the created key object, if
any.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PCELL_DATA pdata;
HCELL_INDEX KeyCell;
ULONG ParentType;
ACCESS_MASK AdditionalAccess;
BOOLEAN CreateAccess;
PCM_KEY_BODY KeyBody;
PSECURITY_DESCRIPTOR SecurityDescriptor;
LARGE_INTEGER TimeStamp;
BOOLEAN BackupRestore;
KPROCESSOR_MODE mode;
PCM_KEY_NODE ParentNode;
#if DBG
ULONG ChildConvKey;
#endif
HV_TRACK_CELL_REF CellRef = {0};
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpDoCreate:\n"));
BackupRestore = FALSE;
if (ARGUMENT_PRESENT(Context)) {
if (Context->CreateOptions & REG_OPTION_BACKUP_RESTORE) {
//
// allow backup operators to create new keys
//
BackupRestore = TRUE;
}
//
// Operation is a create, so set Disposition
//
Context->Disposition = REG_CREATED_NEW_KEY;
}
#if DBG
ChildConvKey = ParentKcb->ConvKey;
if (Name->Length) {
ULONG Cnt;
WCHAR *Cp;
Cp = Name->Buffer;
for (Cnt=0; Cnt<Name->Length; Cnt += sizeof(WCHAR)) {
//
// UNICODE_NULL is a valid char !!!
//
if (*Cp != OBJ_NAME_PATH_SEPARATOR) {
//(*Cp != UNICODE_NULL)) {
ChildConvKey = 37 * ChildConvKey + (ULONG)CmUpcaseUnicodeChar(*Cp);
}
++Cp;
}
}
ASSERT_HASH_ENTRY_LOCKED_EXCLUSIVE(ChildConvKey);
ASSERT_KCB_LOCKED_EXCLUSIVE(ParentKcb);
#endif
CmpLockHiveFlusherShared((PCMHIVE)Hive);
if( CmIsKcbReadOnly(ParentKcb) ) {
//
// key is protected
//
status = STATUS_ACCESS_DENIED;
goto Exit;
}
//
// make sure nothing changed in between:
// 1. ParentKcb is still valid
// 2. Child was not already added by somebody else
//
if( ParentKcb->Delete ) {
//
// key was deleted in between
//
status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Exit;
}
//
// KeQuerySystemTime doesn't give us a fine resolution
// so we have to search if the child has not been created already
//
ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
if( ParentNode == NULL ) {
//
// we couldn't map the bin containing this cell
//
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
if( !HvTrackCellRef(&CellRef,Hive,Cell) ) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
if( CmpFindSubKeyByName(Hive,ParentNode,Name) != HCELL_NIL ) {
//
// key was changed in between; possibly this key was already created ==> reparse
//
status = STATUS_REPARSE;
goto Exit;
}
if(!CmpOKToFollowLink(OriginatingHive,(PCMHIVE)Hive) ) {
//
// about to cross class of trust boundary
//
status = STATUS_ACCESS_DENIED;
goto Exit;
}
ASSERT( Cell == ParentKcb->KeyCell );
ASSERT( ParentKcb->CachedSecurity != NULL );
SecurityDescriptor = &(ParentKcb->CachedSecurity->Descriptor);
ParentType = HvGetCellType(Cell);
if ( (ParentType == Volatile) &&
((Context->CreateOptions & REG_OPTION_VOLATILE) == 0) )
{
//
// Trying to create stable child under volatile parent, report error
//
status = STATUS_CHILD_MUST_BE_VOLATILE;
goto Exit;
}
if (ParentKcb->Flags & KEY_SYM_LINK) {
//
// Disallow attempts to create anything under a symbolic link
//
status = STATUS_ACCESS_DENIED;
goto Exit;
}
AdditionalAccess = (Context->CreateOptions & REG_OPTION_CREATE_LINK) ? KEY_CREATE_LINK : 0;
if( BackupRestore == TRUE ) {
//
// this is a create to support a backup or restore
// operation, do the special case work
//
AccessState->RemainingDesiredAccess = 0;
AccessState->PreviouslyGrantedAccess = 0;
mode = KeGetPreviousMode();
if (SeSinglePrivilegeCheck(SeBackupPrivilege, mode)) {
AccessState->PreviouslyGrantedAccess |=
KEY_READ | ACCESS_SYSTEM_SECURITY;
}
if (SeSinglePrivilegeCheck(SeRestorePrivilege, mode)) {
AccessState->PreviouslyGrantedAccess |=
KEY_WRITE | ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER;
}
if (AccessState->PreviouslyGrantedAccess == 0) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpDoCreate for backup restore: access denied\n"));
status = STATUS_ACCESS_DENIED;
//
// this is not a backup-restore operator; deny the create
//
CreateAccess = FALSE;
} else {
//
// allow backup operators to create new keys
//
status = STATUS_SUCCESS;
CreateAccess = TRUE;
}
} else {
//
// The FullName is not used in the routine CmpCheckCreateAccess,
//
CreateAccess = CmpCheckCreateAccess(NULL,
SecurityDescriptor,
AccessState,
AccessMode,
AdditionalAccess,
&status);
}
if (CreateAccess) {
//
// Security check passed, so we can go ahead and create
// the sub-key.
//
if ( !HvMarkCellDirty(Hive, Cell,FALSE) ) {
status = STATUS_NO_LOG_SPACE;
goto Exit;
}
//
// Create and initialize the new sub-key
//
status = CmpDoCreateChild( Hive,
Cell,
SecurityDescriptor,
AccessState,
Name,
AccessMode,
Context,
ParentKcb,
0,
&KeyCell,
Object );
if (NT_SUCCESS(status)) {
PCM_KEY_NODE KeyNode;
KeyBody = (PCM_KEY_BODY)(*Object);
//
// Child successfully created, add to parent's list.
//
if (! CmpAddSubKey(Hive, Cell, KeyCell)) {
//
// Unable to add child, so free it
//
CmpFreeKeyByCell(Hive, KeyCell, FALSE);
//
// release the object created inside CmpDoCreateChild make sure kcb gets kicked out of cache
//
KeyBody->KeyControlBlock->Delete = TRUE;
CmpRemoveKeyControlBlock(KeyBody->KeyControlBlock);
ObDereferenceObjectDeferDelete(*Object);
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
if( KeyNode == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as we successfully marked the cell as dirty
//
ASSERT( FALSE );
CmpFreeKeyByCell(Hive, KeyCell, TRUE);
KeyBody->KeyControlBlock->Delete = TRUE;
CmpRemoveKeyControlBlock(KeyBody->KeyControlBlock);
ObDereferenceObjectDeferDelete(*Object);
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
if( !HvTrackCellRef(&CellRef,Hive,Cell) ) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
CmpCleanUpSubKeyInfo (KeyBody->KeyControlBlock->ParentKcb);
//
// Update max keyname and class name length fields
//
//some sanity asserts first
ASSERT( KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell );
ASSERT( KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive );
ASSERT( KeyBody->KeyControlBlock->ParentKcb == ParentKcb );
ASSERT( KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen );
//
// update the LastWriteTime on both keynode and kcb;
//
KeQuerySystemTime(&TimeStamp);
KeyNode->LastWriteTime = TimeStamp;
KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
if (KeyNode->MaxNameLen < Name->Length) {
KeyNode->MaxNameLen = Name->Length;
// update the kcb cache too
KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name->Length;
}
if (KeyNode->MaxClassLen < Context->Class.Length) {
KeyNode->MaxClassLen = Context->Class.Length;
}
if (Context->CreateOptions & REG_OPTION_CREATE_LINK) {
pdata = HvGetCell(Hive, KeyCell);
if( pdata == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as we just allocated the cell
// (i.e. it must be PINNED into memory at this point)
//
ASSERT( FALSE );
CmpFreeKeyByCell(Hive, KeyCell, TRUE);
KeyBody->KeyControlBlock->Delete = TRUE;
CmpRemoveKeyControlBlock(KeyBody->KeyControlBlock);
ObDereferenceObjectDeferDelete(*Object);
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
pdata->u.KeyNode.Flags |= KEY_SYM_LINK;
KeyBody->KeyControlBlock->Flags = pdata->u.KeyNode.Flags;
HvReleaseCell(Hive,KeyCell);
}
}
}
Exit:
HvReleaseFreeCellRefArray(&CellRef);
CmpUnlockHiveFlusher((PCMHIVE)Hive);
return status;
}
NTSTATUS
CmpDoCreateChild(
IN PHHIVE Hive,
IN HCELL_INDEX ParentCell,
IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
IN PACCESS_STATE AccessState,
IN PUNICODE_STRING Name,
IN KPROCESSOR_MODE AccessMode,
IN PCM_PARSE_CONTEXT Context,
IN PCM_KEY_CONTROL_BLOCK ParentKcb,
IN USHORT Flags,
OUT PHCELL_INDEX KeyCell,
OUT PVOID *Object
)
/*++
Routine Description:
Creates a new sub-key. This is called by CmpDoCreate to create child
sub-keys and CmpCreateLinkNode to create root sub-keys.
Arguments:
Hive - supplies a pointer to the hive control structure for the hive
ParentCell - supplies cell index of parent cell
ParentDescriptor - Supplies security descriptor of parent key, for use
in inheriting ACLs.
AccessState - Running security access state information for operation.
Name - Supplies pointer to a UNICODE string which is the name of the
child to be created.
AccessMode - Access mode of the original caller.
Context - Supplies pointer to CM_PARSE_CONTEXT structure passed through
the object manager.
BaseName - Name of object create is relative to
KeyName - Relative name (to BaseName)
Flags - Supplies any flags to be set in the newly created node
KeyCell - Receives the cell index of the newly created sub-key, if any.
Object - Receives a pointer to the created key object, if any.
Return Value:
STATUS_SUCCESS - sub-key successfully created. New object is returned in
Object, and the new cell's cell index is returned in KeyCell.
!STATUS_SUCCESS - appropriate error message.
--*/
{
ULONG alloc=0;
NTSTATUS Status = STATUS_SUCCESS;
PCM_KEY_BODY KeyBody;
HCELL_INDEX ClassCell=HCELL_NIL;
PCM_KEY_NODE KeyNode;
PCELL_DATA CellData;
PCM_KEY_CONTROL_BLOCK kcb = NULL;
ULONG StorageType;
PSECURITY_DESCRIPTOR NewDescriptor = NULL;
LARGE_INTEGER systemtime;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpDoCreateChild:\n"));
//
// Get allocation type
//
StorageType = Stable;
try {
if (Context->CreateOptions & REG_OPTION_VOLATILE) {
StorageType = Volatile;
}
//
// Allocate child cell
//
*KeyCell = HvAllocateCell(
Hive,
CmpHKeyNodeSize(Hive, Name),
StorageType,
HCELL_NIL
);
if (*KeyCell == HCELL_NIL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
alloc = 1;
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, *KeyCell);
if( KeyNode == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as we just allocated the cell
// (i.e. it must be PINNED into memory at this point)
//
ASSERT( FALSE );
Status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
// release the cell right here as the view is pinned
HvReleaseCell(Hive,*KeyCell);
//
// Allocate cell for class name
//
if (Context->Class.Length > 0) {
ClassCell = HvAllocateCell(Hive, Context->Class.Length, StorageType,*KeyCell);
if (ClassCell == HCELL_NIL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
}
alloc = 2;
//
// Allocate the object manager object
//
Status = ObCreateObject(AccessMode,
CmpKeyObjectType,
NULL,
AccessMode,
NULL,
sizeof(CM_KEY_BODY),
0,
0,
Object);
if (NT_SUCCESS(Status)) {
KeyBody = (PCM_KEY_BODY)(*Object);
//
// We have managed to allocate all of the objects we need to,
// so initialize them
//
//
// Mark the object as uninitialized (in case we get an error too soon)
//
KeyBody->Type = KEY_BODY_TYPE;
KeyBody->KeyControlBlock = NULL;
//
// Fill in the class name
//
if (Context->Class.Length > 0) {
CellData = HvGetCell(Hive, ClassCell);
if( CellData == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as we just allocated the cell
// (i.e. it must be PINNED into memory at this point)
//
ASSERT( FALSE );
Status = STATUS_INSUFFICIENT_RESOURCES;
ObDereferenceObject(*Object);
leave;
}
// release the cell right here as the view is pinned (cell is dirty).
HvReleaseCell(Hive,ClassCell);
try {
RtlCopyMemory(
&(CellData->u.KeyString[0]),
Context->Class.Buffer,
Context->Class.Length
);
} except(EXCEPTION_EXECUTE_HANDLER) {
ObDereferenceObjectDeferDelete(*Object);
Status = GetExceptionCode();
leave;
}
}
//
// Fill in the new key itself
//
KeyNode->Signature = CM_KEY_NODE_SIGNATURE;
KeyNode->Flags = Flags;
KeQuerySystemTime(&systemtime);
KeyNode->LastWriteTime = systemtime;
KeyNode->Spare = 0;
KeyNode->Parent = ParentCell;
KeyNode->SubKeyCounts[Stable] = 0;
KeyNode->SubKeyCounts[Volatile] = 0;
KeyNode->SubKeyLists[Stable] = HCELL_NIL;
KeyNode->SubKeyLists[Volatile] = HCELL_NIL;
KeyNode->ValueList.Count = 0;
KeyNode->ValueList.List = HCELL_NIL;
KeyNode->Security = HCELL_NIL;
KeyNode->Class = ClassCell;
KeyNode->ClassLength = Context->Class.Length;
KeyNode->MaxValueDataLen = 0;
KeyNode->MaxNameLen = 0;
KeyNode->MaxValueNameLen = 0;
KeyNode->MaxClassLen = 0;
KeyNode->NameLength = CmpCopyName(Hive,
KeyNode->Name,
Name);
if (KeyNode->NameLength < Name->Length) {
KeyNode->Flags |= KEY_COMP_NAME;
}
if (Context->CreateOptions & REG_OPTION_PREDEF_HANDLE) {
KeyNode->ValueList.Count = (ULONG)((ULONG_PTR)Context->PredefinedHandle);
KeyNode->Flags |= KEY_PREDEF_HANDLE;
}
//
// Create kcb here so all data are filled in.
//
// Allocate a key control block
//
kcb = CmpCreateKeyControlBlock(Hive, *KeyCell, KeyNode, ParentKcb, CMP_CREATE_KCB_KCB_LOCKED, Name);
if (kcb == NULL) {
ObDereferenceObjectDeferDelete(*Object);
Status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
ASSERT(kcb->RefCount == 1);
alloc = 3;
#if DBG
if( kcb->ExtFlags & CM_KCB_KEY_NON_EXIST ) {
//
// we shouldn't fall into this
//
ObDereferenceObjectDeferDelete(*Object);
DbgBreakPoint();
Status = STATUS_OBJECT_NAME_NOT_FOUND;
leave;
}
#endif //DBG
//
// Fill in CM specific fields in the object
//
KeyBody->Type = KEY_BODY_TYPE;
KeyBody->KeyControlBlock = kcb;
KeyBody->NotifyBlock = NULL;
KeyBody->ProcessID = PsGetCurrentProcessId();
EnlistKeyBodyWithKCB(KeyBody,CMP_ENLIST_KCB_LOCKED_EXCLUSIVE);
//
// Assign a security descriptor to the object. Note that since
// registry keys are container objects, and ObAssignSecurity
// assumes that the only container object in the world is
// the ObpDirectoryObjectType, we have to call SeAssignSecurity
// directly in order to get the right inheritance.
//
Status = SeAssignSecurity(ParentDescriptor,
AccessState->SecurityDescriptor,
&NewDescriptor,
TRUE, // container object
&AccessState->SubjectSecurityContext,
&CmpKeyObjectType->TypeInfo.GenericMapping,
CmpKeyObjectType->TypeInfo.PoolType);
if (NT_SUCCESS(Status)) {
CmLockHiveSecurityExclusive((PCMHIVE)kcb->KeyHive);
//
// force assign to the new kcb, by passing NULL as the trans
//
Status = CmpAssignSecurityDescriptorWrapper(*Object,NewDescriptor);
CmUnlockHiveSecurity((PCMHIVE)kcb->KeyHive);
}
//
// Since the security descriptor now lives in the hive,
// free the in-memory copy
//
SeDeassignSecurity( &NewDescriptor );
if (!NT_SUCCESS(Status)) {
//
// Note that the dereference will clean up the kcb, so
// make sure and decrement the allocation count here.
//
// Also mark the kcb as deleted so it does not get
// inappropriately cached.
//
kcb->Delete = TRUE;
CmpRemoveKeyControlBlock(kcb);
ObDereferenceObjectDeferDelete(*Object);
alloc = 2;
} else {
CmpReportNotify(
kcb,
kcb->KeyHive,
kcb->KeyCell,
REG_NOTIFY_CHANGE_NAME
);
}
}
} finally {
if (!NT_SUCCESS(Status)) {
//
// Clean up allocations
//
switch (alloc) {
case 3:
//
// Mark KCB as deleted so it does not get inadvertently added to
// the delayed close list. That would have fairly disastrous effects
// as the KCB points to storage we are about to free.
//
kcb->Delete = TRUE;
CmpRemoveKeyControlBlock(kcb);
CmpDereferenceKeyControlBlockWithLock(kcb,FALSE);
// DELIBERATE FALL
case 2:
if (Context->Class.Length > 0) {
HvFreeCell(Hive, ClassCell);
}
// DELIBERATE FALL
case 1:
HvFreeCell(Hive, *KeyCell);
// DELIBERATE FALL
}
}
}
return(Status);
}

191
base/ntos/config/cmpbug.h Normal file
View File

@ -0,0 +1,191 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmpbug.h
Abstract:
Description of the registry bugchecks; only defines and comments.
--*/
#ifndef __CMPBUG_H__
#define __CMPBUG_H__
#define CM_BUGCHECK( Code, Parm1, Parm2, Parm3, Parm4 ) \
KeBugCheckEx( (ULONG)Code, (ULONG_PTR)Parm1, (ULONG_PTR)Parm2, (ULONG_PTR)Parm3, (ULONG_PTR)Parm4 )
/* -
CRITICAL_SERVICE_FAILED (0x5A)
*/
/* -
SET_ENV_VAR_FAILED (0x5B)
*/
#define BAD_LAST_KNOWN_GOOD 1 //CmBootLastKnownGood
/* -
CONFIG_LIST_FAILED (0x73)
Indicates that one of the core system hives cannot be linked in the
registry tree. The hive is valid, it was loaded OK. Examine the 2nd
bugcheck argument to see why the hive could not be linked in the
registry tree.
PARAMETERS
1 - 1
2 - Indicates the NT status code that tripped us into thinking
that we failed to load the hive.
3 - Index of hive in hivelist
4 - Pointer to UNICODE_STRING containing filename of hive
DESCRIPTION
This can be either SAM, SECURITY, SOFTWARE or DEFAULT. One common reason
for this to happen is if you are out of disk space on the system drive
(in which case param 4 is 0xC000017D - STATUS_NO_LOG_SPACE) or an attempt
to allocate pool has failed (in which case param 4 is 0xC000009A -
STATUS_INSUFFICIENT_RESOURCES). Other status codes must be individually
investigated.
*/
#define BAD_CORE_HIVE 1 // CmpInitializeHiveList
/* -
BAD_SYSTEM_CONFIG_INFO (0x74)
Can indicate that the SYSTEM hive loaded by the osloader/NTLDR
was corrupt. This is unlikely, since the osloader will check
a hive to make sure it isn't corrupt after loading it.
It can also indicate that some critical registry keys and values
are not present. (i.e. somebody used regedt32 to delete something
that they shouldn't have) Booting from LastKnownGood may fix
the problem, but if someone is persistent enough in mucking with
the registry they will need to reinstall or use the Emergency
Repair Disk.
PARAMETERS
1 - identifies the function
2 - identifies the line inside the function
3 - other info
4 - usually the NT status code.
*/
#define BAD_SYSTEM_CONTROL_VALUES 1 // CmGetSystemControlValues
#define BAD_HIVE_LIST 2 // CmpInitializeHiveList
#define BAD_SYSTEM_HIVE 3 // CmpInitializeSystemHive
/* -
CONFIG_INITIALIZATION_FAILED (0x67)
PARAMETERS
1 - indicates location in ntos\config\cmsysini that failed
2 - location selector
3 - NT status code
DESCRIPTION
This means the registry couldn't allocate the pool needed to contain the
registry files. This should never happen, since it is early enough in
system initialization that there is always plenty of paged pool available.
*/
#define INIT_SYSTEM1 1 // CmInitSystem1
#define INIT_SYSTEM_DRIVER_LIST 2 // CmGetSystemDriverList
#define INIT_CACHE_TABLE 3 // CmpInitializeCache
#define INIT_DELAYED_CLOSE_TABLE 4 // CmpInitializeDelayedCloseTable
/* -
CANNOT_WRITE_CONFIGURATION (0x75)
This will result if the SYSTEM hive file cannot be converted to a
mapped file. This usually happens if the system is out of pool and
we cannot reopen the hive.
PARAMETERS
1 - 1
2 - Indicates the NT status code that tripped us into thinking
that we failed to convert the hive.
DESCRIPTION
Normally you shouldn't see this as the conversion happens at early
during system initialization, so enough pool should be available.
*/
#define CANNOT_CONVERT_SYSTEM_HIVE 1
/* -
REGISTRY_ERROR (0x51)
PARAMETERS
1 - value 1 (indicates where we bugchecked)
2 - value 2 (indicates where we bugchecked)
3 - depends on where it bugchecked, may be pointer to hive
4 - depends on where it bugchecked, may be return code of
HvCheckHive if the hive is corrupt.
DESCRIPTION
Something has gone horribly wrong with the registry. If a kernel debugger
is available, get a stack trace.It can also indicate that the registry got
an I/O error while trying to read one of its files, so it can be caused by
hardware problems or filesystem corruption.
It may occur due to a failure in a refresh operation, which is used only
in by the security system, and then only when resource limits are encountered.
*/
#define BAD_CELL_MAP 1 // VALIDATE_CELL_MAP
#define BAD_FREE_BINS_LIST 2 // HvpDelistBinFreeCells
#define FATAL_MAPPING_ERROR 3 // HvpFindNextDirtyBlock
// HvpDoWriteHive
#define BAD_SECURITY_CACHE 4 // CmpAssignSecurityToKcb
// CmpSetSecurityDescriptorInfo
#define BAD_SECURITY_METHOD 5 // CmpSecurityMethod
#define CHECK_LOCK_EXCEPTION 6 // CmpCheckLockExceptionFilter
#define REGISTRY_LOCK_CHECKPOINT 7 // END_LOCK_CHECKPOINT
#define BIG_CELL_ERROR 8 // CmpValueToData
#define CMVIEW_ERROR 9 // CmpAllocateCmView
// CmpFreeCmView
// CmpPinCmView
#define REFRESH_HIVE 0xA // HvRefreshHive
#define ALLOCATE_SECURITY_DESCRIPTOR 0xB // CmpHiveRootSecurityDescriptor
#define BAD_NOTIFY_CONTEXT 0xC // NtNotifyChangeMultipleKeys
#define QUOTA_ERROR 0xD // CmpReleaseGlobalQuota
#define INVALID_WRITE_OPERATION 0xE // NtCreateKey
#define HANDLES_STILL_OPEN_AT_SHUTDOWN 0xF // CmFreeAllMemory
#define COMPRESS_HIVE 0x10 // CmCompressKey
#define ALLOC_ERROR 0x11 // CmpFreeKeyControlBlock
#endif // _CMPBUG_

161
base/ntos/config/cmquery.c Normal file
View File

@ -0,0 +1,161 @@
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.
Module Name:
cmquery.c
Abstract:
This module contains the object name query method for the registry.
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpQueryKeyName)
#endif
NTSTATUS
CmpQueryKeyName(
IN PVOID Object,
IN BOOLEAN HasObjectName,
OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
IN ULONG Length,
OUT PULONG ReturnLength,
IN KPROCESSOR_MODE Mode
)
/*++
Routine Description:
This routine interfaces to the NT Object Manager. It is invoked when
the object system wishes to discover the name of an object that
belongs to the registry.
Arguments:
Object - pointer to a Key, thus -> KEY_BODY.
HasObjectName - indicates whether the object manager knows about a name
for this object
ObjectNameInfo - place where we report the name
Length - maximum length they can deal with
ReturnLength - supplies variable to receive actual length
Mode - Processor mode of the caller
Return Value:
STATUS_SUCCESS
STATUS_INFO_LENGTH_MISMATCH
--*/
{
PUNICODE_STRING Name = NULL;
PWCHAR t;
PWCHAR s;
ULONG l;
NTSTATUS status;
PCM_KEY_CONTROL_BLOCK kcb;
BOOLEAN UnlockKcb = TRUE;
UNREFERENCED_PARAMETER(HasObjectName);
UNREFERENCED_PARAMETER(Mode);
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_PARSE,"CmpQueryKeyName:\n"));
BEGIN_LOCK_CHECKPOINT;
CmpLockRegistry();
//
// sanitize the kcb, for cases where we get a callback for se audit
//
kcb = (PCM_KEY_CONTROL_BLOCK)(((PCM_KEY_BODY)Object)->KeyControlBlock);
if( (ULONG_PTR)kcb & 1 ) {
kcb = (PCM_KEY_CONTROL_BLOCK)((ULONG_PTR)kcb ^ 1);
ASSERT_KCB_LOCKED(kcb);
UnlockKcb = FALSE;
} else {
CmpLockKCBShared(kcb);
}
if ( kcb->Delete) {
if( UnlockKcb ) {
CmpUnlockKCB(kcb);
}
CmpUnlockRegistry();
return STATUS_KEY_DELETED;
}
Name = CmpConstructName(kcb);
if( UnlockKcb ) {
CmpUnlockKCB(kcb);
}
//
// don't need the lock anymore
//
CmpUnlockRegistry();
END_LOCK_CHECKPOINT;
if (Name == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
return status;
}
if (Length <= sizeof(OBJECT_NAME_INFORMATION)) {
*ReturnLength = Name->Length + sizeof(WCHAR) + sizeof(OBJECT_NAME_INFORMATION);
ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL);
return STATUS_INFO_LENGTH_MISMATCH; // they can't even handle null
}
t = (PWCHAR)(ObjectNameInfo + 1);
s = Name->Buffer;
l = Name->Length;
l += sizeof(WCHAR); // account for null
*ReturnLength = l + sizeof(OBJECT_NAME_INFORMATION);
if (l > Length - sizeof(OBJECT_NAME_INFORMATION)) {
l = Length - sizeof(OBJECT_NAME_INFORMATION);
status = STATUS_INFO_LENGTH_MISMATCH;
if( l < sizeof(WCHAR) ) {
ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL);
return status; // they can't even handle null
}
} else {
status = STATUS_SUCCESS;
}
l -= sizeof(WCHAR);
//
// The ObjectNameInfo buffer is a usermode buffer, so make sure we have an
// exception handler in case a malicious app changes the protection out from
// under us.
//
// Note the object manager is responsible for probing the buffer and ensuring
// that a top-level exception handler returns the correct error code. We just
// need to make sure we drop our lock.
//
try {
RtlCopyMemory(t, s, l);
t[l/sizeof(WCHAR)] = UNICODE_NULL;
ObjectNameInfo->Name.Length = (USHORT)l;
ObjectNameInfo->Name.MaximumLength = ObjectNameInfo->Name.Length;
ObjectNameInfo->Name.Buffer = t;
} finally {
ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL);
}
return status;
}

2640
base/ntos/config/cmsavres.c Normal file

File diff suppressed because it is too large Load Diff

2328
base/ntos/config/cmse.c Normal file

File diff suppressed because it is too large Load Diff

1126
base/ntos/config/cmsecache.c Normal file

File diff suppressed because it is too large Load Diff

2562
base/ntos/config/cmsubs.c Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More