|
|
/*++
Copyright (c) 1995-2001 Microsoft Corporation
Module Name:
efidrvent.c
Abstract:
Contains the EFI driver entry abstraction implementation.
Author:
Mandar Gokhale (MandarG@microsoft.com) 14-June-2002
Revision History:
None.
--*/
#include <efidrvent.h>
#include <ntosp.h>
#include <efi.h>
#include <stdio.h>
static NTSTATUS EFIDEAddOrUpdateDriverEntry( IN PDRIVER_ENTRY This, IN BOOLEAN IsUpdate ) /*++
Description: Modify or update a driver entry.
Arguments: This - Driver entry .
IsUpdate - whether this is a driver entry update or add.
Return Value: NTSTATUS or add/modify driver operation. --*/ { //
// Add this as new boot entry
//
ULONG FullPathLength = 0; ULONG DevicePathLength = 0; ULONG SrcPathLength = 0; ULONG FriendlyNameOffset = 0; ULONG FriendlyNameLength = 0; ULONG FilePathLength = 0; ULONG EntryLength = 0; ULONG DriverEntryLength = 0; PEFI_DRIVER_ENTRY DriverEntry = NULL; PFILE_PATH FilePath; NTSTATUS Status;
DevicePathLength = (wcslen((PCWSTR)This->NtDevicePath)+ 1) * sizeof(WCHAR); SrcPathLength = (wcslen((PCWSTR)This->DirPath) + 1) * sizeof(WCHAR); FullPathLength = DevicePathLength + SrcPathLength; FriendlyNameOffset = ALIGN_UP(sizeof(EFI_DRIVER_ENTRY), WCHAR); FriendlyNameLength = (wcslen(This->FriendlyName) + 1) * sizeof(WCHAR); FilePathLength = FIELD_OFFSET(FILE_PATH, FilePath) + FullPathLength; EntryLength = FriendlyNameOffset + ALIGN_UP(FriendlyNameLength, ULONG) + FilePathLength; DriverEntry = SBE_MALLOC(EntryLength);
DriverEntry->Version = EFI_DRIVER_ENTRY_VERSION; DriverEntry->Length = EntryLength; DriverEntry->FriendlyNameOffset = FriendlyNameOffset; DriverEntry->DriverFilePathOffset = FriendlyNameOffset + ALIGN_UP(FriendlyNameLength, ULONG); RtlCopyMemory((PCHAR) DriverEntry + DriverEntry->FriendlyNameOffset, This->FriendlyName, FriendlyNameLength);
FilePath = (PFILE_PATH) ((PCHAR) DriverEntry + DriverEntry->DriverFilePathOffset); FilePath->Version = FILE_PATH_VERSION; FilePath->Length = FilePathLength; FilePath->Type = FILE_PATH_TYPE_NT; RtlCopyMemory(FilePath->FilePath, This->NtDevicePath, DevicePathLength ); RtlCopyMemory(FilePath->FilePath + DevicePathLength, This->DirPath, SrcPathLength);
if (IsUpdate){ //
// Update the driver.
//
DriverEntry->Id = This->Id; Status = NtModifyDriverEntry(DriverEntry); } else { //
// Add a new driver entry.
//
Status = NtAddDriverEntry(DriverEntry, &(This->Id)); }
//
// Free allocated memory.
//
if(DriverEntry){ SBE_FREE(DriverEntry); } return Status; }
static BOOLEAN EFIDEFlushDriverEntry( IN PDRIVER_ENTRY This // Points to the driver List.
) {
BOOLEAN Result = FALSE; if (This) { NTSTATUS Status = STATUS_SUCCESS; if (DRIVERENT_IS_DIRTY(This)) { if (DRIVERENT_IS_DELETED(This)) { //
// Delete this entry
//
Status = NtDeleteDriverEntry(This->Id); } else if (DRIVERENT_IS_NEW(This)) { //
// Add new Entry.
//
Status = EFIDEAddOrUpdateDriverEntry(This, FALSE); } else { //
// Just update this boot entry
//
Status = EFIDEAddOrUpdateDriverEntry(This, TRUE); }
if (NT_SUCCESS(Status)) { DRIVERENT_RESET_DIRTY(This); Result = TRUE; } } else { Result = TRUE; // nothing to flush
} }
return Result; }
__inline BOOLEAN EFIDEDriverMatch( IN PDRIVER_ENTRY DriverEntry , IN PCWSTR SrcNtFullPath ) { BOOLEAN Result = FALSE; if (!_wcsicmp(DriverEntry->FileName, (wcsrchr(SrcNtFullPath,L'\\')+1))){ Result = TRUE; }
return(Result); }
static PDRIVER_ENTRY EFIDESearchForDriverEntry( IN POS_BOOT_OPTIONS This, IN PCWSTR SrcNtFullPath ) /*++
Description: Searches our internal list of driver entries for a match. It looks up the driver name (not including the path) for a match. so a\b\c\driver.sys and e\f\driver.sys would be a match. --*/ { PDRIVER_ENTRY CurrentDriverEntry = NULL; if (This && SrcNtFullPath){ CurrentDriverEntry = This->DriverEntries; while (CurrentDriverEntry){ if (EFIDEDriverMatch(CurrentDriverEntry, SrcNtFullPath)){ break; } CurrentDriverEntry = OSBOGetNextDriverEntry(This, CurrentDriverEntry); } } return (CurrentDriverEntry); }
PDRIVER_ENTRY EFIDECreateNewDriverEntry( IN POS_BOOT_OPTIONS This, IN PCWSTR FriendlyName, IN PCWSTR NtDevicePath, IN PCWSTR DirPath ) { PDRIVER_ENTRY DriverEntry = NULL; if (This && FriendlyName && DirPath && NtDevicePath){ PDRIVER_ENTRY CurrentDriverEntry = NULL;
DriverEntry = (PDRIVER_ENTRY)SBE_MALLOC(sizeof(DRIVER_ENTRY)); memset(DriverEntry, 0, sizeof(DRIVER_ENTRY));
EFIDEDriverEntryInit(DriverEntry); DriverEntry->BootOptions = This; //
// Set information for the driver entry.
//
OSDriverSetFileName(DriverEntry, DirPath); OSDriverSetNtPath(DriverEntry, NtDevicePath); OSDriverSetDirPath(DriverEntry, DirPath); OSDriverSetFriendlyName(DriverEntry, FriendlyName);
//
// Mark the driver entry new and dirty.
//
DRIVERENT_SET_NEW(DriverEntry); DRIVERENT_SET_DIRTY(DriverEntry); } return (DriverEntry); }
PDRIVER_ENTRY EFIOSBOInsertDriverListNewEntry( IN POS_BOOT_OPTIONS This, IN PDRIVER_ENTRY DriverEntry )
{
if (This && DriverEntry){ PDRIVER_ENTRY CurrentDriverEntry = NULL; //
// Insert into the list.
//
if (NULL == This->DriverEntries){ //
// No driver entries, this is the first one.
//
This->DriverEntries = DriverEntry; }else{ //
// Insert in the existing list.
//
DriverEntry->NextEntry = This->DriverEntries; This->DriverEntries = DriverEntry; } } return (DriverEntry);
}
PDRIVER_ENTRY EFIDEAddNewDriverEntry( IN POS_BOOT_OPTIONS This, IN PCWSTR FriendlyName, IN PCWSTR NtDevicePath, IN PCWSTR SrcNtFullPath ) /*++
Description: Used to add a new driver entry in NVRAM.
--*/ { PEFI_DRIVER_ENTRY_LIST DriverList = NULL; // list of driver entries
PDRIVER_ENTRY DriverEntry = NULL; if (This && FriendlyName && SrcNtFullPath && NtDevicePath){ DriverEntry = EFIDECreateNewDriverEntry(This, FriendlyName, NtDevicePath, SrcNtFullPath); //
// Mark it as new
//
DRIVERENT_IS_NEW(DriverEntry); //
// flush the entry,
// see status, if successful put it in the list (only if new)
// otherwise free it
//
if (!OSDriverEntryFlush(DriverEntry)){ SBE_FREE(DriverEntry); DriverEntry = NULL; } else { ULONG OrderCount; PULONG NewOrder; //
// If the driver was newly added one then insert it in the driver list.
//
if (DRIVERENT_IS_NEW(DriverEntry)){ EFIOSBOInsertDriverListNewEntry(This, DriverEntry);
//
// Increment the count of the number of driver entries in the list.
//
This->DriverEntryCount++; //
// Put the new entry at the end of the boot order
//
OrderCount = OSBOGetOrderedDriverEntryCount(This);
NewOrder = (PULONG)SBE_MALLOC((OrderCount + 1) * sizeof(ULONG));
if (NewOrder) { memset(NewOrder, 0, sizeof(ULONG) * (OrderCount + 1));
//
// copy over the old ordered list
//
memcpy(NewOrder, This->DriverEntryOrder, sizeof(ULONG) * OrderCount); NewOrder[OrderCount] = OSDriverGetId((PDRIVER_ENTRY)DriverEntry); SBE_FREE(This->DriverEntryOrder); This->DriverEntryOrder = NewOrder; This->DriverEntryOrderCount = OrderCount + 1; } else { //
// Remove the driver entry out of the link list.
// Just freeing it will cause memory leaks.
// TBD: decide if we want to delete this driver entry too
//
This->DriverEntries = DriverEntry->NextEntry; SBE_FREE(DriverEntry); DriverEntry = NULL; } } } } return DriverEntry; }
__inline ULONG EFIDESetDriverId( IN PDRIVER_ENTRY This, IN ULONG DriverId ) { if (This){ This->Id = DriverId; } return (DriverId); }
PDRIVER_ENTRY EFIDECreateDriverEntry(PEFI_DRIVER_ENTRY_LIST Entry, POS_BOOT_OPTIONS This ) /*++
Description: Used to interpret a driver entry returned by NtEnumerateDriverEntries(..) into our format.
Arguments: Entry - EFI format driver entry returned to us by NT. This - container for the driver entry list that we generate.
Return: PDRIVER_ENTRY ( driver entry in our format). --*/
{ PDRIVER_ENTRY ResultDriverEntry = NULL;
if (Entry && This){ PFILE_PATH FilePath = (PFILE_PATH) ((PCHAR) &Entry->DriverEntry + Entry->DriverEntry.DriverFilePathOffset); PWCHAR FriendlyName = (PWCHAR)((PCHAR)&Entry->DriverEntry + Entry->DriverEntry.FriendlyNameOffset); ULONG NtDevicePathLength = 0; PDRIVER_ENTRY DriverEntry = NULL; PFILE_PATH DriverOptionPath = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL;
if(FilePath->Type != FILE_PATH_TYPE_NT) { PVOID Buffer; ULONG PathLength = 0; Status = NtTranslateFilePath(FilePath, FILE_PATH_TYPE_NT, NULL, &PathLength);
if(NT_SUCCESS(Status)) { Status = STATUS_UNSUCCESSFUL; }
if(STATUS_BUFFER_TOO_SMALL == Status) { ASSERT(PathLength != 0); DriverOptionPath = (PFILE_PATH)SBE_MALLOC(PathLength); memset(DriverOptionPath, 0, sizeof(PathLength)); Status = NtTranslateFilePath(FilePath, FILE_PATH_TYPE_NT, DriverOptionPath, &PathLength); }
if(!NT_SUCCESS(Status)) { if(STATUS_OBJECT_PATH_NOT_FOUND == Status || STATUS_OBJECT_NAME_NOT_FOUND == Status) { //
// This entry is stale; remove it
//
NtDeleteDriverEntry(Entry->DriverEntry.Id); }
//
// Free the DriverOptionPath memory
//
if(DriverOptionPath != NULL) { SBE_FREE(DriverOptionPath); DriverOptionPath = NULL; } } } if (DriverOptionPath){ ULONG FilePathLength = 0; DriverEntry = (PDRIVER_ENTRY)SBE_MALLOC(sizeof(DRIVER_ENTRY)); memset(DriverEntry, 0, sizeof(DRIVER_ENTRY)); //
// Set pointer back to boot options (container).
//
DriverEntry->BootOptions = This;
EFIDEDriverEntryInit(DriverEntry); //
// Set driver ID.
//
EFIDESetDriverId(DriverEntry, Entry->DriverEntry.Id);
//
// Set File Name.
//
NtDevicePathLength = wcslen((PCWSTR) DriverOptionPath->FilePath) + 1; OSDriverSetFileName(DriverEntry, (PCWSTR) DriverOptionPath->FilePath + NtDevicePathLength);
//
// Set NT path and Driver dir.
//
OSDriverSetNtPath(DriverEntry, (PCWSTR)DriverOptionPath->FilePath); OSDriverSetDirPath(DriverEntry, (PCWSTR)(DriverOptionPath->FilePath) + NtDevicePathLength);
//
// Set Friendly Name.
//
OSDriverSetFriendlyName(DriverEntry, FriendlyName);
//
// Free the DriverOptionPath memory
//
if(DriverOptionPath != NULL) { SBE_FREE(DriverOptionPath); }
ResultDriverEntry = DriverEntry; } } return ResultDriverEntry; }
NTSTATUS EFIDEInterpretDriverEntries( IN POS_BOOT_OPTIONS This, IN PEFI_DRIVER_ENTRY_LIST DriverList ) /*++
Description: Used to interpret the driver entries returned by NtEnumerateDriverEntries(..) into our format.
Arguments: This - container for the driver entry list that we generate.
DriverList - Driver list returned by NtEnumerateDriverEntries(..).
Return: NTSTATUS code. --*/ { NTSTATUS Status = STATUS_UNSUCCESSFUL; if (This && DriverList){ PEFI_DRIVER_ENTRY_LIST Entry; PDRIVER_ENTRY DriverEntry = NULL; BOOLEAN Continue = TRUE;
Status = STATUS_SUCCESS; for(Entry = DriverList; Continue; Entry = (PEFI_DRIVER_ENTRY_LIST) ((PCHAR) Entry + Entry->NextEntryOffset)) {
Continue = (Entry->NextEntryOffset != 0); DriverEntry = EFIDECreateDriverEntry(Entry, This);
if (DriverEntry){ //
// Insert into the list of drivers in the OSBO structure.
//
if (NULL == This->DriverEntries){ This->DriverEntries = DriverEntry; } else{ DriverEntry->NextEntry = This->DriverEntries; This->DriverEntries = DriverEntry; } This->DriverEntryCount++; } } }
return Status; }
static VOID EFIDEDriverEntryInit( IN PDRIVER_ENTRY This ) { This->Flush = EFIDEFlushDriverEntry; }
|