示例#1
0
文件: coninput.c 项目: RPG-7/reactos
NTSTATUS NTAPI
ConDrvGetConsoleInput(IN PCONSOLE Console,
                      IN PCONSOLE_INPUT_BUFFER InputBuffer,
                      IN BOOLEAN KeepEvents,
                      IN BOOLEAN WaitForMoreEvents,
                      OUT PINPUT_RECORD InputRecord,
                      IN ULONG NumEventsToRead,
                      OUT PULONG NumEventsRead OPTIONAL)
{
    PLIST_ENTRY CurrentInput;
    ConsoleInput* Input;
    ULONG i = 0;

    if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
        return STATUS_INVALID_PARAMETER;

    /* Validity checks */
    ASSERT(Console == InputBuffer->Header.Console);
    ASSERT((InputRecord != NULL) || (InputRecord == NULL && NumEventsToRead == 0));

    if (NumEventsRead) *NumEventsRead = 0;

    if (IsListEmpty(&InputBuffer->InputEvents))
    {
        /*
         * No input is available. Wait for more input if requested,
         * otherwise, we don't wait, so we return success.
         */
        return (WaitForMoreEvents ? STATUS_PENDING : STATUS_SUCCESS);
    }

    /* Only get input if there is any */
    CurrentInput = InputBuffer->InputEvents.Flink;
    i = 0;
    while ((CurrentInput != &InputBuffer->InputEvents) && (i < NumEventsToRead))
    {
        Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);

        *InputRecord = Input->InputEvent;

        ++InputRecord;
        ++i;
        CurrentInput = CurrentInput->Flink;

        /* Remove the events from the queue if needed */
        if (!KeepEvents)
        {
            RemoveEntryList(&Input->ListEntry);
            ConsoleFreeHeap(Input);
        }
    }

    if (NumEventsRead) *NumEventsRead = i;

    if (IsListEmpty(&InputBuffer->InputEvents))
    {
        ResetEvent(InputBuffer->ActiveEvent);
    }

    // FIXME: If we add back UNICODE support, it's here that we need to do the translation.

    /* We read all the inputs available, we return success */
    return STATUS_SUCCESS;
}
示例#2
0
/**
  Get selection for OneOf and OrderedList (Left/Right will be ignored).

  @param  MenuOption        Pointer to the current input menu.

  @retval EFI_SUCCESS       If Option input is processed successfully
  @retval EFI_DEVICE_ERROR  If operation fails

**/
EFI_STATUS
GetSelectionInputPopUp (
  IN  UI_MENU_OPTION              *MenuOption
  )
{
  EFI_STATUS              Status;
  EFI_INPUT_KEY           Key;
  UINTN                   Index;
  CHAR16                  *StringPtr;
  CHAR16                  *TempStringPtr;
  UINTN                   Index2;
  UINTN                   TopOptionIndex;
  UINTN                   HighlightOptionIndex;
  UINTN                   Start;
  UINTN                   End;
  UINTN                   Top;
  UINTN                   Bottom;
  UINTN                   PopUpMenuLines;
  UINTN                   MenuLinesInView;
  UINTN                   PopUpWidth;
  CHAR16                  Character;
  INT32                   SavedAttribute;
  BOOLEAN                 ShowDownArrow;
  BOOLEAN                 ShowUpArrow;
  UINTN                   DimensionsWidth;
  LIST_ENTRY              *Link;
  BOOLEAN                 OrderedList;
  UINT8                   *ValueArray;
  UINT8                   *ReturnValue;
  UINT8                   ValueType;
  EFI_HII_VALUE           HiiValue;
  DISPLAY_QUESTION_OPTION         *OneOfOption;
  DISPLAY_QUESTION_OPTION         *CurrentOption;
  FORM_DISPLAY_ENGINE_STATEMENT  *Question;
  INTN                    Result;
  EFI_IFR_ORDERED_LIST    *OrderList;

  DimensionsWidth   = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;

  ValueArray        = NULL;
  ValueType         = 0;
  CurrentOption     = NULL;
  ShowDownArrow     = FALSE;
  ShowUpArrow       = FALSE;

  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
  ASSERT (StringPtr);

  ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));

  Question = MenuOption->ThisTag;
  if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
    Link = GetFirstNode (&Question->OptionListHead);
    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
    ValueArray = Question->CurrentValue.Buffer;
    ValueType =  OneOfOption->OptionOpCode->Type;
    OrderedList = TRUE;
    OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
  } else {
    OrderedList = FALSE;
    OrderList = NULL;
  }

  //
  // Calculate Option count
  //
  PopUpMenuLines = 0;
  if (OrderedList) {
    AdjustOptionOrder(Question, &PopUpMenuLines);
  } else {
    Link = GetFirstNode (&Question->OptionListHead);
    while (!IsNull (&Question->OptionListHead, Link)) {
      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
      PopUpMenuLines++;
      Link = GetNextNode (&Question->OptionListHead, Link);
    }
  }

  //
  // Get the number of one of options present and its size
  //
  PopUpWidth = 0;
  HighlightOptionIndex = 0;
  Link = GetFirstNode (&Question->OptionListHead);
  for (Index = 0; Index < PopUpMenuLines; Index++) {
    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);

    StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
    if (StrLen (StringPtr) > PopUpWidth) {
      PopUpWidth = StrLen (StringPtr);
    }
    FreePool (StringPtr);
    HiiValue.Type = OneOfOption->OptionOpCode->Type;
    SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);
    if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
      //
      // Find current selected Option for OneOf
      //
      HighlightOptionIndex = Index;
    }

    Link = GetNextNode (&Question->OptionListHead, Link);
  }

  //
  // Perform popup menu initialization.
  //
  PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;

  SavedAttribute = gST->ConOut->Mode->Attribute;
  gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());

  if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
    PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
  }

  Start  = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;
  End    = Start + PopUpWidth + POPUP_FRAME_WIDTH;
  Top    = gStatementDimensions.TopRow;
  Bottom = gStatementDimensions.BottomRow - 1;

  MenuLinesInView = Bottom - Top - 1;
  if (MenuLinesInView >= PopUpMenuLines) {
    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;
    Bottom  = Top + PopUpMenuLines + 1;
  } else {
    ShowDownArrow = TRUE;
  }

  if (HighlightOptionIndex > (MenuLinesInView - 1)) {
    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
  } else {
    TopOptionIndex = 0;
  }

  do {
    //
    // Clear that portion of the screen
    //
    ClearLines (Start, End, Top, Bottom, GetPopupColor ());

    //
    // Draw "One of" pop-up menu
    //
    Character = BOXDRAW_DOWN_RIGHT;
    PrintCharAt (Start, Top, Character);
    for (Index = Start; Index + 2 < End; Index++) {
      if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
        Character = GEOMETRICSHAPE_UP_TRIANGLE;
      } else {
        Character = BOXDRAW_HORIZONTAL;
      }

      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
    }

    Character = BOXDRAW_DOWN_LEFT;
    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
    Character = BOXDRAW_VERTICAL;
    for (Index = Top + 1; Index < Bottom; Index++) {
      PrintCharAt (Start, Index, Character);
      PrintCharAt (End - 1, Index, Character);
    }

    //
    // Move to top Option
    //
    Link = GetFirstNode (&Question->OptionListHead);
    for (Index = 0; Index < TopOptionIndex; Index++) {
      Link = GetNextNode (&Question->OptionListHead, Link);
    }

    //
    // Display the One of options
    //
    Index2 = Top + 1;
    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
      Link = GetNextNode (&Question->OptionListHead, Link);

      StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
      ASSERT (StringPtr != NULL);
      //
      // If the string occupies multiple lines, truncate it to fit in one line,
      // and append a "..." for indication.
      //
      if (StrLen (StringPtr) > (PopUpWidth - 1)) {
        TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
        ASSERT ( TempStringPtr != NULL );
        CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
        FreePool (StringPtr);
        StringPtr = TempStringPtr;
        StrCat (StringPtr, L"...");
      }

      if (Index == HighlightOptionIndex) {
          //
          // Highlight the selected one
          //
          CurrentOption = OneOfOption;

          gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());
          PrintStringAt (Start + 2, Index2, StringPtr);
          gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
        } else {
          gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
          PrintStringAt (Start + 2, Index2, StringPtr);
        }

      Index2++;
      FreePool (StringPtr);
    }

    Character = BOXDRAW_UP_RIGHT;
    PrintCharAt (Start, Bottom, Character);
    for (Index = Start; Index + 2 < End; Index++) {
      if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
        Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
      } else {
        Character = BOXDRAW_HORIZONTAL;
      }

      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
    }

    Character = BOXDRAW_UP_LEFT;
    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);

    //
    // Get User selection
    //
    Key.UnicodeChar = CHAR_NULL;
    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
      Key.ScanCode  = gDirection;
      gDirection    = 0;
      goto TheKey;
    }

    Status = WaitForKeyStroke (&Key);

TheKey:
    switch (Key.UnicodeChar) {
    case '+':
      if (OrderedList) {
        if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
          //
          // Highlight reaches the top of the popup window, scroll one menu item.
          //
          TopOptionIndex--;
          ShowDownArrow = TRUE;
        }

        if (TopOptionIndex == 0) {
          ShowUpArrow = FALSE;
        }

        if (HighlightOptionIndex > 0) {
          HighlightOptionIndex--;

          ASSERT (CurrentOption != NULL);
          SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
        }
      }
      break;

    case '-':
      //
      // If an ordered list op-code, we will allow for a popup of +/- keys
      // to create an ordered list of items
      //
      if (OrderedList) {
        if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
          //
          // Highlight reaches the bottom of the popup window, scroll one menu item.
          //
          TopOptionIndex++;
          ShowUpArrow = TRUE;
        }

        if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
          ShowDownArrow = FALSE;
        }

        if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
          HighlightOptionIndex++;

          ASSERT (CurrentOption != NULL);
          SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
        }
      }
      break;

    case CHAR_NULL:
      switch (Key.ScanCode) {
      case SCAN_UP:
      case SCAN_DOWN:
        if (Key.ScanCode == SCAN_UP) {
          if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
            //
            // Highlight reaches the top of the popup window, scroll one menu item.
            //
            TopOptionIndex--;
            ShowDownArrow = TRUE;
          }

          if (TopOptionIndex == 0) {
            ShowUpArrow = FALSE;
          }

          if (HighlightOptionIndex > 0) {
            HighlightOptionIndex--;
          }
        } else {
          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
            //
            // Highlight reaches the bottom of the popup window, scroll one menu item.
            //
            TopOptionIndex++;
            ShowUpArrow = TRUE;
          }

          if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
            ShowDownArrow = FALSE;
          }

          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
            HighlightOptionIndex++;
          }
        }
        break;

      case SCAN_ESC:
        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);

        //
        // Restore link list order for orderedlist
        //
        if (OrderedList) {
          HiiValue.Type = ValueType;
          HiiValue.Value.u64 = 0;
          for (Index = 0; Index < OrderList->MaxContainers; Index++) {
            HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
            if (HiiValue.Value.u64 == 0) {
              break;
            }

            OneOfOption = ValueToOption (Question, &HiiValue);
            if (OneOfOption == NULL) {
              return EFI_NOT_FOUND;
            }

            RemoveEntryList (&OneOfOption->Link);
            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
          }
        }

        return EFI_DEVICE_ERROR;

      default:
        break;
      }

      break;

    case CHAR_CARRIAGE_RETURN:
      //
      // return the current selection
      //
      if (OrderedList) {
        ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);
        ASSERT (ReturnValue != NULL);
        Index = 0;
        Link = GetFirstNode (&Question->OptionListHead);
        while (!IsNull (&Question->OptionListHead, Link)) {
          OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
          Link = GetNextNode (&Question->OptionListHead, Link);

          SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);

          Index++;
          if (Index > OrderList->MaxContainers) {
            break;
          }
        }
        if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {
          FreePool (ReturnValue);
          return EFI_DEVICE_ERROR;
        } else {
          gUserInput->InputValue.Buffer = ReturnValue;
          gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
          Status = EFI_SUCCESS;
        }
      } else {
        ASSERT (CurrentOption != NULL);
        gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;
        if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {
          return EFI_DEVICE_ERROR;
        } else {
          SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);
          Status = EFI_SUCCESS;
        }
      }

      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);

      return EFI_SUCCESS;
      
    default:
      break;
    }
  } while (TRUE);

}
示例#3
0
PVOID
NTAPI
MiAllocatePoolPages(IN POOL_TYPE PoolType,
                    IN SIZE_T SizeInBytes)
{
    PFN_NUMBER SizeInPages, PageFrameNumber, PageTableCount;
    ULONG i;
    KIRQL OldIrql;
    PLIST_ENTRY NextEntry, NextHead, LastHead;
    PMMPTE PointerPte, StartPte;
    PMMPDE PointerPde;
    ULONG EndAllocation;
    MMPTE TempPte;
    MMPDE TempPde;
    PMMPFN Pfn1;
    PVOID BaseVa, BaseVaStart;
    PMMFREE_POOL_ENTRY FreeEntry;
    PKSPIN_LOCK_QUEUE LockQueue;

    //
    // Figure out how big the allocation is in pages
    //
    SizeInPages = BYTES_TO_PAGES(SizeInBytes);

    //
    // Handle paged pool
    //
    if ((PoolType & BASE_POOL_TYPE_MASK) == PagedPool)
    {
        //
        // Lock the paged pool mutex
        //
        KeAcquireGuardedMutex(&MmPagedPoolMutex);

        //
        // Find some empty allocation space
        //
        i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap,
                                   SizeInPages,
                                   MmPagedPoolInfo.PagedPoolHint);
        if (i == 0xFFFFFFFF)
        {
            //
            // Get the page bit count
            //
            i = ((SizeInPages - 1) / PTE_COUNT) + 1;
            DPRINT1("Paged pool expansion: %d %x\n", i, SizeInPages);

            //
            // Check if there is enougn paged pool expansion space left
            //
            if (MmPagedPoolInfo.NextPdeForPagedPoolExpansion >
                (PMMPDE)MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool))
            {
                //
                // Out of memory!
                //
                DPRINT1("OUT OF PAGED POOL!!!\n");
                KeReleaseGuardedMutex(&MmPagedPoolMutex);
                return NULL;
            }

            //
            // Check if we'll have to expand past the last PTE we have available
            //
            if (((i - 1) + MmPagedPoolInfo.NextPdeForPagedPoolExpansion) >
                 (PMMPDE)MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool))
            {
                //
                // We can only support this much then
                //
                PageTableCount = (PMMPDE)MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool) -
                                         MmPagedPoolInfo.NextPdeForPagedPoolExpansion +
                                         1;
                ASSERT(PageTableCount < i);
                i = PageTableCount;
            }
            else
            {
                //
                // Otherwise, there is plenty of space left for this expansion
                //
                PageTableCount = i;
            }

            //
            // Get the template PDE we'll use to expand
            //
            TempPde = ValidKernelPde;

            //
            // Get the first PTE in expansion space
            //
            PointerPde = MmPagedPoolInfo.NextPdeForPagedPoolExpansion;
            BaseVa = MiPdeToPte(PointerPde);
            BaseVaStart = BaseVa;

            //
            // Lock the PFN database and loop pages
            //
            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
            do
            {
                //
                // It should not already be valid
                //
                ASSERT(PointerPde->u.Hard.Valid == 0);

                /* Request a page */
                MI_SET_USAGE(MI_USAGE_PAGED_POOL);
                MI_SET_PROCESS2("Kernel");
                PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
                TempPde.u.Hard.PageFrameNumber = PageFrameNumber;
#if (_MI_PAGING_LEVELS >= 3)
                /* On PAE/x64 systems, there's no double-buffering */
                ASSERT(FALSE);
#else
                //
                // Save it into our double-buffered system page directory
                //
                MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)] = TempPde;

                /* Initialize the PFN */
                MiInitializePfnForOtherProcess(PageFrameNumber,
                                               (PMMPTE)PointerPde,
                                               MmSystemPageDirectory[(PointerPde - MiAddressToPde(NULL)) / PDE_COUNT]);

                /* Write the actual PDE now */
