⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 roll.c

📁 操作系统引导的一些介绍,对学习引导的有很大的帮助与提高
💻 C
字号:
//
// (C) Copyright 1997 OSR Open Systems Resources, Inc.
// All Rights Reserved
//

#include "roll.h"

//
// This demonstrates how to build your own IRPs completely from scratch, using
// your own memory, etc.
//
// Please keep in mind as you read this example that it was written with the intent
// to demonstrate a specific technique.  Thus, there are numerous ways this could
// be implemented, some of them far more brief.  Feel free to modify this code to use
// in your OWN programs...
//


//
// Data structures local to this module.
//

LIST_ENTRY MyIrpFreeList;          // contains freed, not currently in use
KSPIN_LOCK MyIrpFreeListLock;      // protection for the list
USHORT MyIrpFreeListMax;           // maximum # of IRPs to create for my free list
USHORT MyIrpFreeListCount;         // current # of IRPs created for my free list
KEVENT MyIrpFreeListEvent;         // allows caller to wait for an IRP
USHORT MyIrpSize;                   // # of bytes in the IRPs we allocate
CCHAR MyNumberOfIrpStackLocations; // # of IRP stack locations allocated in each IRP

//
// NOTE: In NT 4.0 you can use "look aside" lists to track free IRPs (they
// are really "free lists".)  These examples were written for NT 3.51 or
// 4.0 so you should modify the code to fit your specific requirements.
//

//
// For our purposes we hard-code the size of the IRPs we'll be creating.  We
// use five because that's safe, even with a single filter driver in the stack.
//

#define MAXIMUM_IRP_STACK_LOCATIONS (5)

//
// We'll limit the # of IRPs we create in this package to an arbitrary number.  Again,
// this can be changed to fit your requirements - or don't limit it at all!
//

#define MAXIMUM_IRP_COUNT (64)



//
// AllocateNewIrp
//
//  This internal helper routine is used to allocate a new IRP from non-paged pool.
//
// Inputs:
//  None.
//
// Outputs:
//  None.
//
// Returns:
//  A pointer to the newly created IRP.
//
// Notes:
//  None.

static PIRP AllocateNewIrp()
{
  PIRP newIrp;

  //
  // First, this routine fails whenever we've hit the maximum number.
  //

  if (MyIrpFreeListCount > MyIrpFreeListMax) {

    //
    // Return null - refuse this request.
    //

    return (PIRP) 0;

  }

  

  //
  // We use a special tag value to allow us to detect the IRPs we are creating (using
  // the kernel debugger or "poolmon".
  //

  newIrp = ExAllocatePoolWithTag(NonPagedPool, MyIrpSize, 'rIyM');

  if (!newIrp) {

    //
    // The creation of a new IRP failed.  The only time this really happens is when there is
    // no more non-paged pool.
    //
    // We choose the simpler solution here - we just return a null pointer.
    // If your driver requires it, please feel free to call NonPagedPoolMustSucceed - but
    // remember that the amount of such memory is VERY limited and if it cannot be granted
    // the system crashes ("blue screen").  Use sparingly.
    //
    
    return 0;
  }

  //
  // At this point, the IRP is allocated.  Return it to the caller.
  //

  return newIrp;

}



//
// MyInitIrpPackage
//
//   This routine is called to initialize the IRP management package.
//
// Inputs:
//   MaximumNumberOfIrpStackLocations - the # of IRP stack locations to allocate for all IRPs in the package
//   MaximumNumberOfIrps - the maximum # of IRPs to be allocated (on demand) by this package
//
// Outputs:
//  None.
//
// Returns:
//  None.
//
// Notes:
//  This package uses defaults if the passed-in values are zero.
//

VOID MyInitIrpPackage(CCHAR MaximumNumberOfIrpStackLocations, USHORT MaximumNumberOfIrps)
{
    ULONG MyIrpSize;


    if (MaximumNumberOfIrpStackLocations == 0) {

      //
      // We'll use the "default" number in this case
      //

      MyNumberOfIrpStackLocations = MAXIMUM_IRP_STACK_LOCATIONS;

    } else {

      //
      // We'll use the number passed in by the caller
      //

      MyNumberOfIrpStackLocations = MaximumNumberOfIrpStackLocations;

    }

    if (MaximumNumberOfIrps == 0) {

      //
      // We'll fall back on the backup value.
      // Note: this could be turned into a registry lookup for your particular driver.
      //

      MyIrpFreeListMax = MAXIMUM_IRP_COUNT;

    } else {

      //
      // We'll use the number given us by the caller
      //

      MyIrpFreeListMax = MaximumNumberOfIrps;
      
    }

    //
    // Now, compute the size of an IRP with the requisite # of stack
    // locations.
    //

    MyIrpSize = IoSizeOfIrp(MyNumberOfIrpStackLocations);


    //
    // Initialize our free list, spin lock, and free list event...
    //

    InitializeListHead(&MyIrpFreeList);

    KeInitializeSpinLock(&MyIrpFreeListLock);

    MyIrpFreeListCount = 0;

    KeInitializeEvent(&MyIrpFreeListEvent, SynchronizationEvent, FALSE);

    //
    // Now, let's start the list off with the first IRP.  We could defer this to first
    // reference but we decided to add this code early because it ensures we exercise
    // most of the logic we use in this package.
    //

    MyFreeIrp(AllocateNewIrp());

    //
    // We believe there will be something on the list.  We assert this at this point.
    //

    ASSERT(!IsListEmpty(&MyIrpFreeList));

    //
    // Done with the initialization.  Of course, feel free to add more
    // code here for YOUR specific project!
    //

    return;

}



