You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
555 lines
16 KiB
555 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1995-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
efidrvent.c
|
|
|
|
Abstract:
|
|
|
|
Contains the EFI driver entry abstraction implementation.
|
|
|
|
Author:
|
|
|
|
Mandar Gokhale ([email protected]) 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;
|
|
}
|