//                MI_WRITE_VALID_PDE(PointerPde, TempPde);
#endif
                //
                // Move on to the next expansion address
                //
                PointerPde++;
                BaseVa = (PVOID)((ULONG_PTR)BaseVa + PAGE_SIZE);
                i--;
            } while (i > 0);

            //
            // Release the PFN database lock
            //
            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);

            //
            // These pages are now available, clear their availablity bits
            //
            EndAllocation = (MmPagedPoolInfo.NextPdeForPagedPoolExpansion -
                             (PMMPDE)MiAddressToPte(MmPagedPoolInfo.FirstPteForPagedPool)) *
                             PTE_COUNT;
            RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap,
                         EndAllocation,
                         PageTableCount * PTE_COUNT);

            //
            // Update the next expansion location
            //
            MmPagedPoolInfo.NextPdeForPagedPoolExpansion += PageTableCount;

            //
            // Zero out the newly available memory
            //
            RtlZeroMemory(BaseVaStart, PageTableCount * PAGE_SIZE);

            //
            // Now try consuming the pages again
            //
            i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap,
                                       SizeInPages,
                                       0);
            if (i == 0xFFFFFFFF)
            {
                //
                // Out of memory!
                //
                DPRINT1("OUT OF PAGED POOL!!!\n");
                KeReleaseGuardedMutex(&MmPagedPoolMutex);
                return NULL;
            }
        }

        //
        // Update the pool hint if the request was just one page
        //
        if (SizeInPages == 1) MmPagedPoolInfo.PagedPoolHint = i + 1;

        //
        // Update the end bitmap so we know the bounds of this allocation when
        // the time comes to free it
        //
        EndAllocation = i + SizeInPages - 1;
        RtlSetBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, EndAllocation);

        //
        // Now we can release the lock (it mainly protects the bitmap)
        //
        KeReleaseGuardedMutex(&MmPagedPoolMutex);

        //
        // Now figure out where this allocation starts
        //
        BaseVa = (PVOID)((ULONG_PTR)MmPagedPoolStart + (i << PAGE_SHIFT));

        //
        // Flush the TLB
        //
        KeFlushEntireTb(TRUE, TRUE);

        /* Setup a demand-zero writable PTE */
        MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);

        //
        // Find the first and last PTE, then loop them all
        //
        PointerPte = MiAddressToPte(BaseVa);
        StartPte = PointerPte + SizeInPages;
        do
        {
            //
            // Write the demand zero PTE and keep going
            //
            MI_WRITE_INVALID_PTE(PointerPte, TempPte);
        } while (++PointerPte < StartPte);

        //
        // Return the allocation address to the caller
        //
        return BaseVa;
    }

    //
    // Allocations of less than 4 pages go into their individual buckets
    //
    i = SizeInPages - 1;
    if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;

    //
    // Loop through all the free page lists based on the page index
    //
    NextHead = &MmNonPagedPoolFreeListHead[i];
    LastHead = &MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS];

    //
    // Acquire the nonpaged pool lock
    //
    OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock);
    do
    {
        //
        // Now loop through all the free page entries in this given list
        //
        NextEntry = NextHead->Flink;
        while (NextEntry != NextHead)
        {
            /* Is freed non paged pool enabled */
            if (MmProtectFreedNonPagedPool)
            {
                /* We need to be able to touch this page, unprotect it */
                MiUnProtectFreeNonPagedPool(NextEntry, 0);
            }

            //
            // Grab the entry and see if it can handle our allocation
            //
            FreeEntry = CONTAINING_RECORD(NextEntry, MMFREE_POOL_ENTRY, List);
            ASSERT(FreeEntry->Signature == MM_FREE_POOL_SIGNATURE);
            if (FreeEntry->Size >= SizeInPages)
            {
                //
                // It does, so consume the pages from here
                //
                FreeEntry->Size -= SizeInPages;

                //
                // The allocation will begin in this free page area
                //
                BaseVa = (PVOID)((ULONG_PTR)FreeEntry +
                                 (FreeEntry->Size  << PAGE_SHIFT));

                /* Remove the item from the list, depending if pool is protected */
                MmProtectFreedNonPagedPool ?
                    MiProtectedPoolRemoveEntryList(&FreeEntry->List) :
                    RemoveEntryList(&FreeEntry->List);

                //
                // However, check if its' still got space left
                //
                if (FreeEntry->Size != 0)
                {
                    /* Check which list to insert this entry into */
                    i = FreeEntry->Size - 1;
                    if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;

                    /* Insert the entry into the free list head, check for prot. pool */
                    MmProtectFreedNonPagedPool ?
                        MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) :
                        InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List);

                    /* Is freed non paged pool protected? */
                    if (MmProtectFreedNonPagedPool)
                    {
                        /* Protect the freed pool! */
                        MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size);
                    }
                }

                //
                // Grab the PTE for this allocation
                //
                PointerPte = MiAddressToPte(BaseVa);
                ASSERT(PointerPte->u.Hard.Valid == 1);

                //
                // Grab the PFN NextEntry and index
                //
                Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));

                //
                // Now mark it as the beginning of an allocation
                //
                ASSERT(Pfn1->u3.e1.StartOfAllocation == 0);
                Pfn1->u3.e1.StartOfAllocation = 1;

                /* Mark it as special pool if needed */
                ASSERT(Pfn1->u4.VerifierAllocation == 0);
                if (PoolType & 64) Pfn1->u4.VerifierAllocation = 1;

                //
                // Check if the allocation is larger than one page
                //
                if (SizeInPages != 1)
                {
                    //
                    // Navigate to the last PFN entry and PTE
                    //
                    PointerPte += SizeInPages - 1;
                    ASSERT(PointerPte->u.Hard.Valid == 1);
                    Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
                }

                //
                // Mark this PFN as the last (might be the same as the first)
                //
                ASSERT(Pfn1->u3.e1.EndOfAllocation == 0);
                Pfn1->u3.e1.EndOfAllocation = 1;

                //
                // Release the nonpaged pool lock, and return the allocation
                //
                KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
                return BaseVa;
            }

            //
            // Try the next free page entry
            //
            NextEntry = FreeEntry->List.Flink;

            /* Is freed non paged pool protected? */
            if (MmProtectFreedNonPagedPool)
            {
                /* Protect the freed pool! */
                MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size);
            }
        }
    } while (++NextHead < LastHead);

    //
    // If we got here, we're out of space.
    // Start by releasing the lock
    //
    KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);

    //
    // Allocate some system PTEs
    //
    StartPte = MiReserveSystemPtes(SizeInPages, NonPagedPoolExpansion);
    PointerPte = StartPte;
    if (StartPte == NULL)
    {
        //
        // Ran out of memory
        //
        DPRINT1("Out of NP Expansion Pool\n");
        return NULL;
    }

    //
    // Acquire the pool lock now
    //
    OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock);

    //
    // Lock the PFN database too
    //
    LockQueue = &KeGetCurrentPrcb()->LockQueue[LockQueuePfnLock];
    KeAcquireQueuedSpinLockAtDpcLevel(LockQueue);

    //
    // Loop the pages
    //
    TempPte = ValidKernelPte;
    do
    {
        /* Allocate a page */
        MI_SET_USAGE(MI_USAGE_PAGED_POOL);
        MI_SET_PROCESS2("Kernel");
        PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR());

        /* Get the PFN entry for it and fill it out */
        Pfn1 = MiGetPfnEntry(PageFrameNumber);
        Pfn1->u3.e2.ReferenceCount = 1;
        Pfn1->u2.ShareCount = 1;
        Pfn1->PteAddress = PointerPte;
        Pfn1->u3.e1.PageLocation = ActiveAndValid;
        Pfn1->u4.VerifierAllocation = 0;

        /* Write the PTE for it */
        TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
        MI_WRITE_VALID_PTE(PointerPte++, TempPte);
    } while (--SizeInPages > 0);

    //
    // This is the last page
    //
    Pfn1->u3.e1.EndOfAllocation = 1;

    //
    // Get the first page and mark it as such
    //
    Pfn1 = MiGetPfnEntry(StartPte->u.Hard.PageFrameNumber);
    Pfn1->u3.e1.StartOfAllocation = 1;

    /* Mark it as a verifier allocation if needed */
    ASSERT(Pfn1->u4.VerifierAllocation == 0);
    if (PoolType & 64) Pfn1->u4.VerifierAllocation = 1;

    //
    // Release the PFN and nonpaged pool lock
    //
    KeReleaseQueuedSpinLockFromDpcLevel(LockQueue);
    KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);

    //
    // Return the address
    //
    return MiPteToAddress(StartPte);
}
//
// Destroy (dereference) the WDFFILEOBJECT related to the
// WDM PFILE_OBJECT according to its FileObjectClass.
//
VOID
FxFileObject::_DestroyFileObject(
    __in FxDevice*                   pDevice,
    __in WDF_FILEOBJECT_CLASS        FileObjectClass,
    __in_opt MdFileObject            pWdmFileObject
    )
{
    FxFileObject* pfo = NULL;
    PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
    WDF_FILEOBJECT_CLASS normalizedFileClass;
    
    //
    // Close does require a WDM file obj based on the normalized file obj 
    // class value.
    //
    normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);

    if( normalizedFileClass == WdfFileObjectNotRequired ) {
        return;
    }

    //
    // Driver has specified file object support, and we
    // allocated one at Create, so they must pass one
    // to close, otherwise it's an error and we will leak
    // the file object.
    //
    MxFileObject wdmFileObject(pWdmFileObject);
    if( pWdmFileObject == NULL && 
        normalizedFileClass != WdfFileObjectWdfCannotUseFsContexts) {

        //
        // It's likely that IRP_MJ_CREATE had NULL for the Wdm FileObject as well.
        //
        // If a driver passes != NULL for Wdm FileObject to create, and NULL to
        // this routine, a WDF FxFileObject object leak will occur, which will
        // be reported at driver unload.
        //
        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
           "PFILE_OBJECT in close IRP is NULL, *Possible Leak of FxFileObject*\n");

        FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());

        return;
    }
    else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) {
        pfo = (FxFileObject*)wdmFileObject.GetFsContext();
        wdmFileObject.SetFsContext(NULL);
        
    }
    else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) {
        pfo = (FxFileObject*)wdmFileObject.GetFsContext2();
        wdmFileObject.SetFsContext2(NULL);
    }
    else {
        NTSTATUS status;
        //
        // We must find the associated FxFileObject from the list
        // on the device
        //
        status = FxFileObject::_GetFileObjectFromWdm(
                          pDevice,
                          WdfFileObjectWdfCannotUseFsContexts,
                          pWdmFileObject,
                          &pfo
                          );
        
        //
        // We should find it, unless a different one was passed to IRP_MJ_CLOSE
        // than to IRP_MJ_CREATE, which is an error.
        //
        if (NT_SUCCESS(status) == FALSE || pfo == NULL) {
            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "Could not find WDFFILEOBJECT for PFILE_OBJECT 0x%p",
                                pWdmFileObject);

            DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
                            "Did a different PFILE_OBJECT get passed to "
                            "IRP_MJ_CLOSE than did to IRP_MJ_CREATE?");
            FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
        }
    }

    if( pfo != NULL ) {
        KIRQL irql;

        //
        // Remove it from the list of FxFileObjects on the FxDevice
        //
        pDevice->Lock(&irql);
        RemoveEntryList(&pfo->m_Link);
        pDevice->Unlock(irql);

        // Delete the file object
        pfo->DeleteObject();
    }

    return;
}
示例#5
0
NTSTATUS
TdiHandleSerializedRequest (
	PVOID		RequestInfo,
	UINT		RequestType
)

/*++

Routine Description:

	Called when we want to process a request relating to one of the
	lists we manage. We look to see if we are currently processing such
	a request - if we are, we queue this for later. Otherwise we'll
	remember that we are doing this, and we'll process this request.
	When we're done we'll look to see if any more came in while we were
	busy.

Arguments:

	RequestInfo			- Reqeust specific information.
	RequestType			- The type of the request.

Return Value:

	Request completion status.


--*/

{
	KIRQL					OldIrql;
	PLIST_ENTRY				List;
	PLIST_ENTRY				ClientList;
	PLIST_ENTRY				ProviderList;
	PLIST_ENTRY				RequestList;
	PBOOLEAN				SerializeFlag;
	PETHREAD				*RequestThread;
	PTDI_SERIALIZED_REQUEST	Request;
	PKEVENT					BlockedEvent = NULL;
	PTDI_NOTIFY_COMMON		NotifyElement;
	PTDI_PROVIDER_RESOURCE	ProviderElement;

	ExAcquireSpinLock(
					&TDIListLock,
					&OldIrql
					);

	if (RequestType <= TDI_MAX_BIND_REQUEST) {
		ClientList = &BindClientList;
		ProviderList = &BindProviderList;
		RequestList = &BindRequestList;
		SerializeFlag = &BindRequestInProgress;
		RequestThread = &BindRequestThread;
	} else {
		ClientList = &NetAddressClientList;
		ProviderList = &NetAddressProviderList;
		RequestList = &NetAddressRequestList;
		SerializeFlag = &AddressRequestInProgress;
		RequestThread = &AddressRequestThread;
	}

	// If we're not already here, handle it right away.

	if (!(*SerializeFlag)) {

		*SerializeFlag = TRUE;

		// Save the identity of the thread we're doing this in in case someone
		// tries to delete a client, which needs to block. In that case we'll
		// check to make sure it's not being done in the same thread we're using
		// to prevent deadlock.

		*RequestThread = PsGetCurrentThread();

		for (;;) {

			// We're done with the lock for now, so free it.

			ExReleaseSpinLock(
							&TDIListLock,
							OldIrql
							);

			// Figure out the type of request we have here.

			switch (RequestType) {
			case TDI_REGISTER_BIND_NOTIFY:
			case TDI_REGISTER_ADDRESS_NOTIFY:
				// This is a client register bind or address handler request.

				// Insert this one into the registered client list.
				NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
				InsertTailList(
							ClientList,
							&NotifyElement->Linkage,
							);

				// Call TdiNotifyNewClient to notify this new client of all
				// all existing providers.

				TdiNotifyNewClient(
							ProviderList,
							RequestInfo
							);

				break;

			case TDI_DEREGISTER_BIND_NOTIFY:
			case TDI_DEREGISTER_ADDRESS_NOTIFY:

				// This is a client deregister request. Pull him from the
				// client list, free it, and we're done.

				NotifyElement = (PTDI_NOTIFY_COMMON)RequestInfo;
				RemoveEntryList(&NotifyElement->Linkage);

				ExFreePool(NotifyElement);

				break;

			case TDI_REGISTER_DEVICE:
			case TDI_REGISTER_ADDRESS:

				// A provider is registering a device or address. Add him to
				// the appropriate provider list, and then notify all
				// existing clients of the new device.

				ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo;

				InsertTailList(
							ProviderList,
							&ProviderElement->Common.Linkage
							);

				// Call TdiNotifyClientList to do the hard work.

				TdiNotifyClientList(
							ClientList,
							RequestInfo,
							TRUE
							);
				break;

			case TDI_DEREGISTER_DEVICE:
			case TDI_DEREGISTER_ADDRESS:

				// A provider device or address is deregistering. Pull the
				// resource from the provider list, and notify clients that
				// he's gone.

				ProviderElement = (PTDI_PROVIDER_RESOURCE)RequestInfo;
				RemoveEntryList(&ProviderElement->Common.Linkage);

				TdiNotifyClientList(
							ClientList,
							RequestInfo,
							FALSE
							);

				// Free the tracking structure we had.

				if (RequestType == TDI_DEREGISTER_DEVICE) {
					ExFreePool(ProviderElement->Specific.Device.DeviceName.Buffer);
				}
				ExFreePool(ProviderElement);

				break;
			default:
				break;
			}

			// If there was an event specified with this request, signal
			// it now. This should only be a client deregister request, which
			// needs to block until it's completed.

			if (BlockedEvent != NULL) {
                KeSetEvent(BlockedEvent, 0, FALSE);
			}

			// Get the lock, and see if more requests have come in while
			// we've been busy. If they have, we'll service them now, otherwise
			// we'll clear the in progress flag and exit.

			ExAcquireSpinLock(
							&TDIListLock,
							&OldIrql
							);

			if (!IsListEmpty(RequestList)) {

				// The request list isn't empty. Pull the next one from
				// the list and process it.

				List = RemoveHeadList(RequestList);

				Request = CONTAINING_RECORD(List, TDI_SERIALIZED_REQUEST, Linkage);

				RequestInfo = Request->Element;
				RequestType = Request->Type;
				BlockedEvent = Request->Event;

				ExFreePool(Request);

			} else {

				// The request list is empty. Clear the flag and we're done.

				*SerializeFlag = FALSE;

				ExReleaseSpinLock(
								&TDIListLock,
								OldIrql
								);
				break;
			}
		}

		return STATUS_SUCCESS;
	} else {
示例#6
0
/**
  Remove the block number from the block range list.

  @param  Head                  The block range list to remove from
  @param  Num                   The block number to remove
  @param  Completed             Whether Num is the last block number
  @param  TotalBlock            The continuous block number in all 

  @retval EFI_NOT_FOUND         The block number isn't in the block range list
  @retval EFI_SUCCESS           The block number has been removed from the list
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource

**/
EFI_STATUS
Mtftp4RemoveBlockNum (
  IN LIST_ENTRY             *Head,
  IN UINT16                 Num,
  IN BOOLEAN                Completed,
  OUT UINT64                *TotalBlock
  )
{
  MTFTP4_BLOCK_RANGE        *Range;
  MTFTP4_BLOCK_RANGE        *NewRange;
  LIST_ENTRY                *Entry;

  NET_LIST_FOR_EACH (Entry, Head) {

    //
    // Each block represents a hole [Start, End] in the file,
    // skip to the first range with End >= Num
    //
    Range = NET_LIST_USER_STRUCT (Entry, MTFTP4_BLOCK_RANGE, Link);

    if (Range->End < Num) {
      continue;
    }

    //
    // There are three different cases for Start
    // 1. (Start > Num) && (End >= Num):
    //    because all the holes before this one has the condition of
    //    End < Num, so this block number has been removed.
    //
    // 2. (Start == Num) && (End >= Num):
    //    Need to increase the Start by one, and if End == Num, this
    //    hole has been removed completely, remove it.
    //
    // 3. (Start < Num) && (End >= Num):
    //    if End == Num, only need to decrease the End by one because
    //    we have (Start < Num) && (Num == End), so (Start <= End - 1).
    //    if (End > Num), the hold is splited into two holes, with
    //    [Start, Num - 1] and [Num + 1, End].
    //
    if (Range->Start > Num) {
      return EFI_NOT_FOUND;

    } else if (Range->Start == Num) {
      Range->Start++;

      //
      // Note that: RFC 1350 does not mention block counter roll-over, 
      // but several TFTP hosts implement the roll-over be able to accept 
      // transfers of unlimited size. There is no consensus, however, whether 
      // the counter should wrap around to zero or to one. Many implementations 
      // wrap to zero, because this is the simplest to implement. Here we choose 
      // this solution.
      //
	  *TotalBlock  = Num;
	  
      if (Range->Round > 0) {
	    *TotalBlock += Range->Bound +  MultU64x32 ((UINTN) (Range->Round -1), (UINT32) (Range->Bound + 1)) + 1;
	  }

      if (Range->Start > Range->Bound) {
	  	  Range->Start = 0;
		  Range->Round ++;
      }

      if ((Range->Start > Range->End) || Completed) {
        RemoveEntryList (&Range->Link);
        FreePool (Range);
      }

      return EFI_SUCCESS;

    } else {
      if (Range->End == Num) {
        Range->End--;
      } else {
        NewRange = Mtftp4AllocateRange ((UINT16) (Num + 1), (UINT16) Range->End);

        if (NewRange == NULL) {
          return EFI_OUT_OF_RESOURCES;
        }

        Range->End = Num - 1;
        NetListInsertAfter (&Range->Link, &NewRange->Link);
      }

      return EFI_SUCCESS;
    }
  }
示例#7
0
NTSTATUS
MsCleanupCcb (
    IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
    IN PIRP Irp,
    IN PCCB Ccb
    )

/*++

Routine Description:

    The routine cleans up a CCB.

Arguments:

    MsfsDeviceObject - A pointer the the mailslot file system device object.

    Irp - Supplies the IRP associated with the cleanup.

    Ccb - Supplies the CCB for the mailslot to clean up.

Return Value:

    NTSTATUS - An appropriate completion status

--*/
{
    NTSTATUS status;
    PFCB fcb;

    PAGED_CODE();
    DebugTrace(+1, Dbg, "MsCleanupCcb...\n", 0);

    //
    // Get a pointer to the FCB.
    //

    fcb = Ccb->Fcb;

    //
    // Acquire exclusive access to the FCB
    //

    MsAcquireExclusiveFcb( fcb );

    status = STATUS_SUCCESS;

    try {

        //
        // Ensure that this CCB still belongs to an active open mailslot.
        //

        MsVerifyCcb( Ccb );

        //
        // Set the CCB to closing and remove this CCB from the active list.
        //

        Ccb->Header.NodeState = NodeStateClosing;
        RemoveEntryList( &Ccb->CcbLinks );

        //
        // Cleanup the share access.
        //

        IoRemoveShareAccess( Ccb->FileObject, &fcb->ShareAccess );

   } finally {

        MsReleaseFcb( fcb );
        DebugTrace(-1, Dbg, "MsCloseFcb -> %08lx\n", status);
    }

    //
    // And return to our caller
    //

    return status;
}
示例#8
0
ARC_STATUS
BlLoadDeviceDriver (
    IN ULONG DeviceId,
    IN PCHAR LoadDevice,
    IN PCHAR DirectoryPath,
    IN PCHAR DriverName,
    IN ULONG DriverFlags,
    OUT PLDR_DATA_TABLE_ENTRY *DriverDataTableEntry
    )

/*++

Routine Description:

    This routine loads the specified device driver and resolves all DLL
    references if the driver is not already loaded.

Arguments:

    DeviceId - Supplies the file id of the device on which the specified
        device driver is loaded from.

    LoadDevice - Supplies a pointer to a zero terminated load device
        string.

    DirectoryPath - Supplies a pointer to a zero terminated directory
        path string.

    DriverName - Supplies a pointer to a zero terminated device driver
        name string.

    DriverFlags - Supplies the driver flags that are to be set in the
        generated data table entry.

    DriverDataTableEntry - Receives a pointer to the data table entry
        created for the newly-loaded driver.

Return Value:

    ESUCCESS is returned if the specified driver is successfully loaded
    or it is already loaded. Otherwise, and unsuccessful status is
    returned.

--*/

{

    CHAR DllName[256];
    CHAR FullName[256];
    PVOID Base;
    ARC_STATUS Status;

    //
    // Generate the DLL name for the device driver.
    //

    strcpy(&DllName[0], DriverName);

    //
    // If the specified device driver is not already loaded, then load it.
    //

    if (BlCheckForLoadedDll(&DllName[0], DriverDataTableEntry) == FALSE) {

        //
        // Generate the full path name of device driver.
        //

        strcpy(&FullName[0], &DirectoryPath[0]);
        strcat(&FullName[0], DriverName);
        BlOutputLoadMessage(LoadDevice, &FullName[0]);
        Status = BlLoadImage(DeviceId,
                             LoaderBootDriver,
                             &FullName[0],
                             TARGET_IMAGE,
                             &Base);

        if (Status != ESUCCESS) {
            return Status;
        }

        //
        // Generate a data table entry for the driver, then clear the entry
        // processed flag. The I/O initialization code calls each DLL in the
        // loaded module list that does not have its entry processed flag set.
        //

        Status = BlAllocateDataTableEntry(&DllName[0],
                                          DriverName,
                                          Base,
                                          DriverDataTableEntry);

        if (Status != ESUCCESS) {
            return Status;
        }

        (*DriverDataTableEntry)->Flags |= DriverFlags;

        //
        // Scan the import table and load all the referenced DLLs.
        //

        Status = BlScanImportDescriptorTable(DeviceId,
                                             LoadDevice,
                                             &DirectoryPath[0],
                                             *DriverDataTableEntry);

        if (Status != ESUCCESS) {
            //
            // Remove the driver from the load order list.
            //
            RemoveEntryList(&(*DriverDataTableEntry)->InLoadOrderLinks);
            return Status;
        }

    }
    return ESUCCESS;
}
示例#9
0
VOID
WSAAPI
WsTcUpdateProtocolList(IN PTCATALOG Catalog,
                       IN PLIST_ENTRY List)
{
    LIST_ENTRY TempList;
    PTCATALOG_ENTRY CatalogEntry, OldCatalogEntry;
    PLIST_ENTRY Entry;

    /* First move from our list to the old one */
    InsertHeadList(&Catalog->ProtocolList, &TempList);
    RemoveEntryList(&Catalog->ProtocolList);
    InitializeListHead(&Catalog->ProtocolList);

    /* Loop every item on the list */
    while (!IsListEmpty(List))
    {
        /* Get the catalog entry */
        Entry = RemoveHeadList(List);
        CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);

        /* Check if this item is already on our list */
        Entry = TempList.Flink;
        while (Entry != &TempList)
        {
            /* Get the catalog entry */
            OldCatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
            Entry = Entry->Flink;

            /* Check if they match */
            if (CatalogEntry->ProtocolInfo.dwCatalogEntryId ==
                OldCatalogEntry->ProtocolInfo.dwCatalogEntryId)
            {
                /* We have a match, use the old item instead */
                WsTcEntryDereference(CatalogEntry);
                CatalogEntry = OldCatalogEntry;
                RemoveEntryList(&CatalogEntry->CatalogLink);

                /* Decrease the number of protocols we have */
                Catalog->ItemCount--;
                break;
            }
        }

        /* Add this item */
        InsertTailList(&Catalog->ProtocolList, &CatalogEntry->CatalogLink);
        Catalog->ItemCount++;
    }

    /* If there's anything left on the temporary list */
    while (!IsListEmpty(&TempList))
    {
        /* Get the entry */
        Entry = RemoveHeadList(&TempList);
        CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);

        /* Remove it */
        Catalog->ItemCount--;
        WsTcEntryDereference(CatalogEntry);
    }
}
示例#10
0
/**
  Stops a device controller or a bus controller.

  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
  As a result, much of the error checking on the parameters to Stop() has been moved
  into this common boot service. It is legal to call Stop() from other locations,
  but the following calling restrictions must be followed or the system behavior will not be deterministic.
  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
     same driver's Start() function.
  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
     EFI_HANDLE. In addition, all of these handles must have been created in this driver's
     Start() function, and the Start() function must have called OpenProtocol() on
     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.

  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
                                support a bus specific I/O protocol for the driver
                                to use to stop the device.
  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
                                if NumberOfChildren is 0.

  @retval EFI_SUCCESS           The device was stopped.
  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.

**/
EFI_STATUS
EFIAPI
SdDxeDriverBindingStop (
  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
  IN  EFI_HANDLE                      Controller,
  IN  UINTN                           NumberOfChildren,
  IN  EFI_HANDLE                      *ChildHandleBuffer
  )
{
  EFI_STATUS                          Status;
  BOOLEAN                             AllChildrenStopped;
  UINTN                               Index;
  SD_DRIVER_PRIVATE_DATA              *Private;
  SD_DEVICE                           *Device;
  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
  EFI_BLOCK_IO2_PROTOCOL              *BlockIo2;
  EFI_BLOCK_IO_PROTOCOL               *BlockIo;
  LIST_ENTRY                          *Link;
  LIST_ENTRY                          *NextLink;
  SD_REQUEST                          *Request;
  EFI_TPL                             OldTpl;

  if (NumberOfChildren == 0) {
    Status = gBS->OpenProtocol (
                    Controller,
                    &gEfiCallerIdGuid,
                    (VOID **) &Private,
                    This->DriverBindingHandle,
                    Controller,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (EFI_ERROR (Status)) {
      return EFI_DEVICE_ERROR;
    }

    gBS->UninstallProtocolInterface (
          Controller,
          &gEfiCallerIdGuid,
          Private
          );
    gBS->CloseProtocol (
          Controller,
          &gEfiSdMmcPassThruProtocolGuid,
          This->DriverBindingHandle,
          Controller
          );

    FreePool (Private);

    return EFI_SUCCESS;
  }

  AllChildrenStopped = TRUE;

  for (Index = 0; Index < NumberOfChildren; Index++) {
    BlockIo  = NULL;
    BlockIo2 = NULL;
    Status = gBS->OpenProtocol (
                    ChildHandleBuffer[Index],
                    &gEfiBlockIoProtocolGuid,
                    (VOID **) &BlockIo,
                    This->DriverBindingHandle,
                    Controller,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (EFI_ERROR (Status)) {
      Status = gBS->OpenProtocol (
                      ChildHandleBuffer[Index],
                      &gEfiBlockIo2ProtocolGuid,
                      (VOID **) &BlockIo2,
                      This->DriverBindingHandle,
                      Controller,
                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
                      );
      if (EFI_ERROR (Status)) {
        AllChildrenStopped = FALSE;
        continue;
      }
    }

    if (BlockIo != NULL) {
      Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);
    } else {
      ASSERT (BlockIo2 != NULL);
      Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2);
    }

    //
    // Free all on-going async tasks.
    //
    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    for (Link = GetFirstNode (&Device->Queue);
         !IsNull (&Device->Queue, Link);
         Link = NextLink) {
      NextLink = GetNextNode (&Device->Queue, Link);
      RemoveEntryList (Link);

      Request = SD_REQUEST_FROM_LINK (Link);

      gBS->CloseEvent (Request->Event);
      Request->Token->TransactionStatus = EFI_ABORTED;

      if (Request->IsEnd) {
        gBS->SignalEvent (Request->Token->Event);
      }

      FreePool (Request);
    }
    gBS->RestoreTPL (OldTpl);

    //
    // Close the child handle
    //
    Status = gBS->CloseProtocol (
                    Controller,
                    &gEfiSdMmcPassThruProtocolGuid,
                    This->DriverBindingHandle,
                    ChildHandleBuffer[Index]
                    );

    Status = gBS->UninstallMultipleProtocolInterfaces (
                    ChildHandleBuffer[Index],
                    &gEfiDevicePathProtocolGuid,
                    Device->DevicePath,
                    &gEfiBlockIoProtocolGuid,
                    &Device->BlockIo,
                    &gEfiBlockIo2ProtocolGuid,
                    &Device->BlockIo2,
                    &gEfiEraseBlockProtocolGuid,
                    &Device->EraseBlock,
                    NULL
                    );
    if (EFI_ERROR (Status)) {
      AllChildrenStopped = FALSE;
        gBS->OpenProtocol (
               Controller,
               &gEfiSdMmcPassThruProtocolGuid,
               (VOID **)&PassThru,
               This->DriverBindingHandle,
               ChildHandleBuffer[Index],
               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
               );
    } else {
      FreePool (Device->DevicePath);
      FreeUnicodeStringTable (Device->ControllerNameTable);
      FreePool (Device);
    }
  }

  if (!AllChildrenStopped) {
    return EFI_DEVICE_ERROR;
  }

  return EFI_SUCCESS;
}
示例#11
0
文件: timer.c 项目: GYGit/reactos
VOID
NTAPI
ExTimerRundown(VOID)
{
    PETHREAD Thread = PsGetCurrentThread();
    KIRQL OldIrql;
    PLIST_ENTRY CurrentEntry;
    PETIMER Timer;
    ULONG DerefsToDo;

    /* Lock the Thread's Active Timer List and loop it */
    KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
    CurrentEntry = Thread->ActiveTimerListHead.Flink;
    while (CurrentEntry != &Thread->ActiveTimerListHead)
    {
        /* Get the timer */
        Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry);

        /* Reference it */
        ObReferenceObject(Timer);
        DerefsToDo = 1;

        /* Unlock the list */
        KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);

        /* Lock the Timer */
        KeAcquireSpinLock(&Timer->Lock, &OldIrql);

        /* Lock the list again */
        KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock);

        /* Make sure that the timer is valid */
        if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread))
        {
            /* Remove it from the list */
            RemoveEntryList(&Timer->ActiveTimerListEntry);
            Timer->ApcAssociated = FALSE;

            /* Cancel the timer and remove its DPC and APC */
            KeCancelTimer(&Timer->KeTimer);
            KeRemoveQueueDpc(&Timer->TimerDpc);
            if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo++;

            /* Add another dereference to do */
            DerefsToDo++;
        }

        /* Unlock the list */
        KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock);

        /* Unlock the Timer */
        KeReleaseSpinLock(&Timer->Lock, OldIrql);

        /* Dereference it */
        ObDereferenceObjectEx(Timer, DerefsToDo);

        /* Loop again */
        KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql);
        CurrentEntry = Thread->ActiveTimerListHead.Flink;
    }

    /* Release lock and return */
    KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql);
}
示例#12
0
文件: smsesnid.c 项目: mingpen/OpenNT
VOID
SmpDeleteSession(
    IN ULONG SessionId,
    IN BOOLEAN SendSessionComplete,
    IN NTSTATUS SessionStatus
    )