//
// MyAllocateIrp
//
//  This routine is called by your driver to allocate a new I/O request packet.
//
// Inputs:
//  StackSize - this is the # of stack elements required.  It must be <= the max # of stack sizes
//  Wait - indicates if the caller is willing to wait for the IRP allocation
//
// Outputs:
//  None.
//
// Returns:
//  The new IRP if successful.  Otherwise, null
//
// Notes:
//  Any caller already "owning" an IRP created by this package MUST indicate Wait = FALSE to
//  avoid deadlock conditions.  Callers of this routine which indicate Wait == TRUE must be
//  dispatchable (IRQL < DISPATCH_LEVEL).
//


PIRP MyAllocateIrp(CCHAR StackSize, BOOLEAN Wait)
{
  KIRQL oldIrql;
  PIRP newIrp = 0;

  //
  // The caller should never ask for an IRP with more stack locations than those we
  // have created.  If they do, there is something wrong - we'll assert out at this point
  // so we can catch this problem.
  //
  // (If you ignore this failure here, later you will see a blue screen with
  // NO_MORE_IRP_STACK_LOCATIONS as the stop code - eventually.)
  //

  ASSERT(StackSize <= MyNumberOfIrpStackLocations);

  while (1) {

    KeAcquireSpinLock(&MyIrpFreeListLock, &oldIrql);

    //
    // We must use RemoveHeadList in an IF statement because it is not an expression.
    //

    if (!IsListEmpty(&MyIrpFreeList)) {
      PLIST_ENTRY listEntry; 

      //
      // Remove the head of the list.
      //

      listEntry = RemoveHeadList(&MyIrpFreeList);

      //
      // Convert into an IRP pointer.
      //

      newIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);

    }

    KeReleaseSpinLock(&MyIrpFreeListLock, oldIrql);

    if (newIrp) {

      //
      // Jump out of the loop.
      //

      break;

    }

    //
    // We'll try to create a new entry.
    //

    newIrp = AllocateNewIrp();

    if (!newIrp) {

      //
      // The allocation was unsuccessful.  If the caller indicated they could wait
      // then we'll put them to sleep waiting for the synchronization event
      //
      // NOTE: We assume here we seeded the list, so there is AT LEAST ONE IRP already
      //       created for the pool.  If there were zero, we might never wake up, because
      //       we're going to count on some other thread releasing an IRP.
      //

      if (Wait) {

        ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
        
        KeWaitForSingleObject(&MyIrpFreeListEvent,
                              Spare6, // reason - we use this to ease debugging.
                              KernelMode, // mode
                              FALSE, // not altertable
                              0); // no timeout
      } else {
        //
        // The caller indicated they could not wait.  We'll break from the loop and handle
        // this condition below.
        //

        break;

      }

    } // if (!newIrp)

  } // while (1)

  //
  // At this point we're done with the processing.  If this is null, it is because the caller
  // was unwilling to wait for allocation.
  //

  return newIrp;

}



//
// MyFreeIrp
//
//  This routine is called to free up an IRP previously allocated by a call to MyAllocateIrp
//
// Inputs:
//  Irp - the IRP to be freed
//
// Outputs:
//  None.
//
// Returns:
//  None.
//
// Notes:
//  NEVER call this package with I/O manager allocated IRPs - doing so may cause catastrophic system failure
//  (since we're going to reinitialize the IRPs and if they aren't of the correct size we could trash things...)
//
//

VOID MyFreeIrp(PIRP Irp)
{
  //
  // If a null pointer is passed we just return.  Not much we can do with
  // a null pointer.
  //

  if (!Irp) {

    return;
 
  }

  //
  // Before we re-queue the IRP, we will initialize it.  It will then be ready to hand off to the new caller
  // when they allocate it.
  //
  // NOTE: This is the ONLY time you would call IoInitializeIrp - with your own allocated memory.  Do NOT
  // call it after calling IoAllocateIrp as that will change flags within the IRP which can lead to a system
  // crash (memory arena corruption.)
  //

  IoInitializeIrp(Irp,
                  MyIrpSize,
                  (USHORT) MAXIMUM_IRP_STACK_LOCATIONS);

  //
  // Stick it on the free list
  //

  ExInterlockedInsertTailList(&MyIrpFreeList,
                              &Irp->Tail.Overlay.ListEntry,
                              &MyIrpFreeListLock);


  //
  //  And set the event - this awakens anyone who might be waiting for an IRP.
  //

  KeSetEvent(&MyIrpFreeListEvent, 1, FALSE);

  return;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -