/**@file Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
(C) Copyright 2018 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent Module Name: WinNtBusDriver.c Abstract: This following section documents the envirnoment variables for the Win NT build. These variables are used to define the (virtual) hardware configuration of the NT environment A ! can be used to seperate multiple instances in a variable. Each instance represents a seperate hardware device. EFI_WIN_NT_PHYSICAL_DISKS - maps to drives on your system EFI_WIN_NT_VIRTUAL_DISKS - maps to a device emulated by a file EFI_WIN_NT_FILE_SYSTEM - mouts a directory as a file system EFI_WIN_NT_CONSOLE - make a logical comand line window (only one!) EFI_WIN_NT_GOP - Builds GOP Windows of Width and Height EFI_WIN_NT_SERIAL_PORT - maps physical serial ports ixed - Fixed disk like a hard drive. emovable - Removable media like a floppy or CD-ROM. Read nly - Write protected device. Read rite - Read write device. - Decimal number of blocks a device supports. - Decimal number of bytes per block. NT envirnonment variable contents. '<' and '>' are not part of the variable, they are just used to make this help more readable. There should be no spaces between the ';'. Extra spaces will break the variable. A '!' is used to seperate multiple devices in a variable. EFI_WIN_NT_VIRTUAL_DISKS = ;;[!...] EFI_WIN_NT_PHYSICAL_DISKS = :;;[!...] Virtual Disks: These devices use a file to emulate a hard disk or removable media device. Thus a 20 MB emulated hard drive would look like: EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512 A 1.44MB emulated floppy with a block size of 1024 would look like: EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024 Physical Disks: These devices use NT to open a real device in your system Thus a 120 MB floppy would look like: EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512 Thus a standard CD-ROM floppy would look like: EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048 EFI_WIN_NT_FILE_SYSTEM = [!...] Mounting the two directories C:\FOO and C:\BAR would look like: EFI_WIN_NT_FILE_SYSTEM=c:\foo!c:\bar EFI_WIN_NT_CONSOLE = Declaring a text console window with the title "My EFI Console" woild look like: EFI_WIN_NT_CONSOLE=My EFI Console EFI_WIN_NT_GOP = [!...] Declaring a two GOP windows with resolutions of 800x600 and 1024x768 would look like: Example : EFI_WIN_NT_GOP=800 600!1024 768 EFI_WIN_NT_SERIAL_PORT = [!...] Declaring two serial ports on COM1 and COM2 would look like: Example : EFI_WIN_NT_SERIAL_PORT=COM1!COM2 EFI_WIN_NT_PASS_THROUGH = ;;; Declaring a base address of 0xE0000000 (used for PCI Express devices) and having NT32 talk to a device located at bus 0, device 1, function 0: Example : EFI_WIN_NT_PASS_THROUGH=E000000;0;1;0 ---*/ // // The package level header files this module uses // #include #include // // The protocols, PPI and GUID defintions for this module // #include #include #include #include #include // // The Library classes this module consumes // #include #include #include #include #include #include #include #include #include #include "WinNtBusDriver.h" extern EFI_GUID gWinNtBusDriverGuid; // // DriverBinding protocol global // EFI_DRIVER_BINDING_PROTOCOL gWinNtBusDriverBinding = { WinNtBusDriverBindingSupported, WinNtBusDriverBindingStart, WinNtBusDriverBindingStop, 0xa, NULL, NULL }; #define NT_PCD_ARRAY_SIZE (sizeof(mPcdEnvironment)/sizeof(NT_PCD_ENTRY)) // // Table to map NT Environment variable to the GUID that should be in // device path. // NT_PCD_ENTRY mPcdEnvironment[] = { PcdToken(PcdWinNtConsole), &gEfiWinNtConsoleGuid, PcdToken(PcdWinNtGop), &gEfiWinNtGopGuid, PcdToken(PcdWinNtSerialPort), &gEfiWinNtSerialPortGuid, PcdToken(PcdWinNtFileSystem), &gEfiWinNtFileSystemGuid, PcdToken(PcdWinNtVirtualDisk), &gEfiWinNtVirtualDisksGuid, PcdToken(PcdWinNtPhysicalDisk), &gEfiWinNtPhysicalDisksGuid }; /** The user Entry Point for module WinNtBusDriver. The user code starts with this function. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI InitializeWinNtBusDriver( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; // // Install driver model protocol(s). // Status = EfiLibInstallDriverBindingComponentName2 ( ImageHandle, SystemTable, &gWinNtBusDriverBinding, ImageHandle, &gWinNtBusDriverComponentName, &gWinNtBusDriverComponentName2 ); ASSERT_EFI_ERROR (Status); return Status; } VOID * AllocateMemory ( IN UINTN Size ) { VOID *Buffer; Buffer = AllocatePool (Size); ASSERT (Buffer != NULL); return Buffer; } EFI_STATUS EFIAPI WinNtBusDriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) /*++ Routine Description: Arguments: Returns: None **/ // TODO: This - add argument and description to function comment // TODO: ControllerHandle - add argument and description to function comment // TODO: RemainingDevicePath - add argument and description to function comment // TODO: EFI_UNSUPPORTED - add return value to function comment // TODO: EFI_UNSUPPORTED - add return value to function comment // TODO: EFI_SUCCESS - add return value to function comment // TODO: EFI_SUCCESS - add return value to function comment { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; UINTN Index; // // Check the contents of the first Device Path Node of RemainingDevicePath to make sure // it is a legal Device Path Node for this bus driver's children. // if (RemainingDevicePath != NULL) { // // Check if RemainingDevicePath is the End of Device Path Node, // if yes, go on checking other conditions // if (!IsDevicePathEnd (RemainingDevicePath)) { // // If RemainingDevicePath isn't the End of Device Path Node, // check its validation // if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH || RemainingDevicePath->SubType != HW_VENDOR_DP || DevicePathNodeLength(RemainingDevicePath) != sizeof(WIN_NT_VENDOR_DEVICE_PATH_NODE)) { return EFI_UNSUPPORTED; } for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) { if (CompareGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid, mPcdEnvironment[Index].DevicePathGuid)) { break; } } if (Index >= NT_PCD_ARRAY_SIZE) { return EFI_UNSUPPORTED; } } } // // Open the IO Abstraction(s) needed to perform the supported test // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiWinNtThunkProtocolGuid, (VOID **) &WinNtThunk, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (Status == EFI_ALREADY_STARTED) { return EFI_SUCCESS; } if (EFI_ERROR (Status)) { return Status; } // // Close the I/O Abstraction(s) used to perform the supported test // gBS->CloseProtocol ( ControllerHandle, &gEfiWinNtThunkProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Open the EFI Device Path protocol needed to perform the supported test // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (Status == EFI_ALREADY_STARTED) { return EFI_SUCCESS; } if (EFI_ERROR (Status)) { return Status; } // // Since we call through WinNtThunk we need to make sure it's valid // Status = EFI_SUCCESS; if (WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) { Status = EFI_UNSUPPORTED; } // // Close protocol, don't use device path protocol in the Support() function // gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); return Status; } EFI_STATUS EFIAPI WinNtBusDriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) /*++ Routine Description: Arguments: Returns: None --*/ // TODO: This - add argument and description to function comment // TODO: ControllerHandle - add argument and description to function comment // TODO: RemainingDevicePath - add argument and description to function comment // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment // TODO: EFI_SUCCESS - add return value to function comment { EFI_STATUS Status; EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; WIN_NT_BUS_DEVICE *WinNtBusDevice; WIN_NT_IO_DEVICE *WinNtDevice; UINTN Index; CHAR16 *StartString; CHAR16 *SubString; UINT16 Count; UINTN StringSize; UINT16 ComponentName[MAX_NT_ENVIRNMENT_VARIABLE_LENGTH]; WIN_NT_VENDOR_DEVICE_PATH_NODE *Node; BOOLEAN CreateDevice; CHAR16 *TempStr; CHAR16 *PcdTempStr; UINTN TempStrSize; Status = EFI_UNSUPPORTED; // // Grab the protocols we need // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **) &ParentDevicePath, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { return Status; } Status = gBS->OpenProtocol ( ControllerHandle, &gEfiWinNtThunkProtocolGuid, (VOID **) &WinNtThunk, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { return Status; } if (Status != EFI_ALREADY_STARTED) { WinNtBusDevice = AllocatePool (sizeof (WIN_NT_BUS_DEVICE)); if (WinNtBusDevice == NULL) { return EFI_OUT_OF_RESOURCES; } WinNtBusDevice->Signature = WIN_NT_BUS_DEVICE_SIGNATURE; WinNtBusDevice->ControllerNameTable = NULL; AddUnicodeString2 ( "eng", gWinNtBusDriverComponentName.SupportedLanguages, &WinNtBusDevice->ControllerNameTable, L"Windows Bus Controller", TRUE ); AddUnicodeString2 ( "en", gWinNtBusDriverComponentName2.SupportedLanguages, &WinNtBusDevice->ControllerNameTable, L"Windows Bus Controller", FALSE ); Status = gBS->InstallMultipleProtocolInterfaces ( &ControllerHandle, &gWinNtBusDriverGuid, WinNtBusDevice, NULL ); if (EFI_ERROR (Status)) { FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable); FreePool (WinNtBusDevice); return Status; } } // // Loop on the Variable list. Parse each variable to produce a set of handles that // represent virtual hardware devices. // for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) { PcdTempStr = (VOID *)LibPcdGetPtr (mPcdEnvironment[Index].Token); ASSERT (PcdTempStr != NULL); TempStrSize = StrLen (PcdTempStr); TempStr = AllocateMemory (((TempStrSize + 1) * sizeof (CHAR16))); StrCpy (TempStr, PcdTempStr); StartString = TempStr; // // Parse the envirnment variable into sub strings using '!' as a delimator. // Each substring needs it's own handle to be added to the system. This code // does not understand the sub string. Thats the device drivers job. // Count = 0; while (*StartString != '\0') { // // Find the end of the sub string // SubString = StartString; while (*SubString != '\0' && *SubString != '!') { SubString++; } if (*SubString == '!') { // // Replace token with '\0' to make sub strings. If this is the end // of the string SubString will already point to NULL. // *SubString = '\0'; SubString++; } CreateDevice = TRUE; if (RemainingDevicePath != NULL) { CreateDevice = FALSE; // // Check if RemainingDevicePath is the End of Device Path Node, // if yes, don't create any child device // if (!IsDevicePathEnd (RemainingDevicePath)) { // // If RemainingDevicePath isn't the End of Device Path Node, // check its validation // Node = (WIN_NT_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath; if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH && Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP && DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE) ) { if (CompareGuid (&Node->VendorDevicePath.Guid, mPcdEnvironment[Index].DevicePathGuid) && Node->Instance == Count ) { CreateDevice = TRUE; } } } } if (CreateDevice) { // // Allocate instance structure, and fill in parent information. // WinNtDevice = AllocateMemory (sizeof (WIN_NT_IO_DEVICE)); if (WinNtDevice == NULL) { return EFI_OUT_OF_RESOURCES; } WinNtDevice->Handle = NULL; WinNtDevice->ControllerHandle = ControllerHandle; WinNtDevice->ParentDevicePath = ParentDevicePath; WinNtDevice->WinNtIo.WinNtThunk = WinNtThunk; // // Plus 2 to account for the NULL at the end of the Unicode string // StringSize = (UINTN) ((UINT8 *) SubString - (UINT8 *) StartString) + sizeof (CHAR16); WinNtDevice->WinNtIo.EnvString = AllocateMemory (StringSize); if (WinNtDevice->WinNtIo.EnvString != NULL) { CopyMem (WinNtDevice->WinNtIo.EnvString, StartString, StringSize); } WinNtDevice->ControllerNameTable = NULL; WinNtThunk->SPrintf (ComponentName, sizeof (ComponentName), L"%s", WinNtDevice->WinNtIo.EnvString); WinNtDevice->DevicePath = WinNtBusCreateDevicePath ( ParentDevicePath, mPcdEnvironment[Index].DevicePathGuid, Count ); if (WinNtDevice->DevicePath == NULL) { FreePool (WinNtDevice); return EFI_OUT_OF_RESOURCES; } AddUnicodeString2 ( "eng", gWinNtBusDriverComponentName.SupportedLanguages, &WinNtDevice->ControllerNameTable, ComponentName, TRUE ); AddUnicodeString2 ( "en", gWinNtBusDriverComponentName2.SupportedLanguages, &WinNtDevice->ControllerNameTable, ComponentName, FALSE ); WinNtDevice->WinNtIo.TypeGuid = mPcdEnvironment[Index].DevicePathGuid; WinNtDevice->WinNtIo.InstanceNumber = Count; WinNtDevice->Signature = WIN_NT_IO_DEVICE_SIGNATURE; Status = gBS->InstallMultipleProtocolInterfaces ( &WinNtDevice->Handle, &gEfiDevicePathProtocolGuid, WinNtDevice->DevicePath, &gEfiWinNtIoProtocolGuid, &WinNtDevice->WinNtIo, NULL ); if (EFI_ERROR (Status)) { FreeUnicodeStringTable (WinNtDevice->ControllerNameTable); FreePool (WinNtDevice); } else { // // Open For Child Device // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiWinNtThunkProtocolGuid, (VOID **) &WinNtThunk, This->DriverBindingHandle, WinNtDevice->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } } // // Parse Next sub string. This will point to '\0' if we are at the end. // Count++; StartString = SubString; } FreePool (TempStr); } return EFI_SUCCESS; } EFI_STATUS EFIAPI WinNtBusDriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) /*++ Routine Description: Arguments: Returns: None --*/ // TODO: This - add argument and description to function comment // TODO: ControllerHandle - add argument and description to function comment // TODO: NumberOfChildren - add argument and description to function comment // TODO: ChildHandleBuffer - add argument and description to function comment // TODO: EFI_SUCCESS - add return value to function comment // TODO: EFI_DEVICE_ERROR - add return value to function comment // TODO: EFI_SUCCESS - add return value to function comment { EFI_STATUS Status; UINTN Index; BOOLEAN AllChildrenStopped; EFI_WIN_NT_IO_PROTOCOL *WinNtIo; WIN_NT_BUS_DEVICE *WinNtBusDevice; WIN_NT_IO_DEVICE *WinNtDevice; EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk; // // Complete all outstanding transactions to Controller. // Don't allow any new transaction to Controller to be started. // if (NumberOfChildren == 0) { // // Close the bus driver // Status = gBS->OpenProtocol ( ControllerHandle, &gWinNtBusDriverGuid, (VOID **) &WinNtBusDevice, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return Status; } gBS->UninstallMultipleProtocolInterfaces ( ControllerHandle, &gWinNtBusDriverGuid, WinNtBusDevice, NULL ); FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable); FreePool (WinNtBusDevice); gBS->CloseProtocol ( ControllerHandle, &gEfiWinNtThunkProtocolGuid, This->DriverBindingHandle, ControllerHandle ); gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { Status = gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiWinNtIoProtocolGuid, (VOID **) &WinNtIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (!EFI_ERROR (Status)) { WinNtDevice = WIN_NT_IO_DEVICE_FROM_THIS (WinNtIo); Status = gBS->CloseProtocol ( ControllerHandle, &gEfiWinNtThunkProtocolGuid, This->DriverBindingHandle, WinNtDevice->Handle ); Status = gBS->UninstallMultipleProtocolInterfaces ( WinNtDevice->Handle, &gEfiDevicePathProtocolGuid, WinNtDevice->DevicePath, &gEfiWinNtIoProtocolGuid, &WinNtDevice->WinNtIo, NULL ); if (EFI_ERROR (Status)) { gBS->OpenProtocol ( ControllerHandle, &gEfiWinNtThunkProtocolGuid, (VOID **) &WinNtThunk, This->DriverBindingHandle, WinNtDevice->Handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { // // Close the child handle // FreeUnicodeStringTable (WinNtDevice->ControllerNameTable); FreePool (WinNtDevice); } } if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; } EFI_DEVICE_PATH_PROTOCOL * WinNtBusCreateDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *RootDevicePath, IN EFI_GUID *Guid, IN UINT16 InstanceNumber ) /*++ Routine Description: Create a device path node using Guid and InstanceNumber and append it to the passed in RootDevicePath Arguments: RootDevicePath - Root of the device path to return. Guid - GUID to use in vendor device path node. InstanceNumber - Instance number to use in the vendor device path. This argument is needed to make sure each device path is unique. Returns: EFI_DEVICE_PATH_PROTOCOL --*/ { WIN_NT_VENDOR_DEVICE_PATH_NODE DevicePath; DevicePath.VendorDevicePath.Header.Type = HARDWARE_DEVICE_PATH; DevicePath.VendorDevicePath.Header.SubType = HW_VENDOR_DP; SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)); // // The GUID defines the Class // CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID)); // // Add an instance number so we can make sure there are no Device Path // duplication. // DevicePath.Instance = InstanceNumber; return AppendDevicePathNode ( RootDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath ); }