/*++

Routine Description:

    This function locates and deletes a session id.  If the
    SendSessionComplete flag is true, then it also sends a session
    complete message to the creator subsystem.

Arguments:

    SessionId - Supplies the session id to delete.

    SendSessionComplete - Specifies whether a session complete message
        is to be sent to the creator subsystem (if one exists).

    SessionStatus - Supplies the session completion status


Return Value:


--*/

{

    PSMPSESSION Session;
    PSMPKNOWNSUBSYS CreatorSubsystem;

    RtlEnterCriticalSection(&SmpSessionListLock);

    Session = SmpSessionIdToSession(SessionId);

    if ( Session ) {

        RemoveEntryList(&Session->SortedSessionIdListLinks);


        RtlLeaveCriticalSection(&SmpSessionListLock);

        CreatorSubsystem = Session->CreatorSubsystem;

        RtlFreeHeap(SmpHeap,0,Session);

        //
        // If there is a creator subsystem, and if
        // told to send a session complete message, then do it.
        //

        if ( CreatorSubsystem && SendSessionComplete ) {

            //
            // Foreign Session Complete
            //
        }

    } else {

        RtlLeaveCriticalSection(&SmpSessionListLock);
    }

    return;


    //
    // Make the compiler happy
    //

    SessionStatus;
}
/**
  Call back function when the timer event is signaled.

  @param[in]  Event     The Event this notify function registered to.
  @param[in]  Context   Pointer to the context data registered to the
                        Event.

**/
VOID
EFIAPI
ProcessAsyncTaskList (
  IN EFI_EVENT                    Event,
  IN VOID*                        Context
  )
{
  NVME_CONTROLLER_PRIVATE_DATA         *Private;
  EFI_PCI_IO_PROTOCOL                  *PciIo;
  NVME_CQ                              *Cq;
  UINT16                               QueueId;
  UINT32                               Data;
  LIST_ENTRY                           *Link;
  LIST_ENTRY                           *NextLink;
  NVME_PASS_THRU_ASYNC_REQ             *AsyncRequest;
  NVME_BLKIO2_SUBTASK                  *Subtask;
  NVME_BLKIO2_REQUEST                  *BlkIo2Request;
  EFI_BLOCK_IO2_TOKEN                  *Token;
  BOOLEAN                              HasNewItem;
  EFI_STATUS                           Status;

  Private    = (NVME_CONTROLLER_PRIVATE_DATA*)Context;
  QueueId    = 2;
  Cq         = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
  HasNewItem = FALSE;
  PciIo      = Private->PciIo;

  //
  // Submit asynchronous subtasks to the NVMe Submission Queue
  //
  for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);
       !IsNull (&Private->UnsubmittedSubtasks, Link);
       Link = NextLink) {
    NextLink      = GetNextNode (&Private->UnsubmittedSubtasks, Link);
    Subtask       = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);
    BlkIo2Request = Subtask->BlockIo2Request;
    Token         = BlkIo2Request->Token;
    RemoveEntryList (Link);
    BlkIo2Request->UnsubmittedSubtaskNum--;

    //
    // If any previous subtask fails, do not process subsequent ones.
    //
    if (Token->TransactionStatus != EFI_SUCCESS) {
      if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&
          BlkIo2Request->LastSubtaskSubmitted &&
          (BlkIo2Request->UnsubmittedSubtaskNum == 0)) {
        //
        // Remove the BlockIo2 request from the device asynchronous queue.
        //
        RemoveEntryList (&BlkIo2Request->Link);
        FreePool (BlkIo2Request);
        gBS->SignalEvent (Token->Event);
      }

      FreePool (Subtask->CommandPacket->NvmeCmd);
      FreePool (Subtask->CommandPacket->NvmeCompletion);
      FreePool (Subtask->CommandPacket);
      FreePool (Subtask);

      continue;
    }

    Status = Private->Passthru.PassThru (
                                 &Private->Passthru,
                                 Subtask->NamespaceId,
                                 Subtask->CommandPacket,
                                 Subtask->Event
                                 );
    if (Status == EFI_NOT_READY) {
      InsertHeadList (&Private->UnsubmittedSubtasks, Link);
      BlkIo2Request->UnsubmittedSubtaskNum++;
      break;
    } else if (EFI_ERROR (Status)) {
      Token->TransactionStatus = EFI_DEVICE_ERROR;

      if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&
          Subtask->IsLast) {
        //
        // Remove the BlockIo2 request from the device asynchronous queue.
        //
        RemoveEntryList (&BlkIo2Request->Link);
        FreePool (BlkIo2Request);
        gBS->SignalEvent (Token->Event);
      }

      FreePool (Subtask->CommandPacket->NvmeCmd);
      FreePool (Subtask->CommandPacket->NvmeCompletion);
      FreePool (Subtask->CommandPacket);
      FreePool (Subtask);
    } else {
      InsertTailList (&BlkIo2Request->SubtasksQueue, Link);
      if (Subtask->IsLast) {
        BlkIo2Request->LastSubtaskSubmitted = TRUE;
      }
    }
  }

  while (Cq->Pt != Private->Pt[QueueId]) {
    ASSERT (Cq->Sqid == QueueId);

    HasNewItem = TRUE;

    //
    // Find the command with given Command Id.
    //
    for (Link = GetFirstNode (&Private->AsyncPassThruQueue);
         !IsNull (&Private->AsyncPassThruQueue, Link);
         Link = NextLink) {
      NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);
      AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);
      if (AsyncRequest->CommandId == Cq->Cid) {
        //
        // Copy the Respose Queue entry for this command to the callers
        // response buffer.
        //
        CopyMem (
          AsyncRequest->Packet->NvmeCompletion,
          Cq,
          sizeof(EFI_NVM_EXPRESS_COMPLETION)
          );

        //
        // Free the resources allocated before cmd submission
        //
        if (AsyncRequest->MapData != NULL) {
          PciIo->Unmap (PciIo, AsyncRequest->MapData);
        }
        if (AsyncRequest->MapMeta != NULL) {
          PciIo->Unmap (PciIo, AsyncRequest->MapMeta);
        }
        if (AsyncRequest->MapPrpList != NULL) {
          PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);
        }
        if (AsyncRequest->PrpListHost != NULL) {
          PciIo->FreeBuffer (
                   PciIo,
                   AsyncRequest->PrpListNo,
                   AsyncRequest->PrpListHost
                   );
        }

        RemoveEntryList (Link);
        gBS->SignalEvent (AsyncRequest->CallerEvent);
        FreePool (AsyncRequest);

        //
        // Update submission queue head.
        //
        Private->AsyncSqHead = Cq->Sqhd;
        break;
      }
    }

    Private->CqHdbl[QueueId].Cqh++;
    if (Private->CqHdbl[QueueId].Cqh > NVME_ASYNC_CCQ_SIZE) {
      Private->CqHdbl[QueueId].Cqh = 0;
      Private->Pt[QueueId] ^= 1;
    }

    Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
  }

  if (HasNewItem) {
    Data  = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);
    PciIo->Mem.Write (
                 PciIo,
                 EfiPciIoWidthUint32,
                 NVME_BAR,
                 NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),
                 1,
                 &Data
                 );
  }
}
示例#14
0
文件: dbgapsup.c 项目: mingpen/OpenNT
PDBGP_APP_THREAD
DbgpLocateStateChangeApp(
    IN PDBGP_USER_INTERFACE UserInterface,
    OUT PDBG_STATE PreviousState
    )

/*++

Routine Description:

    This routine scans the specified user interface's application list
    looking for an application whose state has changed.  If an
    application whose State is not DbgIdle or DbgReplyPending is found,
    its address is returned.

Arguments:

    UserInterface - Supplies the address of UserInterface whose
        application list is to be scanned.

    PreviousState - Supplies the address of a variable that returns
        the previous debug state of an application thread reporting
        a state change.

Return Value:

    NULL - No application thread reporting a state change could be located.

    NON-NULL - Returns the address of the application thread reporting a state
        change.

--*/

{
    PLIST_ENTRY HeadProcess, NextProcess;
    PLIST_ENTRY HeadThread, NextThread;
    PDBGP_APP_THREAD AppThread;
    PDBGP_APP_PROCESS AppProcess;

    RtlEnterCriticalSection(&UserInterface->UserInterfaceLock);

    HeadProcess = &UserInterface->AppProcessListHead;
    NextProcess = HeadProcess->Flink;

    while ( NextProcess != HeadProcess ) {

        //
        // For each process managed by the user interface,
        // scan its thread list
        //

        AppProcess = CONTAINING_RECORD(NextProcess,DBGP_APP_PROCESS,AppLinks);

        HeadThread = &AppProcess->AppThreadListHead;
        NextThread = HeadThread->Flink;

        while ( NextThread != HeadThread ) {
            AppThread = CONTAINING_RECORD(NextThread,DBGP_APP_THREAD,AppLinks);
            if ( DBGP_REPORTING_STATE_CHANGE(AppThread) ) {
                *PreviousState = AppThread->CurrentState;
                AppThread->ContinueState = AppThread->CurrentState;
                AppThread->CurrentState = DbgReplyPending;

                //
                // Reshuffle so that this thread is placed
                // at front of list for process, and so that
                // process is placed at front of list for
                // user interface
                //

                RemoveEntryList(&AppThread->AppLinks);
                InsertHeadList(
                    &AppProcess->AppThreadListHead,
                    &AppThread->AppLinks
                    );

                RemoveEntryList(&AppProcess->AppLinks);
                InsertHeadList(
                    &UserInterface->AppProcessListHead,
                    &AppProcess->AppLinks
                    );

                RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock);
//DbgpDumpAppThread(AppThread);
                return AppThread;
            }
            NextThread = NextThread->Flink;
        }

        NextProcess = NextProcess->Flink;
    }

    RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock);
    return NULL;
}
示例#15
0
/**
  Update memory profile Free information.

  @param CallerAddress  Address of caller who call Free.
  @param Action         This Free action.
  @param Size           Buffer size.
  @param Buffer         Buffer address.

  @retval TRUE          Profile udpate success.
  @retval FALSE         Profile update fail.

**/
BOOLEAN
CoreUpdateProfileFree (
  IN PHYSICAL_ADDRESS       CallerAddress,
  IN MEMORY_PROFILE_ACTION  Action,
  IN UINTN                  Size,
  IN VOID                   *Buffer
  )
{
  MEMORY_PROFILE_CONTEXT           *Context;
  MEMORY_PROFILE_DRIVER_INFO       *DriverInfo;
  MEMORY_PROFILE_ALLOC_INFO        *AllocInfo;
  MEMORY_PROFILE_CONTEXT_DATA      *ContextData;
  MEMORY_PROFILE_DRIVER_INFO_DATA  *DriverInfoData;
  LIST_ENTRY                       *DriverLink;
  LIST_ENTRY                       *DriverInfoList;
  MEMORY_PROFILE_DRIVER_INFO_DATA  *ThisDriverInfoData;
  MEMORY_PROFILE_ALLOC_INFO_DATA   *AllocInfoData;
  EFI_MEMORY_TYPE                  ProfileMemoryIndex;

  ContextData = GetMemoryProfileContext ();
  if (ContextData == NULL) {
    return FALSE;
  }

  DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, CallerAddress);
  ASSERT (DriverInfoData != NULL);

  switch (Action) {
    case MemoryProfileActionFreePages:
      AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
      break;
    case MemoryProfileActionFreePool:
      AllocInfoData = GetMemoryProfileAllocInfoFromAddress (DriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
      break;
    default:
      ASSERT (FALSE);
      AllocInfoData = NULL;
      break;
  }
  if (AllocInfoData == NULL) {
    //
    // Legal case, because driver A might free memory allocated by driver B, by some protocol.
    //
    DriverInfoList = ContextData->DriverInfoList;

    for (DriverLink = DriverInfoList->ForwardLink;
         DriverLink != DriverInfoList;
         DriverLink = DriverLink->ForwardLink) {
      ThisDriverInfoData = CR (
                             DriverLink,
                             MEMORY_PROFILE_DRIVER_INFO_DATA,
                             Link,
                             MEMORY_PROFILE_DRIVER_INFO_SIGNATURE
                             );
      switch (Action) {
        case MemoryProfileActionFreePages:
          AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePages, Size, Buffer);
          break;
        case MemoryProfileActionFreePool:
          AllocInfoData = GetMemoryProfileAllocInfoFromAddress (ThisDriverInfoData, MemoryProfileActionAllocatePool, 0, Buffer);
          break;
        default:
          ASSERT (FALSE);
          AllocInfoData = NULL;
          break;
      }
      if (AllocInfoData != NULL) {
        DriverInfoData = ThisDriverInfoData;
        break;
      }
    }

    if (AllocInfoData == NULL) {
      //
      // No matched allocate operation is found for this free operation.
      // It is because the specified memory type allocate operation has been
      // filtered by CoreNeedRecordProfile(), but free operations have no
      // memory type information, they can not be filtered by CoreNeedRecordProfile().
      // Then, they will be filtered here.
      //
      return FALSE;
    }
  }

  Context = &ContextData->Context;
  DriverInfo = &DriverInfoData->DriverInfo;
  AllocInfo = &AllocInfoData->AllocInfo;

  ProfileMemoryIndex = GetProfileMemoryIndex (AllocInfo->MemoryType);

  Context->CurrentTotalUsage -= AllocInfo->Size;
  Context->CurrentTotalUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;

  DriverInfo->CurrentUsage -= AllocInfo->Size;
  DriverInfo->CurrentUsageByType[ProfileMemoryIndex] -= AllocInfo->Size;
  DriverInfo->AllocRecordCount --;

  RemoveEntryList (&AllocInfoData->Link);

  if (Action == MemoryProfileActionFreePages) {
    if (AllocInfo->Buffer != (PHYSICAL_ADDRESS) (UINTN) Buffer) {
      CoreUpdateProfileAllocate (
        AllocInfo->CallerAddress,
        MemoryProfileActionAllocatePages,
        AllocInfo->MemoryType,
        (UINTN) ((PHYSICAL_ADDRESS) (UINTN) Buffer - AllocInfo->Buffer),
        (VOID *) (UINTN) AllocInfo->Buffer
        );
    }
    if (AllocInfo->Buffer + AllocInfo->Size != ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)) {
      CoreUpdateProfileAllocate (
        AllocInfo->CallerAddress,
        MemoryProfileActionAllocatePages,
        AllocInfo->MemoryType,
        (UINTN) ((AllocInfo->Buffer + AllocInfo->Size) - ((PHYSICAL_ADDRESS) (UINTN) Buffer + Size)),
        (VOID *) ((UINTN) Buffer + Size)
        );
    }
  }

  //
  // Use CoreInternalFreePool() that will not update profile for this FreePool action.
  //
  CoreInternalFreePool (AllocInfoData);

  return TRUE;
}
示例#16
0
文件: intobj.c 项目: conioh/os-design
BOOLEAN
KeDisconnectInterrupt (
    IN PKINTERRUPT Interrupt
    )

/*++

Routine Description:

    This function disconnects an interrupt object from the interrupt vector
    specified by the interrupt object. If the interrupt object is not
    connected, then a value of FALSE is returned. Else the specified interrupt
    object is disconnected from the interrupt vector, the connected state is
    set to FALSE, and TRUE is returned as the function value.

Arguments:

    Interrupt - Supplies a pointer to a control object of type interrupt.

Return Value:

    If the interrupt object is not connected, then a value of FALSE is
    returned. Else a value of TRUE is returned.

--*/

{

    BOOLEAN Connected;
    PKINTERRUPT Interruptx;
    PKINTERRUPT Interrupty;
    KIRQL Irql;
    KIRQL OldIrql;
    KIRQL PreviousIrql;
    ULONG Vector;

    //
    // Set system affinity to the specified processor.
    //

    KeSetSystemAffinityThread((KAFFINITY)(1 << Interrupt->Number));

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // If the interrupt object is connected, then disconnect it from the
    // specified vector.
    //

    Connected = Interrupt->Connected;
    if (Connected != FALSE) {
        Irql = Interrupt->Irql;
        Vector = Interrupt->Vector;

        //
        // If the specified interrupt vector is not connected to the chained
        // interrupt dispatcher, then disconnect it by setting its dispatch
        // address to the unexpected interrupt routine. Else remove the
        // interrupt object from the interrupt chain. If there is only
        // one entry remaining in the list, then reestablish the dispatch
        // address.
        //

        Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector],
                                       KINTERRUPT,
                                       DispatchCode[0]);

        if (Interruptx->DispatchAddress ==
                                (PKINTERRUPT_ROUTINE)KiChainedDispatch) {
            KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql);
            if (Interrupt == Interruptx) {
                Interruptx = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
                                               KINTERRUPT, InterruptListEntry);
                Interruptx->DispatchAddress =
                                (PKINTERRUPT_ROUTINE)KiChainedDispatch;
                Interruptx->DispatchCode[0] = *(PULONG)KiChainedDispatch;
                Interruptx->DispatchCode[1] = *(((PULONG)KiChainedDispatch)+1);
                PCR->InterruptRoutine[Vector] =
                                (PKINTERRUPT_ROUTINE)Interruptx->DispatchCode;

            }

            RemoveEntryList(&Interrupt->InterruptListEntry);
            Interrupty = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
                                           KINTERRUPT,
                                           InterruptListEntry);

            if (Interruptx == Interrupty) {
                if (Interrupt->FloatingSave) {
                    Interrupt->DispatchAddress = KiFloatingDispatch;

                } else {
                    if (Interrupt->Irql == Interrupt->SynchronizeIrql) {
#if defined(NT_UP)
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine;
#else
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
#endif

                    } else {
                        Interrupt->DispatchAddress =
                                 (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
                    }
                }

                //
                // Copy the function descriptor for the Dispatch routine
                // into DispatchCode.  This will be used by KiInterruptEx-
                // ception to dispatch the interrupt.
                //
                Interrupty->DispatchCode[0] =
                                *(PULONG)(Interrupty->DispatchAddress);
                Interrupty->DispatchCode[1] =
                                *(((PULONG)(Interrupty->DispatchAddress))+1);
                PCR->InterruptRoutine[Vector] =
                               (PKINTERRUPT_ROUTINE)Interrupty->DispatchCode;

                }

            KeLowerIrql(PreviousIrql);

        } else {
            HalDisableSystemInterrupt(Vector, Irql);
            PCR->InterruptRoutine[Vector] =
                    (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode);
        }
#ifdef NOTDEF
        KeSweepIcache(TRUE);
#endif
        Interrupt->Connected = FALSE;
    }

    //
    // Unlock dispatcher database and lower IRQL to its previous value.
    //

    KiUnlockDispatcherDatabase(OldIrql);

    //
    // Set system affinity back to the original value.
    //

    KeRevertToUserAffinityThread();

    //
    // Return whether interrupt was disconnected from the specified vector.
    //

    return Connected;
}
示例#17
0
文件: timeout.c 项目: Torxed/dokany
NTSTATUS
ReleaseTimeoutPendingIrp(
   __in PDokanDCB	Dcb
   )
{
	KIRQL				oldIrql;
    PLIST_ENTRY			thisEntry, nextEntry, listHead;
	PIRP_ENTRY			irpEntry;
	LARGE_INTEGER		tickCount;
	LIST_ENTRY			completeList;
	PIRP				irp;

	DDbgPrint("==> ReleaseTimeoutPendingIRP\n");
	InitializeListHead(&completeList);

	ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
	KeAcquireSpinLock(&Dcb->PendingIrp.ListLock, &oldIrql);

	// when IRP queue is empty, there is nothing to do
	if (IsListEmpty(&Dcb->PendingIrp.ListHead)) {
		KeReleaseSpinLock(&Dcb->PendingIrp.ListLock, oldIrql);
		DDbgPrint("  IrpQueue is Empty\n");
		return STATUS_SUCCESS;
	}

	KeQueryTickCount(&tickCount);

	// search timeout IRP through pending IRP list
	listHead = &Dcb->PendingIrp.ListHead;

    for (thisEntry = listHead->Flink;
		thisEntry != listHead;
		thisEntry = nextEntry) {

        nextEntry = thisEntry->Flink;

        irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry);

		// this IRP is NOT timeout yet
		if (tickCount.QuadPart < irpEntry->TickCount.QuadPart) {
			break;
		}

		RemoveEntryList(thisEntry);

		DDbgPrint(" timeout Irp #%X\n", irpEntry->SerialNumber);

		irp = irpEntry->Irp;

		if (irp == NULL) {
			// this IRP has already been canceled
			ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE);
			DokanFreeIrpEntry(irpEntry);
			continue;
		}

		// this IRP is not canceled yet
		if (IoSetCancelRoutine(irp, NULL) == NULL) {
			// Cancel routine will run as soon as we release the lock
			InitializeListHead(&irpEntry->ListEntry);
			irpEntry->CancelRoutineFreeMemory = TRUE;
			continue;
		}
		// IrpEntry is saved here for CancelRoutine
		// Clear it to prevent to be completed by CancelRoutine twice
		irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY] = NULL;
		InsertTailList(&completeList, &irpEntry->ListEntry);
	}

	if (IsListEmpty(&Dcb->PendingIrp.ListHead)) {
		KeClearEvent(&Dcb->PendingIrp.NotEmpty);
	}
	KeReleaseSpinLock(&Dcb->PendingIrp.ListLock, oldIrql);
	
	while (!IsListEmpty(&completeList)) {
		listHead = RemoveHeadList(&completeList);
		irpEntry = CONTAINING_RECORD(listHead, IRP_ENTRY, ListEntry);
		irp = irpEntry->Irp;
		DokanCompleteIrpRequest(irp, STATUS_INSUFFICIENT_RESOURCES, 0);
		DokanFreeIrpEntry(irpEntry);
	}

	DDbgPrint("<== ReleaseTimeoutPendingIRP\n");
	return STATUS_SUCCESS;
}
示例#18
0
文件: memory.c 项目: layerfsd/ffsfsd
VOID
FFSRemoveVcb(
	PFFS_VCB Vcb)
{
	RemoveEntryList(&Vcb->Next);
}
示例#19
0
文件: kill.c 项目: GYGit/reactos
VOID
NTAPI
PspDeleteProcess(IN PVOID ObjectBody)
{
    PEPROCESS Process = (PEPROCESS)ObjectBody;
    KAPC_STATE ApcState;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody);
    PSREFTRACE(Process);

    /* Check if it has an Active Process Link */
    if (Process->ActiveProcessLinks.Flink)
    {
        /* Remove it from the Active List */
        KeAcquireGuardedMutex(&PspActiveProcessMutex);
        RemoveEntryList(&Process->ActiveProcessLinks);
        Process->ActiveProcessLinks.Flink = NULL;
        Process->ActiveProcessLinks.Blink = NULL;
        KeReleaseGuardedMutex(&PspActiveProcessMutex);
    }

    /* Check for Auditing information */
    if (Process->SeAuditProcessCreationInfo.ImageFileName)
    {
        /* Free it */
        ExFreePoolWithTag(Process->SeAuditProcessCreationInfo.ImageFileName,
                          TAG_SEPA);
        Process->SeAuditProcessCreationInfo.ImageFileName = NULL;
    }

    /* Check if we have a job */
    if (Process->Job)
    {
        /* Remove the process from the job */
        PspRemoveProcessFromJob(Process, Process->Job);

        /* Dereference it */
        ObDereferenceObject(Process->Job);
        Process->Job = NULL;
    }

    /* Increase the stack count */
    Process->Pcb.StackCount++;

    /* Check if we have a debug port */
    if (Process->DebugPort)
    {
        /* Deference the Debug Port */
        ObDereferenceObject(Process->DebugPort);
        Process->DebugPort = NULL;
    }

    /* Check if we have an exception port */
    if (Process->ExceptionPort)
    {
        /* Deference the Exception Port */
        ObDereferenceObject(Process->ExceptionPort);
        Process->ExceptionPort = NULL;
    }

    /* Check if we have a section object */
    if (Process->SectionObject)
    {
        /* Deference the Section Object */
        ObDereferenceObject(Process->SectionObject);
        Process->SectionObject = NULL;
    }

#if defined(_X86_)
    /* Clean Ldt and Vdm objects */
    PspDeleteLdt(Process);
    PspDeleteVdmObjects(Process);
#endif

    /* Delete the Object Table */
    if (Process->ObjectTable)
    {
        /* Attach to the process */
        KeStackAttachProcess(&Process->Pcb, &ApcState);

        /* Kill the Object Info */
        ObKillProcess(Process);

        /* Detach */
        KeUnstackDetachProcess(&ApcState);
    }

    /* Check if we have an address space, and clean it */
    if (Process->HasAddressSpace)
    {
        /* Attach to the process */
        KeStackAttachProcess(&Process->Pcb, &ApcState);

        /* Clean the Address Space */
        PspExitProcess(FALSE, Process);

        /* Detach */
        KeUnstackDetachProcess(&ApcState);

        /* Completely delete the Address Space */
        MmDeleteProcessAddressSpace(Process);
    }

    /* See if we have a PID */
    if (Process->UniqueProcessId)
    {
        /* Delete the PID */
        if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId, NULL)))
        {
            /* Something wrong happened, bugcheck */
            KeBugCheck(CID_HANDLE_DELETION);
        }
    }

    /* Cleanup security information */
    PspDeleteProcessSecurity(Process);

    /* Check if we have kept information on the Working Set */
    if (Process->WorkingSetWatch)
    {
        /* Free it */
        ExFreePool(Process->WorkingSetWatch);

        /* And return the quota it was taking up */
        PsReturnProcessNonPagedPoolQuota(Process, 0x2000);
    }

    /* Dereference the Device Map */
    ObDereferenceDeviceMap(Process);

    /* Destroy the Quota Block */
    PspDestroyQuotaBlock(Process);
}
示例#20
0
STATIC
EFI_STATUS
InsertSystemMemoryResources (
  LIST_ENTRY *ResourceList,
  EFI_HOB_RESOURCE_DESCRIPTOR *ResHob
  )
{
  SYSTEM_MEMORY_RESOURCE  *NewResource;
  LIST_ENTRY              *Link;
  LIST_ENTRY              *NextLink;
  LIST_ENTRY              AttachedResources;
  SYSTEM_MEMORY_RESOURCE  *Resource;
  EFI_PHYSICAL_ADDRESS    NewResourceEnd;

  if (IsListEmpty (ResourceList)) {
    NewResource = AllocateZeroPool (sizeof (SYSTEM_MEMORY_RESOURCE));
    NewResource->PhysicalStart = ResHob->PhysicalStart;
    NewResource->ResourceLength = ResHob->ResourceLength;
    InsertTailList (ResourceList, &NewResource->Link);
    return EFI_SUCCESS;
  }

  InitializeListHead (&AttachedResources);

  Link = ResourceList->ForwardLink;
  ASSERT (Link != NULL);
  while (Link != ResourceList) {
    Resource = (SYSTEM_MEMORY_RESOURCE*)Link;

    // Sanity Check. The resources should not overlapped.
    ASSERT (!((ResHob->PhysicalStart >= Resource->PhysicalStart) && (ResHob->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))));
    ASSERT (!((ResHob->PhysicalStart + ResHob->ResourceLength - 1 >= Resource->PhysicalStart) &&
        ((ResHob->PhysicalStart + ResHob->ResourceLength - 1) < (Resource->PhysicalStart + Resource->ResourceLength))));

    // The new resource is attached after this resource descriptor
    if (ResHob->PhysicalStart == Resource->PhysicalStart + Resource->ResourceLength) {
      Resource->ResourceLength =  Resource->ResourceLength + ResHob->ResourceLength;

      NextLink = RemoveEntryList (&Resource->Link);
      InsertTailList (&AttachedResources, &Resource->Link);
      Link = NextLink;
    }
    // The new resource is attached before this resource descriptor
    else if (ResHob->PhysicalStart + ResHob->ResourceLength == Resource->PhysicalStart) {
      Resource->PhysicalStart = ResHob->PhysicalStart;
      Resource->ResourceLength =  Resource->ResourceLength + ResHob->ResourceLength;

      NextLink = RemoveEntryList (&Resource->Link);
      InsertTailList (&AttachedResources, &Resource->Link);
      Link = NextLink;
    } else {
      Link = Link->ForwardLink;
    }
  }

  if (!IsListEmpty (&AttachedResources)) {
    // See if we can merge the attached resource with other resources

    NewResource = (SYSTEM_MEMORY_RESOURCE*)GetFirstNode (&AttachedResources);
    Link = RemoveEntryList (&NewResource->Link);
    while (!IsListEmpty (&AttachedResources)) {
      // Merge resources
      Resource = (SYSTEM_MEMORY_RESOURCE*)Link;

      // Ensure they overlap each other
      ASSERT (
          ((NewResource->PhysicalStart >= Resource->PhysicalStart) && (NewResource->PhysicalStart < (Resource->PhysicalStart + Resource->ResourceLength))) ||
          (((NewResource->PhysicalStart + NewResource->ResourceLength) >= Resource->PhysicalStart) && ((NewResource->PhysicalStart + NewResource->ResourceLength) < (Resource->PhysicalStart + Resource->ResourceLength)))
      );

      NewResourceEnd = MAX (NewResource->PhysicalStart + NewResource->ResourceLength, Resource->PhysicalStart + Resource->ResourceLength);
      NewResource->PhysicalStart = MIN (NewResource->PhysicalStart, Resource->PhysicalStart);
      NewResource->ResourceLength = NewResourceEnd - NewResource->PhysicalStart;

      Link = RemoveEntryList (Link);
    }
  } else {
    // None of the Resource of the list is attached to this ResHob. Create a new entry for it
    NewResource = AllocateZeroPool (sizeof (SYSTEM_MEMORY_RESOURCE));
    NewResource->PhysicalStart = ResHob->PhysicalStart;
    NewResource->ResourceLength = ResHob->ResourceLength;
  }
  InsertTailList (ResourceList, &NewResource->Link);
  return EFI_SUCCESS;
}
示例#21
0
NTSTATUS
MsCleanupFcb (
    IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
    IN PIRP Irp,
    IN PFCB Fcb
    )

/*++

Routine Description:

    This routine cleans up an FCB.  All outstanding i/o on the file
    object are completed with an error status.

Arguments:

    MsfsDeviceObject - A pointer the the mailslot file system device object.

    Irp - Supplies the IRP associated with the cleanup.

    Fcb - Supplies the FCB for the mailslot to clean up.

Return Value:

    NTSTATUS - An appropriate completion status

--*/
{
    NTSTATUS status;
    PDATA_QUEUE dataQueue;
    PDATA_ENTRY dataEntry;
    PLIST_ENTRY listEntry;
    PIRP oldIrp;
    PCCB ccb;
    PWORK_CONTEXT workContext;
    PKTIMER timer;

    PAGED_CODE();
    DebugTrace(+1, Dbg, "MsCleanupFcb, Fcb = %08lx\n", (ULONG)Fcb);

    //
    // Acquire exclusive access to the FCB.
    //

    MsAcquireExclusiveFcb( Fcb );

    status = STATUS_SUCCESS;

    try {

        //
        // Ensure that this FCB still belongs to an active open mailslot.
        //

        MsVerifyFcb( Fcb );

        //
        // Remove the entry from the prefix table, and then remove the full
        // file name.
        //

        MsAcquirePrefixTableLock();
        RtlRemoveUnicodePrefix( &Fcb->Vcb->PrefixTable, &Fcb->PrefixTableEntry );
        MsReleasePrefixTableLock();

        //
        // Remove ourselves from our parent DCB's queue.
        //

        RemoveEntryList( &(Fcb->ParentDcbLinks) );

        //
        // Complete all outstanding I/O on this FCB.
        //

        dataQueue = &Fcb->DataQueue;
        dataQueue->QueueState = -1;

        for (listEntry = MsGetNextDataQueueEntry( dataQueue );
             !MsIsDataQueueEmpty(dataQueue);
             listEntry = MsGetNextDataQueueEntry( dataQueue ) ) {

             //
             // This is an outstanding I/O request on this FCB.
             // Remove it from our queue and complete the request
             // if one is outstanding.
             //

             dataEntry = CONTAINING_RECORD( listEntry, DATA_ENTRY, ListEntry );

             //
             // Cancel the timer if there is a timer for the read request.
             //

             workContext = dataEntry->TimeoutWorkContext;
             if (workContext != NULL) {

                 DebugTrace( 0, Dbg, "Cancelling a timer\n", 0);

                 //
                 // There was a timer on this read operation.  Attempt
                 // to cancel the operation.  If the cancel operation
                 // is successful, then we must cleanup after the operation.
                 // If it was unsuccessful the timer DPC will run, and
                 // will eventually cleanup.
                 //

                 timer = &workContext->Timer;

                 if (KeCancelTimer( timer ) ) {

                     //
                     // Release the reference to the FCB.
                     //

                     MsDereferenceFcb( workContext->Fcb );

                     //
                     // Free the memory from the work context, the timer,
                     // and the DPC.
                     //

                     ExFreePool( workContext );

                 }

             }

             oldIrp = MsRemoveDataQueueEntry( dataQueue, dataEntry );

             if (oldIrp != NULL) {

                 DebugTrace(0, Dbg, "Completing IRP %08lx\n", (ULONG)oldIrp );
                 MsCompleteRequest( oldIrp, STATUS_FILE_FORCED_CLOSED );

             }

        }

        //
        // Now cleanup all the CCB's on this FCB, to ensure that new
        // write IRP will not be processed.
        //

        MsAcquireCcbListLock();

        listEntry = Fcb->Specific.Fcb.CcbQueue.Flink;

        while( listEntry != &Fcb->Specific.Fcb.CcbQueue ) {

            ccb = (PCCB)CONTAINING_RECORD( listEntry, CCB, CcbLinks );

            ccb->Header.NodeState = NodeStateClosing;

            //
            // Get the next CCB on this FCB.
            //

            listEntry = listEntry->Flink;
        }

        MsReleaseCcbListLock();

        //
        // Cleanup the share access.
        //

        IoRemoveShareAccess( Fcb->FileObject, &Fcb->ShareAccess);

        //
        // Mark the FCB closing.
        //

        Fcb->Header.NodeState = NodeStateClosing;

   } finally {

        ASSERT (MsIsDataQueueEmpty(dataQueue));

        MsReleaseFcb( Fcb );
        DebugTrace(-1, Dbg, "MsCloseFcb -> %08lx\n", status);
    }

    //
    // Return to the caller.
    //

    return status;

}
示例#22
0
NTSTATUS
kmdf1394_FreeAddressRange (
                           IN WDFDEVICE Device,
                           IN WDFREQUEST Request,
                           IN HANDLE hAddressRange)
/*++

Routine Description:

    Allocate Address Range routine.

Arguments:

    Device - the current WDFDEVICE Object.

    Request - the current request.

    hAddressRange - The Address Range to be freed.

Return Value:

    VOID
--*/
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_EXTENSION deviceExtension = GetDeviceContext(Device);
    PIRB pIrb = NULL;
    PASYNC_ADDRESS_DATA AsyncAddressData  = NULL;
    PLIST_ENTRY listHead, thisEntry;

    UNREFERENCED_PARAMETER(Request);

    ENTER("kmdf1394_FreeAddressRange");

    //
    // have to find our struct...
    //
    WdfSpinLockAcquire (deviceExtension->AsyncSpinLock);

    listHead = &deviceExtension->AsyncAddressData;

    for (thisEntry = listHead->Flink; 
        thisEntry != listHead; 
        AsyncAddressData = NULL, thisEntry = thisEntry->Flink)
    {
        AsyncAddressData = CONTAINING_RECORD (
            thisEntry, 
            ASYNC_ADDRESS_DATA,
            AsyncAddressList);

        if (AsyncAddressData->hAddressRange == hAddressRange) 
        {
            RemoveEntryList(&AsyncAddressData->AsyncAddressList);
            break;
        }
    }

    WdfSpinLockRelease(deviceExtension->AsyncSpinLock);

    //
    // never found an entry...
    //
    if (!AsyncAddressData) 
    {
        return STATUS_INVALID_PARAMETER;
    }

    // 
    // got it, lets free it...
    //
    pIrb = ExAllocatePoolWithTag (NonPagedPool, sizeof(IRB), POOLTAG_KMDF_VDEV);
    if (!pIrb) 
    {
        TRACE(TL_ERROR, ("Failed to allocate pIrb!\n"));

        //
        // Catasrophic failure, insert the AddressData element back on 
        // the list before existing
        //
        WdfSpinLockAcquire (deviceExtension->AsyncSpinLock);

        InsertHeadList (
            &deviceExtension->AsyncAddressData, 
            &AsyncAddressData->AsyncAddressList);

        WdfSpinLockRelease (deviceExtension->AsyncSpinLock);

        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlZeroMemory (pIrb, sizeof (IRB));
    pIrb->FunctionNumber = REQUEST_FREE_ADDRESS_RANGE;
    pIrb->Flags = 0;
    pIrb->u.FreeAddressRange.nAddressesToFree = \
        AsyncAddressData->nAddressesReturned;
    pIrb->u.FreeAddressRange.p1394AddressRange = AsyncAddressData->AddressRange;
    pIrb->u.FreeAddressRange.pAddressRange = &AsyncAddressData->hAddressRange;
    pIrb->u.FreeAddressRange.DeviceExtension = (PVOID)deviceExtension;

    //
    // We're going to send this one synchronously
    //
    ntStatus = kmdf1394_SubmitIrpSynch (
        deviceExtension->StackIoTarget, 
        Request, 
        pIrb);
    if (!NT_SUCCESS (ntStatus))
    {
        //
        // The free request failed, insert the element back on to our tracking 
        // list and either try to free later, or release the resources on 
        // driver tear down.
        //
        WdfSpinLockAcquire (deviceExtension->AsyncSpinLock);

        InsertHeadList (
            &deviceExtension->AsyncAddressData, 
            &AsyncAddressData->AsyncAddressList);

        WdfSpinLockRelease (deviceExtension->AsyncSpinLock);
    }
    else
    {
        // 
        //  need to free up everything associated with this from the allocate...
        //
        IoFreeMdl (AsyncAddressData->pMdl);
        ExFreePoolWithTag (AsyncAddressData->Buffer, POOLTAG_KMDF_VDEV);
        ExFreePoolWithTag (AsyncAddressData->AddressRange, POOLTAG_KMDF_VDEV);
        ExFreePoolWithTag (AsyncAddressData, POOLTAG_KMDF_VDEV);
    }

    ExFreePoolWithTag (pIrb, POOLTAG_KMDF_VDEV);

    EXIT("kmdf1394_FreeAddressRange", ntStatus);
    return ntStatus;
} // kmdf1394_FreeAddressRange
示例#23
0
文件: Pool.c 项目: iderzh/edk2
/**
  Internal function to allocate pool of a particular type.
  Caller must have the memory lock held

  @param  PoolType               Type of pool to allocate
  @param  Size                   The amount of pool to allocate

  @return The allocate pool, or NULL

**/
VOID *
CoreAllocatePoolI (
  IN EFI_MEMORY_TYPE  PoolType,
  IN UINTN            Size
  )
{
  POOL        *Pool;
  POOL_FREE   *Free;
  POOL_HEAD   *Head;
  POOL_TAIL   *Tail;
  CHAR8       *NewPage;
  VOID        *Buffer;
  UINTN       Index;
  UINTN       FSize;
  UINTN       Offset, MaxOffset;
  UINTN       NoPages;
  UINTN       Granularity;

  ASSERT_LOCKED (&gMemoryLock);

  if  (PoolType == EfiACPIReclaimMemory   ||
       PoolType == EfiACPIMemoryNVS       ||
       PoolType == EfiRuntimeServicesCode ||
       PoolType == EfiRuntimeServicesData) {

    Granularity = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;
  } else {
    Granularity = DEFAULT_PAGE_ALLOCATION;
  }

  //
  // Adjust the size by the pool header & tail overhead
  //

  //
  // Adjusting the Size to be of proper alignment so that
  // we don't get an unaligned access fault later when
  // pool_Tail is being initialized
  //
  Size = ALIGN_VARIABLE (Size);

  Size += POOL_OVERHEAD;
  Index = SIZE_TO_LIST(Size);
  Pool = LookupPoolHead (PoolType);
  if (Pool== NULL) {
    return NULL;
  }
  Head = NULL;

  //
  // If allocation is over max size, just allocate pages for the request
  // (slow)
  //
  if (Index >= SIZE_TO_LIST (Granularity)) {
    NoPages = EFI_SIZE_TO_PAGES(Size) + EFI_SIZE_TO_PAGES (Granularity) - 1;
    NoPages &= ~(UINTN)(EFI_SIZE_TO_PAGES (Granularity) - 1);
    Head = CoreAllocatePoolPages (PoolType, NoPages, Granularity);
    goto Done;
  }

  //
  // If there's no free pool in the proper list size, go get some more pages
  //
  if (IsListEmpty (&Pool->FreeList[Index])) {

    Offset = LIST_TO_SIZE (Index);
    MaxOffset = Granularity;

    //
    // Check the bins holding larger blocks, and carve one up if needed
    //
    while (++Index < SIZE_TO_LIST (Granularity)) {
      if (!IsListEmpty (&Pool->FreeList[Index])) {
        Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
        RemoveEntryList (&Free->Link);
        NewPage = (VOID *) Free;
        MaxOffset = LIST_TO_SIZE (Index);
        goto Carve;
      }
    }

    //
    // Get another page
    //
    NewPage = CoreAllocatePoolPages(PoolType, EFI_SIZE_TO_PAGES (Granularity), Granularity);
    if (NewPage == NULL) {
      goto Done;
    }

    //
    // Serve the allocation request from the head of the allocated block
    //
Carve:
    Head = (POOL_HEAD *) NewPage;

    //
    // Carve up remaining space into free pool blocks
    //
    Index--;
    while (Offset < MaxOffset) {
      ASSERT (Index < MAX_POOL_LIST);
      FSize = LIST_TO_SIZE(Index);

      while (Offset + FSize <= MaxOffset) {
        Free = (POOL_FREE *) &NewPage[Offset];
        Free->Signature = POOL_FREE_SIGNATURE;
        Free->Index     = (UINT32)Index;
        InsertHeadList (&Pool->FreeList[Index], &Free->Link);
        Offset += FSize;
      }
      Index -= 1;
    }

    ASSERT (Offset == MaxOffset);
    goto Done;
  }

  //
  // Remove entry from free pool list
  //
  Free = CR (Pool->FreeList[Index].ForwardLink, POOL_FREE, Link, POOL_FREE_SIGNATURE);
  RemoveEntryList (&Free->Link);

  Head = (POOL_HEAD *) Free;

Done:
  Buffer = NULL;

  if (Head != NULL) {

    //
    // If we have a pool buffer, fill in the header & tail info
    //
    Head->Signature = POOL_HEAD_SIGNATURE;
    Head->Size      = Size;
    Head->Type      = (EFI_MEMORY_TYPE) PoolType;
    Tail            = HEAD_TO_TAIL (Head);
    Tail->Signature = POOL_TAIL_SIGNATURE;
    Tail->Size      = Size;
    Buffer          = Head->Data;
    DEBUG_CLEAR_MEMORY (Buffer, Size - POOL_OVERHEAD);

    DEBUG ((
      DEBUG_POOL,
      "AllocatePoolI: Type %x, Addr %p (len %lx) %,ld\n", PoolType,
      Buffer,
      (UINT64)(Size - POOL_OVERHEAD),
      (UINT64) Pool->Used
      ));

    //
    // Account the allocation
    //
    Pool->Used += Size;

  } else {
    DEBUG ((DEBUG_ERROR | DEBUG_POOL, "AllocatePool: failed to allocate %ld bytes\n", (UINT64) Size));
  }

  return Buffer;
}
示例#24
0
VOID
HvFreeHivePartial(
    PHHIVE      Hive,
    HCELL_INDEX Start,
    HSTORAGE_TYPE Type
    )
/*++

Routine Description:

    Free the memory and associated maps for the end of a hive
    starting at Start.  The baseblock, hive, etc will not be touched.

Arguments:

    Hive - supplies a pointer to hive control structure for hive to
            partially free.

    Start - HCELL_INDEX of first bin to free, will free from this
            bin (inclusive) to the end of the hives stable storage.

    Type - Type of storage (Stable or Volatile) to be freed.

Return Value:

    NONE.

--*/
{
    PHMAP_DIRECTORY Dir;
    PHMAP_ENTRY     Me;
    HCELL_INDEX     Address;
    ULONG           StartTable;
    ULONG           Length;
    PHBIN           Bin;
    ULONG           Tables;
    ULONG           FirstBit;
    ULONG           LastBit;
    PFREE_HBIN      FreeBin;

    ASSERT(Hive->Flat == FALSE);
    ASSERT(Hive->ReadOnly == FALSE);

    Address = Start;
    Length = Hive->Storage[Type].Length;
    ASSERT(Address <= Length);

    if (Address == Length) {
        return;
    }

    //
    // Sweep through bin set
    //
    do {
        Me = HvpGetCellMap(Hive, Address + (Type*HCELL_TYPE_MASK));
        VALIDATE_CELL_MAP(__LINE__,Me,Hive,Address + (Type*HCELL_TYPE_MASK));
        if (Me->BinAddress & HMAP_DISCARDABLE) {
            FreeBin = (PFREE_HBIN)Me->BlockAddress;
            if (FreeBin->Flags & FREE_HBIN_DISCARDABLE) {
                CmpFree((PVOID)HBIN_BASE(Me->BinAddress), FreeBin->Size);
            } else {
                //
                // The bin has been freed, but quota is still charged.
                // Since the file will now shrink, the quota must be
                // returned here.
                //
                if( Me->BinAddress & HMAP_INPAGEDPOOL) {
                    //
                    // we charge quota only for bins in paged-pool
                    //
                    CmpReleaseGlobalQuota(FreeBin->Size);
                }
            }
            RemoveEntryList(&FreeBin->ListEntry);
            Address += FreeBin->Size;
            CmpFree(FreeBin, sizeof(FREE_HBIN));

        } else {
            Bin = (PHBIN)HBIN_BASE(Me->BinAddress);
            Address += HvpGetBinMemAlloc(Hive,Bin,Type);
            
            if( Me->BinAddress & HMAP_INPAGEDPOOL && HvpGetBinMemAlloc(Hive,Bin,Type) ) {
                //
                // free the bin only if it is allocated from paged pool
                //
                CmpFree(Bin, HvpGetBinMemAlloc(Hive,Bin,Type));
            }
        }
    } while (Address < Length);

    //
    // Free map table storage
    //
    Tables = (((Hive->Storage[Type].Length) / HBLOCK_SIZE) - 1) / HTABLE_SLOTS;
    Dir = Hive->Storage[Type].Map;
    if (Start > 0) {
        StartTable = ((Start-1) / HBLOCK_SIZE) / HTABLE_SLOTS;
    } else {
        StartTable = (ULONG)-1;
    }
    HvpFreeMap(Hive, Dir, StartTable+1, Tables);

    //
    // update hysteresis (eventually queue work item)
    //
    if( Type == Stable) {
        CmpUpdateSystemHiveHysteresis(Hive,(Start&(~HCELL_TYPE_MASK)),Hive->Storage[Type].Length);
    }

    Hive->Storage[Type].Length = (Start&(~HCELL_TYPE_MASK));

    if (Type==Stable) {
        //
        // Clear dirty vector for data past Hive->Storage[Stable].Length
        //
        FirstBit = Start / HSECTOR_SIZE;
        LastBit = Hive->DirtyVector.SizeOfBitMap;
        ASSERT(Hive->DirtyCount == RtlNumberOfSetBits(&Hive->DirtyVector));
        RtlClearBits(&Hive->DirtyVector, FirstBit, LastBit-FirstBit);
        Hive->DirtyCount = RtlNumberOfSetBits(&Hive->DirtyVector);
    }

    HvpAdjustHiveFreeDisplay(Hive,Hive->Storage[Type].Length,Type);

    return;
}
示例#25
0
NTSTATUS NTAPI
ConDrvGetConsoleInput(IN PCONSOLE Console,
                      IN PCONSOLE_INPUT_BUFFER InputBuffer,
                      IN BOOLEAN KeepEvents,
                      IN BOOLEAN WaitForMoreEvents,
                      IN BOOLEAN Unicode,
                      OUT PINPUT_RECORD InputRecord,
                      IN ULONG NumEventsToRead,
                      OUT PULONG NumEventsRead OPTIONAL)
{
    PLIST_ENTRY CurrentInput;
    ConsoleInput* Input;
    ULONG i = 0;

    if (Console == NULL || InputBuffer == NULL /* || InputRecord == NULL */)
        return STATUS_INVALID_PARAMETER;

    /* Validity checks */
    ASSERT(Console == InputBuffer->Header.Console);
    ASSERT( (InputRecord != NULL && NumEventsToRead >= 0) ||
            (InputRecord == NULL && NumEventsToRead == 0) );

    // Do NOT do that !! Use the existing number of events already read, if any...
    // if (NumEventsRead) *NumEventsRead = 0;

    if (IsListEmpty(&InputBuffer->InputEvents))
    {
        /*
         * No input is available. Wait for more input if requested,
         * otherwise, we don't wait, so we return success.
         */
        return (WaitForMoreEvents ? STATUS_PENDING : STATUS_SUCCESS);
    }

    /* Only get input if there is any */
    CurrentInput = InputBuffer->InputEvents.Flink;
    if (NumEventsRead) i = *NumEventsRead; // We will read the remaining events...

    while ((CurrentInput != &InputBuffer->InputEvents) && (i < NumEventsToRead))
    {
        Input = CONTAINING_RECORD(CurrentInput, ConsoleInput, ListEntry);

        *InputRecord = Input->InputEvent;

        if (!Unicode)
        {
            ConioInputEventToAnsi(InputBuffer->Header.Console, InputRecord);
        }

        ++InputRecord;
        ++i;
        CurrentInput = CurrentInput->Flink;

        /* Remove the events from the queue if needed */
        if (!KeepEvents)
        {
            RemoveEntryList(&Input->ListEntry);
            ConsoleFreeHeap(Input);
        }
    }

    if (NumEventsRead) *NumEventsRead = i;

    if (IsListEmpty(&InputBuffer->InputEvents))
    {
        ResetEvent(InputBuffer->ActiveEvent);
    }

    /* We read all the inputs available, we return success */
    return STATUS_SUCCESS;
}
示例#26
0
/**
  Reorder boot options

  Ask for the boot option to move and then move it when up or down arrows
  are pressed. This function is called when the user selects the "Reorder Boot
  Device Entries" entry in the boot manager menu.
  The order of the boot options in BootOptionList and in the UEFI BootOrder
  global variable are kept coherent until the user confirm his reordering (ie:
  he does not exit by pressing escape).

  @param[in]  BootOptionsList  List of the boot devices constructed in
                               BootMenuMain()

  @retval  EFI_SUCCESS   No error encountered.
  @retval  !EFI_SUCCESS  An error has occured either in the selection of the
                         boot option to move or while interacting with the user.

**/
STATIC
EFI_STATUS
BootMenuReorderBootOptions (
  IN LIST_ENTRY *BootOptionsList
  )
{
  EFI_STATUS              Status;
  BDS_LOAD_OPTION_ENTRY  *BootOptionEntry;
  LIST_ENTRY             *SelectedEntry;
  LIST_ENTRY             *PrevEntry;
  BOOLEAN                 Move;
  BOOLEAN                 Save;
  BOOLEAN                 Cancel;
  UINTN                   WaitIndex;
  EFI_INPUT_KEY           Key;
  LIST_ENTRY             *SecondEntry;
  UINTN                   BootOrderSize;
  UINT16                 *BootOrder;
  LIST_ENTRY             *Entry;
  UINTN                   Index;

  DisplayBootOptions (BootOptionsList);

  // Ask to select the boot option to move
  while (TRUE) {
    Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry);
    if (EFI_ERROR (Status)) {
      goto ErrorExit;
    }

    SelectedEntry = &BootOptionEntry->Link;
    SecondEntry = NULL;
    // Note down the previous entry in the list to be able to cancel changes
    PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);

    //  Start of interaction
    while (TRUE) {
      Print (
        L"* Use up/down arrows to move the entry '%s'",
        BootOptionEntry->BdsLoadOption->Description
        );

      // Wait for a move, save or cancel request
      Move   = FALSE;
      Save   = FALSE;
      Cancel = FALSE;
      do {
        Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
        if (!EFI_ERROR (Status)) {
          Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
        }
        if (EFI_ERROR (Status)) {
          Print (L"\n");
          goto ErrorExit;
        }

        switch (Key.ScanCode) {
        case SCAN_NULL:
          Save = (Key.UnicodeChar == CHAR_LINEFEED)        ||
                 (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||
                 (Key.UnicodeChar == 0x7f);
          break;

        case SCAN_UP:
          SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry);
          Move = SecondEntry != BootOptionsList;
          break;

        case SCAN_DOWN:
          SecondEntry = GetNextNode (BootOptionsList, SelectedEntry);
          Move = SecondEntry != BootOptionsList;
          break;

        case SCAN_ESC:
          Cancel = TRUE;
          break;
        }
      } while ((!Move) && (!Save) && (!Cancel));

      if (Move) {
        if ((SelectedEntry != NULL) && (SecondEntry != NULL)) {
          SwapListEntries (SelectedEntry, SecondEntry);
        }
      } else {
        if (Save) {
          Status = GetGlobalEnvironmentVariable (
                    L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder
                    );
          BootOrderSize /= sizeof (UINT16);

          if (!EFI_ERROR (Status)) {
            // The order of the boot options in the 'BootOptionsList' is the
            // new order that has been just defined by the user. Save this new
            // order in "BootOrder" UEFI global variable.
            Entry = GetFirstNode (BootOptionsList);
            for (Index = 0; Index < BootOrderSize; Index++) {
              BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex;
              Entry = GetNextNode (BootOptionsList, Entry);
            }
            Status = gRT->SetVariable (
                           (CHAR16*)L"BootOrder",
                           &gEfiGlobalVariableGuid,
                           EFI_VARIABLE_NON_VOLATILE       |
                           EFI_VARIABLE_BOOTSERVICE_ACCESS |
                           EFI_VARIABLE_RUNTIME_ACCESS,
                           BootOrderSize * sizeof (UINT16),
                           BootOrder
                           );
            FreePool (BootOrder);
          }

          if (EFI_ERROR (Status)) {
            Print (L"\nAn error occurred, move not completed!\n");
            Cancel = TRUE;
          }
        }

        if (Cancel) {
          //
          // Restore initial position of the selected boot option
          //
          RemoveEntryList (SelectedEntry);
          InsertHeadList (PrevEntry, SelectedEntry);
        }
      }

      Print (L"\n");
      DisplayBootOptions (BootOptionsList);
      // Saved or cancelled, back to the choice of boot option to move
      if (!Move) {
        break;
      }
    }
  }

ErrorExit:
  return Status ;
}
示例#27
0
NTSTATUS
FatFsdDeviceControl (
    IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine implements the FSD part of Device control operations

Arguments:

    VolumeDeviceObject - Supplies the volume device object where the
        file exists

    Irp - Supplies the Irp being processed

Return Value:

    NTSTATUS - The FSD status for the IRP

--*/

{
    NTSTATUS Status;
    PIRP_CONTEXT IrpContext = NULL;

    BOOLEAN TopLevel;

#ifdef	__ND_FAT__

	PIO_STACK_LOCATION	irpSp = IoGetCurrentIrpStackLocation( Irp );

	if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL && FatData.DiskFileSystemDeviceObject == (PDEVICE_OBJECT)VolumeDeviceObject) {

		switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {

		case IOCTL_REGISTER_NDFS_CALLBACK: {

			PNDFS_CALLBACK	inputBuffer			= (PNDFS_CALLBACK)Irp->AssociatedIrp.SystemBuffer;
			ULONG			inputBufferLength	= irpSp->Parameters.DeviceIoControl.InputBufferLength;


			if ( inputBufferLength != sizeof( VolumeDeviceObject->NdfsCallback ) ) {

				Status = Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
				Irp->IoStatus.Information = 0;
				break;
			} 
			
			DebugTrace2( 0, Dbg2, ("NtfsFsdDispatch: IOCTL_REGISTER_NDFS_CALLBACK, size = %d\n", inputBuffer->Size) );		

			RtlCopyMemory( &VolumeDeviceObject->NdfsCallback, inputBuffer, sizeof(VolumeDeviceObject->NdfsCallback) );

			//ASSERT( FALSE );
			Status = Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = 0;
			
			break;
		}
	
		case IOCTL_UNREGISTER_NDFS_CALLBACK:

			DebugTrace2( 0, Dbg2, ("NtfsFsdDispatch: IOCTL_UNREGISTER_NDFS_CALLBACK\n") );		

			RtlZeroMemory( &VolumeDeviceObject->NdfsCallback, sizeof(VolumeDeviceObject->NdfsCallback) );

			Status = Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = 0;

			break;

		case IOCTL_SHUTDOWN: {
			
			PLIST_ENTRY				vcbListEntry;

			DebugTrace2( 0, Dbg2, ("FatFsdDeviceControl: IOCTL_SHUTDOWN\n") );		

	        for (vcbListEntry = FatData.VcbQueue.Flink;
			     vcbListEntry != &FatData.VcbQueue;
				 vcbListEntry = vcbListEntry->Flink) {

				PVCB					vcb = NULL;
#ifdef __ND_FAT_PRIMARY__
				PLIST_ENTRY				primarySessionListEntry;
#endif
				PVOLUME_DEVICE_OBJECT	volDo = NULL;


				DebugTrace2( 0, Dbg2, ("NtfsFsdDispatch: volDo = %p, KeGetCurrentIrql() = %d\n", volDo, KeGetCurrentIrql()) );		

				vcb = CONTAINING_RECORD(vcbListEntry, VCB, VcbLinks);
				volDo = CONTAINING_RECORD( vcb, VOLUME_DEVICE_OBJECT, Vcb );

				DebugTrace2( 0, Dbg2, ("FatFsdDeviceControl: ND_FAT_DEVICE_FLAG_SHUTDOWN\n") );		
				SetFlag( volDo->NdFatFlags, ND_FAT_DEVICE_FLAG_SHUTDOWN );

		
#ifdef __ND_FAT_PRIMARY__

				for (primarySessionListEntry = volDo->PrimarySessionQueue.Flink;
					 primarySessionListEntry != &volDo->PrimarySessionQueue; ) {

					PPRIMARY_SESSION primarySession;

					primarySession = CONTAINING_RECORD( primarySessionListEntry, PRIMARY_SESSION, ListEntry );
					primarySessionListEntry = primarySessionListEntry->Flink;
					PrimarySession_Reference( primarySession );
		
					PrimarySession_FileSystemShutdown( primarySession );

					RemoveEntryList( &primarySession->ListEntry );
					InitializeListHead(  &primarySession->ListEntry );
					PrimarySession_Dereference( primarySession );
				}
#endif
			}

			Status = Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = 0;
			DebugTrace2( 0, Dbg2, ("NtfsFsdDispatch: IOCTL_SHUTDOWN return\n") );		

			break;
		}

		default:
				
			ASSERT( FALSE );
			Status = Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
			Irp->IoStatus.Information = 0;
		}

		IoCompleteRequest( Irp, IO_DISK_INCREMENT );
		return Status;
	}

	//if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL && 
	//	IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode == IOCTL_INSERT_PRIMARY_SESSION) {

    //    return NtfsFsdDispatchSwitch( NULL, Irp, FALSE );
	//}

#endif

    DebugTrace(+1, Dbg, "FatFsdDeviceControl\n", 0);

    FsRtlEnterFileSystem();

    TopLevel = FatIsIrpTopLevel( Irp );

    try {

#ifdef __ND_FAT__

		if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_DEVICE_CONTROL && 
			IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode == IOCTL_INSERT_PRIMARY_SESSION) {

			IrpContext = FatCreateIrpContext( Irp, FALSE );
		
		} else {

			IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ));
		}



#else
		IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ));
#endif

        Status = FatCommonDeviceControl( IrpContext, Irp );

    } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {

        //
        //  We had some trouble trying to perform the requested
        //  operation, so we'll abort the I/O request with
        //  the error status that we get back from the
        //  execption code
        //

        Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
    }

    if (TopLevel) { IoSetTopLevelIrp( NULL ); }

    FsRtlExitFileSystem();

    //
    //  And return to our caller
    //

    DebugTrace(-1, Dbg, "FatFsdDeviceControl -> %08lx\n", Status);

    UNREFERENCED_PARAMETER( VolumeDeviceObject );

    return Status;
}
示例#28
0
LONG
KeReleaseMutant (
    IN PRKMUTANT Mutant,
    IN KPRIORITY Increment,
    IN BOOLEAN Abandoned,
    IN BOOLEAN Wait
    )

/*++

Routine Description:

    This function releases a mutant object by incrementing the mutant
    count. If the resultant value is one, then an attempt is made to
    satisfy as many Waits as possible. The previous signal state of
    the mutant is returned as the function value. If the Abandoned
    parameter is TRUE, then the mutant object is released by settings
    the signal state to one.

Arguments:

    Mutant - Supplies a pointer to a dispatcher object of type mutant.

    Increment - Supplies the priority increment that is to be applied
        if setting the event causes a Wait to be satisfied.

    Abandoned - Supplies a boolean value that signifies whether the
        mutant object is being abandoned.

    Wait - Supplies a boolean value that signifies whether the call to
        KeReleaseMutant will be immediately followed by a call to one
        of the kernel Wait functions.

Return Value:

    The previous signal state of the mutant object.

--*/

{

    KIRQL OldIrql;
    LONG OldState;
    PRKTHREAD Thread;


    ASSERT_MUTANT(Mutant);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    //
    // Raise IRQL to dispatcher level and lock dispatcher database.
    //

    KiLockDispatcherDatabase(&OldIrql);

    //
    // Capture the current signal state of the mutant object.
    //

    OldState = Mutant->Header.SignalState;

    //
    // If the Abandoned parameter is TRUE, then force the release of the
    // mutant object by setting its ownership count to one and setting its
    // abandoned state to TRUE. Otherwise increment mutant ownership count.
    // If the result count is one, then remove the mutant object from the
    // thread's owned mutant list, set the owner thread to NULL, and attempt
    // to satisfy a Wait for the mutant object if the mutant object wait
    // list is not empty.
    //

    Thread = KeGetCurrentThread();
    if (Abandoned != FALSE) {
        Mutant->Header.SignalState = 1;
        Mutant->Abandoned = TRUE;

    } else {

        //
        // If the Mutant object is not owned by the current thread, then
        // unlock the dispatcher data base and raise an exception. Otherwise
        // increment the ownership count.
        //

        if (Mutant->OwnerThread != Thread) {
            KiUnlockDispatcherDatabase(OldIrql);
            ExRaiseStatus(Mutant->Abandoned ?
                          STATUS_ABANDONED : STATUS_MUTANT_NOT_OWNED);
        }

        Mutant->Header.SignalState += 1;
    }

    if (Mutant->Header.SignalState == 1) {
        if (OldState <= 0) {
            RemoveEntryList(&Mutant->MutantListEntry);
            Thread->KernelApcDisable += Mutant->ApcDisable;
            if ((Thread->KernelApcDisable == 0) &&
                (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE)) {
                Thread->ApcState.KernelApcPending = TRUE;
                KiRequestSoftwareInterrupt(APC_LEVEL);
            }
        }

        Mutant->OwnerThread = (PKTHREAD)NULL;
        if (IsListEmpty(&Mutant->Header.WaitListHead) == FALSE) {
            KiWaitTest(Mutant, Increment);
        }
    }

    //
    // If the value of the Wait argument is TRUE, then return to
    // caller with IRQL raised and the dispatcher database locked.
    // Else release the dispatcher database lock and lower IRQL to
    // its previous value.
    //

    if (Wait != FALSE) {
        Thread->WaitNext = Wait;
        Thread->WaitIrql = OldIrql;

    } else {
        KiUnlockDispatcherDatabase(OldIrql);
    }

    //
    // Return previous signal state of mutant object.
    //

    return OldState;
}
示例#29
0
/**
  Load the variable data from file and set to variable data base.

  @param[in]  FileHandle     The file to be read.
  @param[in]  Name           The name of the variables to be loaded.
  @param[in]  Guid           The guid of the variables to be loaded.
  @param[out] Found          TRUE when at least one variable was loaded and set.

  @retval SHELL_DEVICE_ERROR      Cannot access the file.
  @retval SHELL_VOLUME_CORRUPTED  The file is in bad format.
  @retval SHELL_OUT_OF_RESOURCES  There is not enough memory to perform the operation.
  @retval SHELL_SUCCESS           Successfully load and set the variables.
**/
SHELL_STATUS
LoadVariablesFromFile (
  IN SHELL_FILE_HANDLE FileHandle,
  IN CONST CHAR16      *Name,
  IN CONST EFI_GUID    *Guid,
  OUT BOOLEAN          *Found
  )
{
  EFI_STATUS           Status;
  SHELL_STATUS         ShellStatus;
  UINT32               NameSize;
  UINT32               DataSize;
  UINTN                BufferSize;
  UINTN                RemainingSize;
  UINT64               Position;
  UINT64               FileSize;
  LIST_ENTRY           List;
  DMP_STORE_VARIABLE   *Variable;
  LIST_ENTRY           *Link;
  CHAR16               *Attributes;
  UINT8                *Buffer;
  UINT32               Crc32;

  Status = ShellGetFileSize (FileHandle, &FileSize);
  if (EFI_ERROR (Status)) {
    return SHELL_DEVICE_ERROR;
  }
  
  ShellStatus = SHELL_SUCCESS;
  
  InitializeListHead (&List);
  
  Position = 0;
  while (Position < FileSize) {
    //
    // NameSize
    //
    BufferSize = sizeof (NameSize);
    Status = ShellReadFile (FileHandle, &BufferSize, &NameSize);
    if (EFI_ERROR (Status) || (BufferSize != sizeof (NameSize))) {
      ShellStatus = SHELL_VOLUME_CORRUPTED;
      break;
    }

    //
    // DataSize
    //
    BufferSize = sizeof (DataSize);
    Status = ShellReadFile (FileHandle, &BufferSize, &DataSize);
    if (EFI_ERROR (Status) || (BufferSize != sizeof (DataSize))) {
      ShellStatus = SHELL_VOLUME_CORRUPTED;
      break;
    }

    //
    // Name, Guid, Attributes, Data, Crc32
    //
    RemainingSize = NameSize + sizeof (EFI_GUID) + sizeof (UINT32) + DataSize + sizeof (Crc32);
    BufferSize    = sizeof (NameSize) + sizeof (DataSize) + RemainingSize;
    Buffer        = AllocatePool (BufferSize);
    if (Buffer == NULL) {
      ShellStatus = SHELL_OUT_OF_RESOURCES;
      break;
    }
    BufferSize    = RemainingSize;
    Status = ShellReadFile (FileHandle, &BufferSize, (UINT32 *) Buffer + 2);
    if (EFI_ERROR (Status) || (BufferSize != RemainingSize)) {
      ShellStatus = SHELL_VOLUME_CORRUPTED;
      FreePool (Buffer);
      break;
    }

    //
    // Check Crc32
    //
    * (UINT32 *) Buffer       = NameSize;
    * ((UINT32 *) Buffer + 1) = DataSize;
    BufferSize = RemainingSize + sizeof (NameSize) + sizeof (DataSize) - sizeof (Crc32);
    gBS->CalculateCrc32 (
           Buffer,
           BufferSize,
           &Crc32
           );
    if (Crc32 != * (UINT32 *) (Buffer + BufferSize)) {
      FreePool (Buffer);
      ShellStatus = SHELL_VOLUME_CORRUPTED;
      break;
    }

    Position += BufferSize + sizeof (Crc32);
    
    Variable = AllocateZeroPool (sizeof (*Variable) + NameSize + DataSize);
    if (Variable == NULL) {
      FreePool (Buffer);
      ShellStatus = SHELL_OUT_OF_RESOURCES;
      break;
    }
    Variable->Signature = DMP_STORE_VARIABLE_SIGNATURE;
    Variable->Name      = (CHAR16 *) (Variable + 1);
    Variable->DataSize  = DataSize;
    Variable->Data      = (UINT8 *) Variable->Name + NameSize;
    CopyMem (Variable->Name,        Buffer + sizeof (NameSize) + sizeof (DataSize),                                                  NameSize);
    CopyMem (&Variable->Guid,       Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize,                                       sizeof (EFI_GUID));
    CopyMem (&Variable->Attributes, Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize + sizeof (EFI_GUID),                   sizeof (UINT32));
    CopyMem (Variable->Data,        Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize + sizeof (EFI_GUID) + sizeof (UINT32), DataSize);

    InsertTailList (&List, &Variable->Link);
    FreePool (Buffer);
  }
    
  if ((Position != FileSize) || (ShellStatus != SHELL_SUCCESS)) {
    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD_BAD_FILE), gShellDebug1HiiHandle, L"dmpstore");  
    if (Position != FileSize) {
      ShellStatus = SHELL_VOLUME_CORRUPTED;
    }
  }
  
  for ( Link = GetFirstNode (&List)
      ; !IsNull (&List, Link) && (ShellStatus == SHELL_SUCCESS)
      ; Link = GetNextNode (&List, Link)
      ) {
    Variable = CR (Link, DMP_STORE_VARIABLE, Link, DMP_STORE_VARIABLE_SIGNATURE);
    
    if (((Name == NULL) || gUnicodeCollation->MetaiMatch (gUnicodeCollation, Variable->Name, (CHAR16 *) Name)) &&
        ((Guid == NULL) || CompareGuid (&Variable->Guid, Guid))
       ) {
      Attributes = GetAttrType (Variable->Attributes);
      ShellPrintHiiEx (
        -1, -1, NULL, STRING_TOKEN(STR_DMPSTORE_HEADER_LINE), gShellDebug1HiiHandle,
        Attributes, &Variable->Guid, Variable->Name, Variable->DataSize
        );
      SHELL_FREE_NON_NULL(Attributes);

      *Found = TRUE;
      Status = gRT->SetVariable (
                      Variable->Name,
                      &Variable->Guid,
                      Variable->Attributes,
                      Variable->DataSize,
                      Variable->Data
                      );
      if (EFI_ERROR (Status)) {
        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD_GEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", Variable->Name, Status);  
      }
    }
  }

  for (Link = GetFirstNode (&List); !IsNull (&List, Link); ) {
    Variable = CR (Link, DMP_STORE_VARIABLE, Link, DMP_STORE_VARIABLE_SIGNATURE);
    Link = RemoveEntryList (&Variable->Link);
    FreePool (Variable);
  }

  return ShellStatus;
}
示例#30
0
/**
  Get selection for OneOf and OrderedList (Left/Right will be ignored).

  @param  Selection         Pointer to current selection.
  @param  MenuOption        Pointer to the current input menu.

  @retval EFI_SUCCESS       If Option input is processed successfully
  @retval EFI_DEVICE_ERROR  If operation fails

**/
EFI_STATUS
GetSelectionInputPopUp (
  IN  UI_MENU_SELECTION           *Selection,
  IN  UI_MENU_OPTION              *MenuOption
  )
{
  EFI_STATUS              Status;
  EFI_INPUT_KEY           Key;
  UINTN                   Index;
  CHAR16                  *StringPtr;
  CHAR16                  *TempStringPtr;
  UINTN                   Index2;
  UINTN                   TopOptionIndex;
  UINTN                   HighlightOptionIndex;
  UINTN                   Start;
  UINTN                   End;
  UINTN                   Top;
  UINTN                   Bottom;
  UINTN                   PopUpMenuLines;
  UINTN                   MenuLinesInView;
  UINTN                   PopUpWidth;
  CHAR16                  Character;
  INT32                   SavedAttribute;
  BOOLEAN                 ShowDownArrow;
  BOOLEAN                 ShowUpArrow;
  UINTN                   DimensionsWidth;
  LIST_ENTRY              *Link;
  BOOLEAN                 OrderedList;
  UINT8                   *ValueArray;
  UINT8                   ValueType;
  EFI_HII_VALUE           HiiValue;
  EFI_HII_VALUE           *HiiValueArray;
  UINTN                   OptionCount;
  QUESTION_OPTION         *OneOfOption;
  QUESTION_OPTION         *CurrentOption;
  FORM_BROWSER_STATEMENT  *Question;
  INTN                    Result;

  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;

  ValueArray        = NULL;
  ValueType         = 0;
  CurrentOption     = NULL;
  ShowDownArrow     = FALSE;
  ShowUpArrow       = FALSE;

  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
  ASSERT (StringPtr);

  Question = MenuOption->ThisTag;
  if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {
    ValueArray = Question->BufferValue;
    ValueType = Question->ValueType;
    OrderedList = TRUE;
  } else {
    OrderedList = FALSE;
  }

  //
  // Calculate Option count
  //
  if (OrderedList) {
    for (Index = 0; Index < Question->MaxContainers; Index++) {
      if (GetArrayData (ValueArray, ValueType, Index) == 0) {
        break;
      }
    }

    OptionCount = Index;
  } else {
    OptionCount = 0;
    Link = GetFirstNode (&Question->OptionListHead);
    while (!IsNull (&Question->OptionListHead, Link)) {
      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

      OptionCount++;

      Link = GetNextNode (&Question->OptionListHead, Link);
    }
  }

  //
  // Prepare HiiValue array
  //
  HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));
  ASSERT (HiiValueArray != NULL);
  Link = GetFirstNode (&Question->OptionListHead);
  for (Index = 0; Index < OptionCount; Index++) {
    if (OrderedList) {
      HiiValueArray[Index].Type = ValueType;
      HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
    } else {
      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
      CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE));
      Link = GetNextNode (&Question->OptionListHead, Link);
    }
  }

  //
  // Move Suppressed Option to list tail
  //
  PopUpMenuLines = 0;
  for (Index = 0; Index < OptionCount; Index++) {
    OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);
    if (OneOfOption == NULL) {
      return EFI_NOT_FOUND;
    }

    RemoveEntryList (&OneOfOption->Link);

    if ((OneOfOption->SuppressExpression != NULL) &&
        EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
      //
      // This option is suppressed, insert to tail
      //
      InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
    } else {
      //
      // Insert to head
      //
      InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);

      PopUpMenuLines++;
    }
  }

  //
  // Get the number of one of options present and its size
  //
  PopUpWidth = 0;
  HighlightOptionIndex = 0;
  Link = GetFirstNode (&Question->OptionListHead);
  for (Index = 0; Index < PopUpMenuLines; Index++) {
    OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

    StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
    if (StrLen (StringPtr) > PopUpWidth) {
      PopUpWidth = StrLen (StringPtr);
    }
    FreePool (StringPtr);

    if (!OrderedList && (CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
      //
      // Find current selected Option for OneOf
      //
      HighlightOptionIndex = Index;
    }

    Link = GetNextNode (&Question->OptionListHead, Link);
  }

  //
  // Perform popup menu initialization.
  //
  PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;

  SavedAttribute = gST->ConOut->Mode->Attribute;
  gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);

  if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
    PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
  }

  Start  = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;
  End    = Start + PopUpWidth + POPUP_FRAME_WIDTH;
  Top    = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
  Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 1;

  MenuLinesInView = Bottom - Top - 1;
  if (MenuLinesInView >= PopUpMenuLines) {
    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;
    Bottom  = Top + PopUpMenuLines + 1;
  } else {
    ShowDownArrow = TRUE;
  }

  if (HighlightOptionIndex > (MenuLinesInView - 1)) {
    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
  } else {
    TopOptionIndex = 0;
  }

  do {
    //
    // Clear that portion of the screen
    //
    ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);

    //
    // Draw "One of" pop-up menu
    //
    Character = BOXDRAW_DOWN_RIGHT;
    PrintCharAt (Start, Top, Character);
    for (Index = Start; Index + 2 < End; Index++) {
      if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
        Character = GEOMETRICSHAPE_UP_TRIANGLE;
      } else {
        Character = BOXDRAW_HORIZONTAL;
      }

      PrintChar (Character);
    }

    Character = BOXDRAW_DOWN_LEFT;
    PrintChar (Character);
    Character = BOXDRAW_VERTICAL;
    for (Index = Top + 1; Index < Bottom; Index++) {
      PrintCharAt (Start, Index, Character);
      PrintCharAt (End - 1, Index, Character);
    }

    //
    // Move to top Option
    //
    Link = GetFirstNode (&Question->OptionListHead);
    for (Index = 0; Index < TopOptionIndex; Index++) {
      Link = GetNextNode (&Question->OptionListHead, Link);
    }

    //
    // Display the One of options
    //
    Index2 = Top + 1;
    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
      Link = GetNextNode (&Question->OptionListHead, Link);

      StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
      ASSERT (StringPtr != NULL);
      //
      // If the string occupies multiple lines, truncate it to fit in one line,
      // and append a "..." for indication.
      //
      if (StrLen (StringPtr) > (PopUpWidth - 1)) {
        TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
        ASSERT ( TempStringPtr != NULL );
        CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
        FreePool (StringPtr);
        StringPtr = TempStringPtr;
        StrCat (StringPtr, L"...");
      }

      if (Index == HighlightOptionIndex) {
          //
          // Highlight the selected one
          //
          CurrentOption = OneOfOption;

          gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);
          PrintStringAt (Start + 2, Index2, StringPtr);
          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
        } else {
          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
          PrintStringAt (Start + 2, Index2, StringPtr);
        }

      Index2++;
      FreePool (StringPtr);
    }

    Character = BOXDRAW_UP_RIGHT;
    PrintCharAt (Start, Bottom, Character);
    for (Index = Start; Index + 2 < End; Index++) {
      if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
        Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
      } else {
        Character = BOXDRAW_HORIZONTAL;
      }

      PrintChar (Character);
    }

    Character = BOXDRAW_UP_LEFT;
    PrintChar (Character);

    //
    // Get User selection
    //
    Key.UnicodeChar = CHAR_NULL;
    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
      Key.ScanCode  = gDirection;
      gDirection    = 0;
      goto TheKey;
    }

    Status = WaitForKeyStroke (&Key);

TheKey:
    switch (Key.UnicodeChar) {
    case '+':
      if (OrderedList) {
        if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
          //
          // Highlight reaches the top of the popup window, scroll one menu item.
          //
          TopOptionIndex--;
          ShowDownArrow = TRUE;
        }

        if (TopOptionIndex == 0) {
          ShowUpArrow = FALSE;
        }

        if (HighlightOptionIndex > 0) {
          HighlightOptionIndex--;

          ASSERT (CurrentOption != NULL);
          SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
        }
      }
      break;

    case '-':
      //
      // If an ordered list op-code, we will allow for a popup of +/- keys
      // to create an ordered list of items
      //
      if (OrderedList) {
        if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
          //
          // Highlight reaches the bottom of the popup window, scroll one menu item.
          //
          TopOptionIndex++;
          ShowUpArrow = TRUE;
        }

        if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
          ShowDownArrow = FALSE;
        }

        if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
          HighlightOptionIndex++;

          ASSERT (CurrentOption != NULL);
          SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
        }
      }
      break;

    case CHAR_NULL:
      switch (Key.ScanCode) {
      case SCAN_UP:
      case SCAN_DOWN:
        if (Key.ScanCode == SCAN_UP) {
          if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
            //
            // Highlight reaches the top of the popup window, scroll one menu item.
            //
            TopOptionIndex--;
            ShowDownArrow = TRUE;
          }

          if (TopOptionIndex == 0) {
            ShowUpArrow = FALSE;
          }

          if (HighlightOptionIndex > 0) {
            HighlightOptionIndex--;
          }
        } else {
          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
            //
            // Highlight reaches the bottom of the popup window, scroll one menu item.
            //
            TopOptionIndex++;
            ShowUpArrow = TRUE;
          }

          if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
            ShowDownArrow = FALSE;
          }

          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
            HighlightOptionIndex++;
          }
        }
        break;

      case SCAN_ESC:
        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);

        //
        // Restore link list order for orderedlist
        //
        if (OrderedList) {
          HiiValue.Type = ValueType;
          HiiValue.Value.u64 = 0;
          for (Index = 0; Index < Question->MaxContainers; Index++) {
            HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
            if (HiiValue.Value.u64 == 0) {
              break;
            }

            OneOfOption = ValueToOption (Question, &HiiValue);
            if (OneOfOption == NULL) {
              return EFI_NOT_FOUND;
            }

            RemoveEntryList (&OneOfOption->Link);
            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
          }
        }

        FreePool (HiiValueArray);
        return EFI_DEVICE_ERROR;

      default:
        break;
      }

      break;

    case CHAR_CARRIAGE_RETURN:
      //
      // return the current selection
      //
      if (OrderedList) {
        Index = 0;
        Link = GetFirstNode (&Question->OptionListHead);
        while (!IsNull (&Question->OptionListHead, Link)) {
          OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

          SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64);

          Index++;
          if (Index > Question->MaxContainers) {
            break;
          }

          Link = GetNextNode (&Question->OptionListHead, Link);
        }
      } else {
        ASSERT (CurrentOption != NULL);
        CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));
      }

      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
      FreePool (HiiValueArray);

      Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
      if (EFI_ERROR (Status)) {
        //
        // Input value is not valid, restore Question Value
        //
        GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
      } else {
        SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
        UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
      }

      return Status;

    default:
      break;
    }
  } while (TRUE);

}