diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg')
48 files changed, 7198 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/ComponentName.c new file mode 100644 index 00000000..8858186a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/ComponentName.c @@ -0,0 +1,171 @@ +/** @file + This portion is to register the IDE Controller Driver name: + "IDE Controller Init Driver" + + Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "IdeController.h" + +// +/// EFI Component Name Protocol +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIdeControllerComponentName = { + IdeControllerComponentNameGetDriverName, + IdeControllerComponentNameGetControllerName, + "eng" +}; + +// +/// EFI Component Name 2 Protocol +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIdeControllerComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IdeControllerComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IdeControllerComponentNameGetControllerName, + "en" +}; + +// +/// Driver Name Strings +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIdeControllerDriverNameTable[] = { + { + "eng;en", + (CHAR16 *)L"IDE Controller Init Driver" + }, + { + NULL, + NULL + } +}; + +/// +/// Controller Name Strings +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIdeControllerControllerNameTable[] = { + { + "eng;en", + (CHAR16 *)L"PCAT IDE Controller" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +IdeControllerComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mIdeControllerDriverNameTable, + DriverName, + (BOOLEAN)(This == &gIdeControllerComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param ChildHandle OPTIONAL The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +IdeControllerComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + + // + // Make sure this driver is currently managing ControllHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gIdeControllerDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mIdeControllerControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gIdeControllerComponentName) + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.c new file mode 100644 index 00000000..439d3198 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.c @@ -0,0 +1,750 @@ +/** @file + This driver module produces IDE_CONTROLLER_INIT protocol and will be used by + IDE Bus driver to support platform dependent timing information. This driver + is responsible for early initialization of IDE controller. + + Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "IdeController.h" + +/// +/// EFI_DRIVER_BINDING_PROTOCOL instance +/// +EFI_DRIVER_BINDING_PROTOCOL gIdeControllerDriverBinding = { + IdeControllerSupported, + IdeControllerStart, + IdeControllerStop, + 0xa, + NULL, + NULL +}; + +/// +/// EFI_IDE_CONTROLLER_PRIVATE_DATA Template +/// +#ifndef VBOX +EFI_IDE_CONTROLLER_INIT_PROTOCOL gEfiIdeControllerInit = { + IdeInitGetChannelInfo, + IdeInitNotifyPhase, + IdeInitSubmitData, + IdeInitDisqualifyMode, + IdeInitCalculateMode, + IdeInitSetTiming, + ICH_IDE_ENUMER_ALL, + ICH_IDE_MAX_CHANNEL +}; +#else +typedef struct { + EFI_IDE_CONTROLLER_INIT_PROTOCOL Core; + EFI_PCI_IO_PROTOCOL *pIdeControllerProtocol_PciIo; +} IDECONTROLLERINITPROTOCOL; + +IDECONTROLLERINITPROTOCOL gEfiIdeControllerInit = +{ + { + IdeInitGetChannelInfo, + IdeInitNotifyPhase, + IdeInitSubmitData, + IdeInitDisqualifyMode, + IdeInitCalculateMode, + IdeInitSetTiming, + ICH_IDE_ENUMER_ALL, + ICH_IDE_MAX_CHANNEL + }, + NULL +}; +#endif + +/// +/// EFI_ATA_COLLECTIVE_MODE Template +/// +EFI_ATA_COLLECTIVE_MODE gEfiAtaCollectiveModeTemplate = { + { + TRUE, ///< PioMode.Valid + 0 ///< PioMode.Mode + }, + { + TRUE, ///< SingleWordDmaMode.Valid + 0 + }, + { + FALSE, ///< MultiWordDmaMode.Valid + 0 + }, + { + TRUE, ///< UdmaMode.Valid + 0 ///< UdmaMode.Mode + } +}; + +#ifdef VBOX +static EFI_STATUS GetPciIo(EFI_DRIVER_BINDING_PROTOCOL *This, EFI_HANDLE hController, EFI_PCI_IO_PROTOCOL **ppPciIo) +{ + EFI_STATUS Status = EFI_INVALID_PARAMETER; + VBoxLogFlowFuncEnter(); + if (!ppPciIo) + { + VBoxLogFlowFuncLeaveRC(Status); + return Status; + } + Status = gBS->OpenProtocol ( + hController, + &gEfiPciIoProtocolGuid, + (VOID **) ppPciIo, + This->DriverBindingHandle, + hController, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + VBoxLogFlowFuncLeaveRC(Status); + return Status; +} +#endif /* VBOX */ + +/** + Chipset Ide Driver EntryPoint function. It follows the standard EFI driver model. + It's called by StartImage() of DXE Core. + + @param ImageHandle While the driver image loaded be the ImageLoader(), + an image handle is assigned to this driver binary, + all activities of the driver is tied to this ImageHandle + @param SystemTable A pointer to the system table, for all BS(Boo Services) and + RT(Runtime Services) + + @return EFI_STATUS Status of EfiLibInstallDriverBindingComponentName2(). +**/ +EFI_STATUS +EFIAPI +InitializeIdeControllerDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gIdeControllerDriverBinding, + ImageHandle, + &gIdeControllerComponentName, + &gIdeControllerComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Register Driver Binding protocol for this driver. + + @param This A pointer points to the Binding Protocol instance + @param Controller The handle of controller to be tested. + @param RemainingDevicePath A pointer to the device path. Ignored by device + driver but used by bus driver + + @retval EFI_SUCCESS Driver loaded. + @retval !EFI_SUCCESS Driver not loaded. +**/ +EFI_STATUS +EFIAPI +IdeControllerSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 PciClass; + UINT8 PciSubClass; + + // + // Attempt to Open PCI I/O Protocol + // +#ifndef VBOX + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); +#else + Status = GetPciIo(This, Controller, &PciIo); +#endif + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now further check the PCI header: Base class (offset 0x0B) and + // Sub Class (offset 0x0A). This controller should be an Ide controller + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET + 2, + 1, + &PciClass + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET + 1, + 1, + &PciSubClass + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Examine Ide PCI Configuration table fields + // +#ifndef VBOX + if ((PciClass != PCI_CLASS_MASS_STORAGE) || (PciSubClass != PCI_CLASS_MASS_STORAGE_IDE)) { +#else + if ( (PciClass != PCI_CLASS_MASS_STORAGE) + || ( PciSubClass != PCI_CLASS_MASS_STORAGE_IDE + && PciSubClass != 0x6 /* SATA */)) { +#endif + Status = EFI_UNSUPPORTED; + } + +Done: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +/** + This routine is called right after the .Supported() called and return + EFI_SUCCESS. Notes: The supported protocols are checked but the Protocols + are closed. + + @param This A pointer points to the Binding Protocol instance + @param Controller The handle of controller to be tested. Parameter + passed by the caller + @param RemainingDevicePath A pointer to the device path. Should be ignored by + device driver + + @return EFI_STATUS Status of InstallMultipleProtocolInterfaces() +**/ +EFI_STATUS +EFIAPI +IdeControllerStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; +#ifndef VBOX + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // Now test and open the EfiPciIoProtocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); +#else + Status = GetPciIo(This, Controller, &gEfiIdeControllerInit.pIdeControllerProtocol_PciIo); +#endif + // + // Status == EFI_SUCCESS - A normal execution flow, SUCCESS and the program proceeds. + // Status == ALREADY_STARTED - A non-zero Status code returned. It indicates + // that the protocol has been opened and should be treated as a + // normal condition and the program proceeds. The Protocol will not + // opened 'again' by this call. + // Status != ALREADY_STARTED - Error status, terminate program execution + // + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Install IDE_CONTROLLER_INIT protocol + // + return gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiIdeControllerInitProtocolGuid, &gEfiIdeControllerInit.Core, /* VBox: We added .Core, probably for warnings. */ + NULL + ); +} + +/** + Stop this driver on Controller Handle. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on + @param NumberOfChildren Not used + @param ChildHandleBuffer Not used + + @retval EFI_SUCCESS This driver is removed DeviceHandle + @retval !EFI_SUCCESS This driver was not removed from this device +**/ +EFI_STATUS +EFIAPI +IdeControllerStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInit; + + // + // Open the produced protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **) &IdeControllerInit, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Make sure the protocol was produced by this driver + // + if ((void *)IdeControllerInit != (void *)&gEfiIdeControllerInit) { /* VBox: Dunno why we're doing the (void *) thing, types should be the same... */ + return EFI_UNSUPPORTED; + } + + // + // Uninstall the IDE Controller Init Protocol + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiIdeControllerInitProtocolGuid, &gEfiIdeControllerInit.Core, /* VBox: We added .Core, probably for warnings. */ + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Close protocols opened by Ide controller driver + // + return gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); +} + +// +// Interface functions of IDE_CONTROLLER_INIT protocol +// +/** + Returns the information about the specified IDE channel. + + This function can be used to obtain information about a particular IDE channel. + The driver entity uses this information during the enumeration process. + + If Enabled is set to FALSE, the driver entity will not scan the channel. Note + that it will not prevent an operating system driver from scanning the channel. + + For most of today's controllers, MaxDevices will either be 1 or 2. For SATA + controllers, this value will always be 1. SATA configurations can contain SATA + port multipliers. SATA port multipliers behave like SATA bridges and can support + up to 16 devices on the other side. If a SATA port out of the IDE controller + is connected to a port multiplier, MaxDevices will be set to the number of SATA + devices that the port multiplier supports. Because today's port multipliers + support up to fifteen SATA devices, this number can be as large as fifteen. The IDE + bus driver is required to scan for the presence of port multipliers behind an SATA + controller and enumerate up to MaxDevices number of devices behind the port + multiplier. + + In this context, the devices behind a port multiplier constitute a channel. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[out] Enabled TRUE if this channel is enabled. Disabled channels + are not scanned to see if any devices are present. + @param[out] MaxDevices The maximum number of IDE devices that the bus driver + can expect on this channel. For the ATA/ATAPI + specification, version 6, this number will either be + one or two. For Serial ATA (SATA) configurations with a + port multiplier, this number can be as large as fifteen. + + @retval EFI_SUCCESS Information was returned without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + +**/ +EFI_STATUS +EFIAPI +IdeInitGetChannelInfo ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + OUT BOOLEAN *Enabled, + OUT UINT8 *MaxDevices + ) +{ + // + // Channel number (0 based, either 0 or 1) + // +#ifdef VBOX + VBoxLogFlowFuncEnter(); + VBoxLogFlowFuncMarkVar(Channel, "%d"); + *MaxDevices = 0; + *Enabled = FALSE; +#endif + if (Channel < ICH_IDE_MAX_CHANNEL) { +#ifdef VBOX + UINT8 u8Device = 0; + for (;u8Device < ICH_IDE_MAX_CHANNEL; ++u8Device) + { + BOOLEAN fEnabled = FALSE; + EFI_PCI_IO_PROTOCOL *pPciIo = gEfiIdeControllerInit.pIdeControllerProtocol_PciIo; + UINT8 u8CS = 0xaa; + UINT8 u8SN = 0x55; + UINT64 u64IoBase; + UINT64 u8DH = 0; + ASSERT(pPciIo); + VBoxLogFlowFuncMarkVar(u8Device, "%d"); + if (u8Device == 0) + u8DH = 0xa0; + else if (u8Device == 1) + u8DH = 0xb0; + else + { + VBoxLogFlowFuncLeaveRC(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; + } + switch (Channel) + { + case 0: + u64IoBase = 0x1f0; + break; + case 1: + u64IoBase = 0x170; + break; + default: + ASSERT(0); + return EFI_INVALID_PARAMETER; + } + VBoxLogFlowFuncMarkVar(u8DH, "%x"); + VBoxLogFlowFuncMarkVar(u64IoBase, "%llx"); + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 6, 1, (void *)&u8DH); + + u8CS = 0xaa; u8SN = 0x55; + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 2, 1, (void *)&u8CS); + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 3, 1, (void *)&u8SN); + + u8CS = 0x55; u8SN = 0xaa; + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 2, 1, (void *)&u8CS); + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 3, 1, (void *)&u8SN); + + u8CS = 0xaa; u8SN = 0x55; + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 2, 1, (void *)&u8CS); + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 3, 1, (void *)&u8SN); + u8CS = 0x0; u8SN = 0x0; + + /* read values back */ + pPciIo->Io.Read(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 2, 1, (void *)&u8CS); + pPciIo->Io.Read(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 3, 1, (void *)&u8SN); + + VBoxLogFlowFuncMarkVar(u8CS, "%x"); + VBoxLogFlowFuncMarkVar(u8SN, "%x"); + + fEnabled = (u8CS == 0xaa && u8SN == 0x55); + *MaxDevices += (fEnabled ? 1 : 0); + *Enabled = !*Enabled ? fEnabled : *Enabled; + + u8CS = 0x1; u8SN = 0x1; + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 2, 1, (void *)&u8CS); + pPciIo->Io.Write(pPciIo, EfiPciIoWidthUint8, EFI_PCI_IO_PASS_THROUGH_BAR, u64IoBase + 3, 1, (void *)&u8SN); + } +#else /* !VBOX */ + *Enabled = TRUE; + *MaxDevices = ICH_IDE_MAX_DEVICES; +#endif /* !VBOX */ + VBoxLogFlowFuncMarkVar(*MaxDevices, "%d"); + VBoxLogFlowFuncMarkVar(*Enabled, "%d"); + VBoxLogFlowFuncLeaveRC(EFI_SUCCESS); + return EFI_SUCCESS; + } + + *Enabled = FALSE; + return EFI_INVALID_PARAMETER; +} + +/** + The notifications from the driver entity that it is about to enter a certain + phase of the IDE channel enumeration process. + + This function can be used to notify the IDE controller driver to perform + specific actions, including any chipset-specific initialization, so that the + chipset is ready to enter the next phase. Seven notification points are defined + at this time. + + More synchronization points may be added as required in the future. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Phase The phase during enumeration. + @param[in] Channel Zero-based channel number. + + @retval EFI_SUCCESS The notification was accepted without any errors. + @retval EFI_UNSUPPORTED Phase is not supported. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_NOT_READY This phase cannot be entered at this time; for + example, an attempt was made to enter a Phase + without having entered one or more previous + Phase. + +**/ +EFI_STATUS +EFIAPI +IdeInitNotifyPhase ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN EFI_IDE_CONTROLLER_ENUM_PHASE Phase, + IN UINT8 Channel + ) +{ + return EFI_SUCCESS; +} + +/** + Submits the device information to the IDE controller driver. + + This function is used by the driver entity to pass detailed information about + a particular device to the IDE controller driver. The driver entity obtains + this information by issuing an ATA or ATAPI IDENTIFY_DEVICE command. IdentifyData + is the pointer to the response data buffer. The IdentifyData buffer is owned + by the driver entity, and the IDE controller driver must make a local copy + of the entire buffer or parts of the buffer as needed. The original IdentifyData + buffer pointer may not be valid when + + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() or + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() is called at a later point. + + The IDE controller driver may consult various fields of EFI_IDENTIFY_DATA to + compute the optimum mode for the device. These fields are not limited to the + timing information. For example, an implementation of the IDE controller driver + may examine the vendor and type/mode field to match known bad drives. + + The driver entity may submit drive information in any order, as long as it + submits information for all the devices belonging to the enumeration group + before EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() is called for any device + in that enumeration group. If a device is absent, EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + should be called with IdentifyData set to NULL. The IDE controller driver may + not have any other mechanism to know whether a device is present or not. Therefore, + setting IdentifyData to NULL does not constitute an error condition. + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() can be called only once for a + given (Channel, Device) pair. + + @param[in] This A pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] IdentifyData The device's response to the ATA IDENTIFY_DEVICE command. + + @retval EFI_SUCCESS The information was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + +**/ +EFI_STATUS +EFIAPI +IdeInitSubmitData ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_IDENTIFY_DATA *IdentifyData + ) +{ + return EFI_SUCCESS; +} + +/** + Disqualifies specific modes for an IDE device. + + This function allows the driver entity or other drivers (such as platform + drivers) to reject certain timing modes and request the IDE controller driver + to recalculate modes. This function allows the driver entity and the IDE + controller driver to negotiate the timings on a per-device basis. This function + is useful in the case of drives that lie about their capabilities. An example + is when the IDE device fails to accept the timing modes that are calculated + by the IDE controller driver based on the response to the Identify Drive command. + + If the driver entity does not want to limit the ATA timing modes and leave that + decision to the IDE controller driver, it can either not call this function for + the given device or call this function and set the Valid flag to FALSE for all + modes that are listed in EFI_ATA_COLLECTIVE_MODE. + + The driver entity may disqualify modes for a device in any order and any number + of times. + + This function can be called multiple times to invalidate multiple modes of the + same type (e.g., Programmed Input/Output [PIO] modes 3 and 4). See the ATA/ATAPI + specification for more information on PIO modes. + + For Serial ATA (SATA) controllers, this member function can be used to disqualify + a higher transfer rate mode on a given channel. For example, a platform driver + may inform the IDE controller driver to not use second-generation (Gen2) speeds + for a certain SATA drive. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel The zero-based channel number. + @param[in] Device The zero-based device number on the Channel. + @param[in] BadModes The modes that the device does not support and that + should be disqualified. + + @retval EFI_SUCCESS The modes were accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER IdentifyData is NULL. + +**/ +EFI_STATUS +EFIAPI +IdeInitDisqualifyMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *BadModes + ) +{ + return EFI_SUCCESS; +} + +/** + Returns the information about the optimum modes for the specified IDE device. + + This function is used by the driver entity to obtain the optimum ATA modes for + a specific device. The IDE controller driver takes into account the following + while calculating the mode: + - The IdentifyData inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + - The BadModes inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() + + The driver entity is required to call EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + for all the devices that belong to an enumeration group before calling + EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() for any device in the same group. + + The IDE controller driver will use controller- and possibly platform-specific + algorithms to arrive at SupportedModes. The IDE controller may base its + decision on user preferences and other considerations as well. This function + may be called multiple times because the driver entity may renegotiate the mode + with the IDE controller driver using EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode(). + + The driver entity may collect timing information for various devices in any + order. The driver entity is responsible for making sure that all the dependencies + are satisfied. For example, the SupportedModes information for device A that + was previously returned may become stale after a call to + EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() for device B. + + The buffer SupportedModes is allocated by the callee because the caller does + not necessarily know the size of the buffer. The type EFI_ATA_COLLECTIVE_MODE + is defined in a way that allows for future extensibility and can be of variable + length. This memory pool should be deallocated by the caller when it is no + longer necessary. + + The IDE controller driver for a Serial ATA (SATA) controller can use this + member function to force a lower speed (first-generation [Gen1] speeds on a + second-generation [Gen2]-capable hardware). The IDE controller driver can + also allow the driver entity to stay with the speed that has been negotiated + by the physical layer. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel A zero-based channel number. + @param[in] Device A zero-based device number on the Channel. + @param[out] SupportedModes The optimum modes for the device. + + @retval EFI_SUCCESS SupportedModes was returned. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER SupportedModes is NULL. + @retval EFI_NOT_READY Modes cannot be calculated due to a lack of + data. This error may happen if + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + and EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyData() + were not called for at least one drive in the + same enumeration group. + +**/ +EFI_STATUS +EFIAPI +IdeInitCalculateMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes + ) +{ +#ifndef VBOX + if (Channel >= ICH_IDE_MAX_CHANNEL || Device >= ICH_IDE_MAX_DEVICES) { + return EFI_INVALID_PARAMETER; + } +#endif + + *SupportedModes = AllocateCopyPool (sizeof (EFI_ATA_COLLECTIVE_MODE), &gEfiAtaCollectiveModeTemplate); + if (*SupportedModes == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Commands the IDE controller driver to program the IDE controller hardware + so that the specified device can operate at the specified mode. + + This function is used by the driver entity to instruct the IDE controller + driver to program the IDE controller hardware to the specified modes. This + function can be called only once for a particular device. For a Serial ATA + (SATA) Advanced Host Controller Interface (AHCI) controller, no controller- + specific programming may be required. + + @param[in] This Pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] Modes The modes to set. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_NOT_READY Modes cannot be set at this time due to lack of data. + @retval EFI_DEVICE_ERROR Modes cannot be set due to hardware failure. + The driver entity should not use this device. + +**/ +EFI_STATUS +EFIAPI +IdeInitSetTiming ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *Modes + ) +{ + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.h b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.h new file mode 100644 index 00000000..9f51860e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.h @@ -0,0 +1,472 @@ +/** @file + Header file for IDE controller driver. + + Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _IDE_CONTROLLER_H_ +#define _IDE_CONTROLLER_H_ + +#include <Uefi.h> +#include <Protocol/ComponentName.h> +#include <Protocol/DriverBinding.h> +#include <Protocol/PciIo.h> +#include <Protocol/IdeControllerInit.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <IndustryStandard/Pci.h> + +// +// Global Variables definitions +// +extern EFI_DRIVER_BINDING_PROTOCOL gIdeControllerDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gIdeControllerComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gIdeControllerComponentName2; + +/// +/// Supports 2 channel max +/// +#define ICH_IDE_MAX_CHANNEL 0x02 + +/// +/// Supports 2 devices max +/// +#define ICH_IDE_MAX_DEVICES 0x02 +#define ICH_IDE_ENUMER_ALL FALSE + +// +// Driver binding functions declaration +// +/** + Register Driver Binding protocol for this driver. + + @param This A pointer points to the Binding Protocol instance + @param Controller The handle of controller to be tested. + @param RemainingDevicePath A pointer to the device path. Ignored by device + driver but used by bus driver + + @retval EFI_SUCCESS Driver loaded. + @retval !EFI_SUCCESS Driver not loaded. +**/ +EFI_STATUS +EFIAPI +IdeControllerSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +/** + This routine is called right after the .Supported() called and return + EFI_SUCCESS. Notes: The supported protocols are checked but the Protocols + are closed. + + @param This A pointer points to the Binding Protocol instance + @param Controller The handle of controller to be tested. Parameter + passed by the caller + @param RemainingDevicePath A pointer to the device path. Should be ignored by + device driver + + @return EFI_STATUS Status of InstallMultipleProtocolInterfaces() +**/ +EFI_STATUS +EFIAPI +IdeControllerStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +/** + Stop this driver on Controller Handle. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on + @param NumberOfChildren Not used + @param ChildHandleBuffer Not used + + @retval EFI_SUCCESS This driver is removed DeviceHandle + @retval !EFI_SUCCESS This driver was not removed from this device +**/ +EFI_STATUS +EFIAPI +IdeControllerStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + +// +// IDE controller init functions declaration +// +/** + Returns the information about the specified IDE channel. + + This function can be used to obtain information about a particular IDE channel. + The driver entity uses this information during the enumeration process. + + If Enabled is set to FALSE, the driver entity will not scan the channel. Note + that it will not prevent an operating system driver from scanning the channel. + + For most of today's controllers, MaxDevices will either be 1 or 2. For SATA + controllers, this value will always be 1. SATA configurations can contain SATA + port multipliers. SATA port multipliers behave like SATA bridges and can support + up to 16 devices on the other side. If a SATA port out of the IDE controller + is connected to a port multiplier, MaxDevices will be set to the number of SATA + devices that the port multiplier supports. Because today's port multipliers + support up to fifteen SATA devices, this number can be as large as fifteen. The IDE + bus driver is required to scan for the presence of port multipliers behind an SATA + controller and enumerate up to MaxDevices number of devices behind the port + multiplier. + + In this context, the devices behind a port multiplier constitute a channel. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[out] Enabled TRUE if this channel is enabled. Disabled channels + are not scanned to see if any devices are present. + @param[out] MaxDevices The maximum number of IDE devices that the bus driver + can expect on this channel. For the ATA/ATAPI + specification, version 6, this number will either be + one or two. For Serial ATA (SATA) configurations with a + port multiplier, this number can be as large as fifteen. + + @retval EFI_SUCCESS Information was returned without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + +**/ +EFI_STATUS +EFIAPI +IdeInitGetChannelInfo ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + OUT BOOLEAN *Enabled, + OUT UINT8 *MaxDevices + ) +; + +/** + The notifications from the driver entity that it is about to enter a certain + phase of the IDE channel enumeration process. + + This function can be used to notify the IDE controller driver to perform + specific actions, including any chipset-specific initialization, so that the + chipset is ready to enter the next phase. Seven notification points are defined + at this time. + + More synchronization points may be added as required in the future. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Phase The phase during enumeration. + @param[in] Channel Zero-based channel number. + + @retval EFI_SUCCESS The notification was accepted without any errors. + @retval EFI_UNSUPPORTED Phase is not supported. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_NOT_READY This phase cannot be entered at this time; for + example, an attempt was made to enter a Phase + without having entered one or more previous + Phase. + +**/ +EFI_STATUS +EFIAPI +IdeInitNotifyPhase ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN EFI_IDE_CONTROLLER_ENUM_PHASE Phase, + IN UINT8 Channel + ) +; + +/** + Submits the device information to the IDE controller driver. + + This function is used by the driver entity to pass detailed information about + a particular device to the IDE controller driver. The driver entity obtains + this information by issuing an ATA or ATAPI IDENTIFY_DEVICE command. IdentifyData + is the pointer to the response data buffer. The IdentifyData buffer is owned + by the driver entity, and the IDE controller driver must make a local copy + of the entire buffer or parts of the buffer as needed. The original IdentifyData + buffer pointer may not be valid when + + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() or + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() is called at a later point. + + The IDE controller driver may consult various fields of EFI_IDENTIFY_DATA to + compute the optimum mode for the device. These fields are not limited to the + timing information. For example, an implementation of the IDE controller driver + may examine the vendor and type/mode field to match known bad drives. + + The driver entity may submit drive information in any order, as long as it + submits information for all the devices belonging to the enumeration group + before EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() is called for any device + in that enumeration group. If a device is absent, EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + should be called with IdentifyData set to NULL. The IDE controller driver may + not have any other mechanism to know whether a device is present or not. Therefore, + setting IdentifyData to NULL does not constitute an error condition. + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() can be called only once for a + given (Channel, Device) pair. + + @param[in] This A pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] IdentifyData The device's response to the ATA IDENTIFY_DEVICE command. + + @retval EFI_SUCCESS The information was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + +**/ +EFI_STATUS +EFIAPI +IdeInitSubmitData ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_IDENTIFY_DATA *IdentifyData + ) +; + +/** + Disqualifies specific modes for an IDE device. + + This function allows the driver entity or other drivers (such as platform + drivers) to reject certain timing modes and request the IDE controller driver + to recalculate modes. This function allows the driver entity and the IDE + controller driver to negotiate the timings on a per-device basis. This function + is useful in the case of drives that lie about their capabilities. An example + is when the IDE device fails to accept the timing modes that are calculated + by the IDE controller driver based on the response to the Identify Drive command. + + If the driver entity does not want to limit the ATA timing modes and leave that + decision to the IDE controller driver, it can either not call this function for + the given device or call this function and set the Valid flag to FALSE for all + modes that are listed in EFI_ATA_COLLECTIVE_MODE. + + The driver entity may disqualify modes for a device in any order and any number + of times. + + This function can be called multiple times to invalidate multiple modes of the + same type (e.g., Programmed Input/Output [PIO] modes 3 and 4). See the ATA/ATAPI + specification for more information on PIO modes. + + For Serial ATA (SATA) controllers, this member function can be used to disqualify + a higher transfer rate mode on a given channel. For example, a platform driver + may inform the IDE controller driver to not use second-generation (Gen2) speeds + for a certain SATA drive. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel The zero-based channel number. + @param[in] Device The zero-based device number on the Channel. + @param[in] BadModes The modes that the device does not support and that + should be disqualified. + + @retval EFI_SUCCESS The modes were accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER IdentifyData is NULL. + +**/ +EFI_STATUS +EFIAPI +IdeInitDisqualifyMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *BadModes + ) +; + +/** + Returns the information about the optimum modes for the specified IDE device. + + This function is used by the driver entity to obtain the optimum ATA modes for + a specific device. The IDE controller driver takes into account the following + while calculating the mode: + - The IdentifyData inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + - The BadModes inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() + + The driver entity is required to call EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + for all the devices that belong to an enumeration group before calling + EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() for any device in the same group. + + The IDE controller driver will use controller- and possibly platform-specific + algorithms to arrive at SupportedModes. The IDE controller may base its + decision on user preferences and other considerations as well. This function + may be called multiple times because the driver entity may renegotiate the mode + with the IDE controller driver using EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode(). + + The driver entity may collect timing information for various devices in any + order. The driver entity is responsible for making sure that all the dependencies + are satisfied. For example, the SupportedModes information for device A that + was previously returned may become stale after a call to + EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() for device B. + + The buffer SupportedModes is allocated by the callee because the caller does + not necessarily know the size of the buffer. The type EFI_ATA_COLLECTIVE_MODE + is defined in a way that allows for future extensibility and can be of variable + length. This memory pool should be deallocated by the caller when it is no + longer necessary. + + The IDE controller driver for a Serial ATA (SATA) controller can use this + member function to force a lower speed (first-generation [Gen1] speeds on a + second-generation [Gen2]-capable hardware). The IDE controller driver can + also allow the driver entity to stay with the speed that has been negotiated + by the physical layer. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel A zero-based channel number. + @param[in] Device A zero-based device number on the Channel. + @param[out] SupportedModes The optimum modes for the device. + + @retval EFI_SUCCESS SupportedModes was returned. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER SupportedModes is NULL. + @retval EFI_NOT_READY Modes cannot be calculated due to a lack of + data. This error may happen if + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + and EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyData() + were not called for at least one drive in the + same enumeration group. + +**/ +EFI_STATUS +EFIAPI +IdeInitCalculateMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes + ) +; + +/** + Commands the IDE controller driver to program the IDE controller hardware + so that the specified device can operate at the specified mode. + + This function is used by the driver entity to instruct the IDE controller + driver to program the IDE controller hardware to the specified modes. This + function can be called only once for a particular device. For a Serial ATA + (SATA) Advanced Host Controller Interface (AHCI) controller, no controller- + specific programming may be required. + + @param[in] This Pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] Modes The modes to set. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_NOT_READY Modes cannot be set at this time due to lack of data. + @retval EFI_DEVICE_ERROR Modes cannot be set due to hardware failure. + The driver entity should not use this device. + +**/ +EFI_STATUS +EFIAPI +IdeInitSetTiming ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *Modes + ) +; + +// +// Forward reference declaration +// +/** + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +IdeControllerComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +; + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param OPTIONAL ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +IdeControllerComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.uni new file mode 100644 index 00000000..22a6b187 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeController.uni @@ -0,0 +1,16 @@ +// /** @file
+// IDE Controller Init module that will produce IDE_CONTROLLER_INIT protocol
+//
+// Component description file for the IDE Controller Init module.
+//
+// Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "IDE Controller Init module that will produce IDE_CONTROLLER_INIT protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "IDE Controller Init module that will produce IDE_CONTROLLER_INIT protocol."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf new file mode 100644 index 00000000..c72d963d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf @@ -0,0 +1,46 @@ +## @file +# IDE Controller Init driver that provide IDE_CONTROLLER_INIT protocol and will be used by +# IDE Bus driver to support platform dependent timing information. +# +# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IdeController + MODULE_UNI_FILE = IdeController.uni + FILE_GUID = 99549F44-49BB-4820-B9D2-901329412D67 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeIdeControllerDriver + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + ComponentName.c + IdeController.c + IdeController.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + +[Protocols] + gEfiPciIoProtocolGuid ## TO_START + gEfiIdeControllerInitProtocolGuid ## BY_START +[UserExtensions.TianoCore."ExtraFiles"] + IdeControllerExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerExtra.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerExtra.uni new file mode 100644 index 00000000..a6d7618e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// IdeController Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"IDE Controller DXE Driver"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimer.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimer.c new file mode 100644 index 00000000..9c595bd3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimer.c @@ -0,0 +1,993 @@ +/** @file + Timer Architectural Protocol module using High Precision Event Timer (HPET) + + Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/Cpu.h> +#include <Protocol/Timer.h> + +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/LocalApicLib.h> +#include <Library/IoApicLib.h> + +#include <Register/LocalApic.h> +#include <Register/IoApic.h> +#include <Register/Hpet.h> + +/// +/// Define value for an invalid HPET Timer index. +/// +#define HPET_INVALID_TIMER_INDEX 0xff + +/// +/// Timer Architectural Protocol function prototypes. +/// + +/** + This function registers the handler NotifyFunction so it is called every time + the timer interrupt fires. It also passes the amount of time since the last + handler call to the NotifyFunction. If NotifyFunction is NULL, then the + handler is unregistered. If the handler is registered, then EFI_SUCCESS is + returned. If the CPU does not support registering a timer interrupt handler, + then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler + when a handler is already registered, then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to + register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR + is returned. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param NotifyFunction The function to call when a timer interrupt fires. + This function executes at TPL_HIGH_LEVEL. The DXE + Core will register a handler for the timer interrupt, + so it can know how much time has passed. This + information is used to signal timer based events. + NULL will unregister the handler. + + @retval EFI_SUCCESS The timer handler was registered. + @retval EFI_UNSUPPORTED The platform does not support timer interrupts. + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already + registered. + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not + previously registered. + @retval EFI_DEVICE_ERROR The timer handler could not be registered. + +**/ +EFI_STATUS +EFIAPI +TimerDriverRegisterHandler ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction + ); + +/** + This function adjusts the period of timer interrupts to the value specified + by TimerPeriod. If the timer period is updated, then the selected timer + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. + If an error occurs while attempting to update the timer period, then the + timer hardware will be put back in its state prior to this call, and + EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt + is disabled. This is not the same as disabling the CPU's interrupts. + Instead, it must either turn off the timer hardware, or it must adjust the + interrupt controller so that a CPU interrupt is not generated when the timer + interrupt fires. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod The rate to program the timer interrupt in 100 nS units. + If the timer hardware is not programmable, then + EFI_UNSUPPORTED is returned. If the timer is programmable, + then the timer period will be rounded up to the nearest + timer period that is supported by the timer hardware. + If TimerPeriod is set to 0, then the timer interrupts + will be disabled. + + @retval EFI_SUCCESS The timer period was changed. + @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. + @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. + +**/ +EFI_STATUS +EFIAPI +TimerDriverSetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ); + +/** + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. + If 0 is returned, then the timer is currently disabled. + + @retval EFI_SUCCESS The timer period was returned in TimerPeriod. + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ); + +/** + This function generates a soft timer interrupt. If the platform does not support soft + timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned. + If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler() + service, then a soft timer interrupt will be generated. If the timer interrupt is + enabled when this service is called, then the registered handler will be invoked. The + registered handler should not be able to distinguish a hardware-generated timer + interrupt from a software-generated timer interrupt. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS The soft timer interrupt was generated. + @retval EFI_UNSUPPORTED The platform does not support the generation of soft + timer interrupts. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGenerateSoftInterrupt ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ); + +/// +/// The handle onto which the Timer Architectural Protocol will be installed. +/// +EFI_HANDLE mTimerHandle = NULL; + +/// +/// The Timer Architectural Protocol that this driver produces. +/// +EFI_TIMER_ARCH_PROTOCOL mTimer = { + TimerDriverRegisterHandler, + TimerDriverSetTimerPeriod, + TimerDriverGetTimerPeriod, + TimerDriverGenerateSoftInterrupt +}; + +/// +/// Pointer to the CPU Architectural Protocol instance. +/// +EFI_CPU_ARCH_PROTOCOL *mCpu = NULL; + +/// +/// The notification function to call on every timer interrupt. +/// +EFI_TIMER_NOTIFY mTimerNotifyFunction = NULL; + +/// +/// The current period of the HPET timer interrupt in 100 ns units. +/// +UINT64 mTimerPeriod = 0; + +/// +/// The number of HPET timer ticks required for the current HPET rate specified by mTimerPeriod. +/// +UINT64 mTimerCount; + +/// +/// Mask used for counter and comparator calculations to adjust for a 32-bit or 64-bit counter. +/// +UINT64 mCounterMask; + +/// +/// The HPET main counter value from the most recent HPET timer interrupt. +/// +volatile UINT64 mPreviousMainCounter; + +volatile UINT64 mPreviousComparator; + +/// +/// The index of the HPET timer being managed by this driver. +/// +UINTN mTimerIndex; + +/// +/// The I/O APIC IRQ that the HPET Timer is mapped if I/O APIC mode is used. +/// +UINT32 mTimerIrq; + +/// +/// Cached state of the HPET General Capabilities register managed by this driver. +/// Caching the state reduces the number of times the configuration register is read. +/// +HPET_GENERAL_CAPABILITIES_ID_REGISTER mHpetGeneralCapabilities; + +/// +/// Cached state of the HPET General Configuration register managed by this driver. +/// Caching the state reduces the number of times the configuration register is read. +/// +HPET_GENERAL_CONFIGURATION_REGISTER mHpetGeneralConfiguration; + +/// +/// Cached state of the Configuration register for the HPET Timer managed by +/// this driver. Caching the state reduces the number of times the configuration +/// register is read. +/// +HPET_TIMER_CONFIGURATION_REGISTER mTimerConfiguration; + +/// +/// Counts the number of HPET Timer interrupts processed by this driver. +/// Only required for debug. +/// +volatile UINTN mNumTicks; + +/** + Read a 64-bit register from the HPET + + @param Offset Specifies the offset of the HPET register to read. + + @return The 64-bit value read from the HPET register specified by Offset. +**/ +UINT64 +HpetRead ( + IN UINTN Offset + ) +{ + return MmioRead64 (PcdGet32 (PcdHpetBaseAddress) + Offset); +} + +/** + Write a 64-bit HPET register. + + @param Offset Specifies the offset of the HPET register to write. + @param Value Specifies the value to write to the HPET register specified by Offset. + + @return The 64-bit value written to HPET register specified by Offset. +**/ +UINT64 +HpetWrite ( + IN UINTN Offset, + IN UINT64 Value + ) +{ + return MmioWrite64 (PcdGet32 (PcdHpetBaseAddress) + Offset, Value); +} + +/** + Enable or disable the main counter in the HPET Timer. + + @param Enable If TRUE, then enable the main counter in the HPET Timer. + If FALSE, then disable the main counter in the HPET Timer. +**/ +VOID +HpetEnable ( + IN BOOLEAN Enable + ) +{ + mHpetGeneralConfiguration.Bits.MainCounterEnable = Enable ? 1 : 0; + HpetWrite (HPET_GENERAL_CONFIGURATION_OFFSET, mHpetGeneralConfiguration.Uint64); +} + +/** + The interrupt handler for the HPET timer. This handler clears the HPET interrupt + and computes the amount of time that has passed since the last HPET timer interrupt. + If a notification function is registered, then the amount of time since the last + HPET interrupt is passed to that notification function in 100 ns units. The HPET + time is updated to generate another interrupt in the required time period. + + @param InterruptType The type of interrupt that occurred. + @param SystemContext A pointer to the system context when the interrupt occurred. +**/ +VOID +EFIAPI +TimerInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT64 MainCounter; + UINT64 Comparator; + UINT64 TimerPeriod; + UINT64 Delta; + + // + // Count number of ticks + // + DEBUG_CODE (mNumTicks++;); + + // + // Clear HPET timer interrupt status + // + HpetWrite (HPET_GENERAL_INTERRUPT_STATUS_OFFSET, LShiftU64 (1, mTimerIndex)); + + // + // Local APIC EOI + // + SendApicEoi (); + + // + // Disable HPET timer when adjusting the COMPARATOR value to prevent a missed interrupt + // + HpetEnable (FALSE); + + // + // Capture main counter value + // + MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET); + + // + // Get the previous comparator counter + // + mPreviousComparator = HpetRead (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE); + + // + // Set HPET COMPARATOR to the value required for the next timer tick + // + Comparator = (mPreviousComparator + mTimerCount) & mCounterMask; + + if ((mPreviousMainCounter < MainCounter) && (mPreviousComparator > Comparator)) { + // + // When comparator overflows + // + HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, Comparator); + } else if ((mPreviousMainCounter > MainCounter) && (mPreviousComparator < Comparator)) { + // + // When main counter overflows + // + HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (MainCounter + mTimerCount) & mCounterMask); + } else { + // + // When both main counter and comparator do not overflow or both do overflow + // + if (Comparator > MainCounter) { + HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, Comparator); + } else { + HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (MainCounter + mTimerCount) & mCounterMask); + } + } + + // + // Enable the HPET counter once the new COMPARATOR value has been set. + // + HpetEnable (TRUE); + + // + // Check to see if there is a registered notification function + // + if (mTimerNotifyFunction != NULL) { + // + // Compute time since last notification in 100 ns units (10 ^ -7) + // + if (MainCounter > mPreviousMainCounter) { + // + // Main counter does not overflow + // + Delta = MainCounter - mPreviousMainCounter; + } else { + // + // Main counter overflows, first usb, then add + // + Delta = (mCounterMask - mPreviousMainCounter) + MainCounter; + } + TimerPeriod = DivU64x32 ( + MultU64x32 ( + Delta & mCounterMask, + mHpetGeneralCapabilities.Bits.CounterClockPeriod + ), + 100000000 + ); + + // + // Call registered notification function passing in the time since the last + // interrupt in 100 ns units. + // + mTimerNotifyFunction (TimerPeriod); + } + + // + // Save main counter value + // + mPreviousMainCounter = MainCounter; +} + +/** + This function registers the handler NotifyFunction so it is called every time + the timer interrupt fires. It also passes the amount of time since the last + handler call to the NotifyFunction. If NotifyFunction is NULL, then the + handler is unregistered. If the handler is registered, then EFI_SUCCESS is + returned. If the CPU does not support registering a timer interrupt handler, + then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler + when a handler is already registered, then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to + register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR + is returned. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param NotifyFunction The function to call when a timer interrupt fires. + This function executes at TPL_HIGH_LEVEL. The DXE + Core will register a handler for the timer interrupt, + so it can know how much time has passed. This + information is used to signal timer based events. + NULL will unregister the handler. + + @retval EFI_SUCCESS The timer handler was registered. + @retval EFI_UNSUPPORTED The platform does not support timer interrupts. + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already + registered. + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not + previously registered. + @retval EFI_DEVICE_ERROR The timer handler could not be registered. + +**/ +EFI_STATUS +EFIAPI +TimerDriverRegisterHandler ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction + ) +{ + // + // Check for invalid parameters + // + if (NotifyFunction == NULL && mTimerNotifyFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + if (NotifyFunction != NULL && mTimerNotifyFunction != NULL) { + return EFI_ALREADY_STARTED; + } + + // + // Cache the registered notification function + // + mTimerNotifyFunction = NotifyFunction; + + return EFI_SUCCESS; +} + +/** + This function adjusts the period of timer interrupts to the value specified + by TimerPeriod. If the timer period is updated, then the selected timer + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. + If an error occurs while attempting to update the timer period, then the + timer hardware will be put back in its state prior to this call, and + EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt + is disabled. This is not the same as disabling the CPU's interrupts. + Instead, it must either turn off the timer hardware, or it must adjust the + interrupt controller so that a CPU interrupt is not generated when the timer + interrupt fires. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod The rate to program the timer interrupt in 100 nS units. + If the timer hardware is not programmable, then + EFI_UNSUPPORTED is returned. If the timer is programmable, + then the timer period will be rounded up to the nearest + timer period that is supported by the timer hardware. + If TimerPeriod is set to 0, then the timer interrupts + will be disabled. + + @retval EFI_SUCCESS The timer period was changed. + @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. + @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. + +**/ +EFI_STATUS +EFIAPI +TimerDriverSetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +{ + EFI_TPL Tpl; + UINT64 MainCounter; + UINT64 Delta; + UINT64 CurrentComparator; + HPET_TIMER_MSI_ROUTE_REGISTER HpetTimerMsiRoute; + + // + // Disable interrupts + // + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + // + // Disable HPET timer when adjusting the timer period + // + HpetEnable (FALSE); + + if (TimerPeriod == 0) { + if (mTimerPeriod != 0) { + // + // Check if there is possibly a pending interrupt + // + MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET); + if (MainCounter < mPreviousMainCounter) { + Delta = (mCounterMask - mPreviousMainCounter) + MainCounter; + } else { + Delta = MainCounter - mPreviousMainCounter; + } + if ((Delta & mCounterMask) >= mTimerCount) { + // + // Interrupt still happens after disable HPET, wait to be processed + // Wait until interrupt is processed and comparator is increased + // + CurrentComparator = HpetRead (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE); + while (CurrentComparator == mPreviousComparator) { + CurrentComparator = HpetRead (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE); + CpuPause(); + } + } + } + + // + // If TimerPeriod is 0, then mask HPET Timer interrupts + // + + if (mTimerConfiguration.Bits.MsiInterruptCapability != 0 && FeaturePcdGet (PcdHpetMsiEnable)) { + // + // Disable HPET MSI interrupt generation + // + mTimerConfiguration.Bits.MsiInterruptEnable = 0; + } else { + // + // Disable I/O APIC Interrupt + // + IoApicEnableInterrupt (mTimerIrq, FALSE); + } + + // + // Disable HPET timer interrupt + // + mTimerConfiguration.Bits.InterruptEnable = 0; + HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64); + } else { + // + // Convert TimerPeriod to femtoseconds and divide by the number if femtoseconds + // per tick of the HPET counter to determine the number of HPET counter ticks + // in TimerPeriod 100 ns units. + // + mTimerCount = DivU64x32 ( + MultU64x32 (TimerPeriod, 100000000), + mHpetGeneralCapabilities.Bits.CounterClockPeriod + ); + + // + // Program the HPET Comparator with the number of ticks till the next interrupt + // + MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET); + if (MainCounter > mPreviousMainCounter) { + Delta = MainCounter - mPreviousMainCounter; + } else { + Delta = (mCounterMask - mPreviousMainCounter) + MainCounter; + } + if ((Delta & mCounterMask) >= mTimerCount) { + HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (MainCounter + 1) & mCounterMask); + } else { + HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (mPreviousMainCounter + mTimerCount) & mCounterMask); + } + + // + // Enable HPET Timer interrupt generation + // + if (mTimerConfiguration.Bits.MsiInterruptCapability != 0 && FeaturePcdGet (PcdHpetMsiEnable)) { + // + // Program MSI Address and MSI Data values in the selected HPET Timer + // Program HPET register with APIC ID of current BSP in case BSP has been switched + // + HpetTimerMsiRoute.Bits.Address = GetApicMsiAddress (); + HpetTimerMsiRoute.Bits.Value = (UINT32)GetApicMsiValue (PcdGet8 (PcdHpetLocalApicVector), LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY, FALSE, FALSE); + HpetWrite (HPET_TIMER_MSI_ROUTE_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, HpetTimerMsiRoute.Uint64); + // + // Enable HPET MSI Interrupt + // + mTimerConfiguration.Bits.MsiInterruptEnable = 1; + } else { + // + // Enable timer interrupt through I/O APIC + // Program IOAPIC register with APIC ID of current BSP in case BSP has been switched + // + IoApicConfigureInterrupt (mTimerIrq, PcdGet8 (PcdHpetLocalApicVector), IO_APIC_DELIVERY_MODE_LOWEST_PRIORITY, TRUE, FALSE); + IoApicEnableInterrupt (mTimerIrq, TRUE); + } + + // + // Enable HPET Interrupt Generation + // + mTimerConfiguration.Bits.InterruptEnable = 1; + HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64); + } + + // + // Save the new timer period + // + mTimerPeriod = TimerPeriod; + + // + // Enable the HPET counter once new timer period has been established + // The HPET counter should run even if the HPET Timer interrupts are + // disabled. This is used to account for time passed while the interrupt + // is disabled. + // + HpetEnable (TRUE); + + // + // Restore interrupts + // + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +/** + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. + If 0 is returned, then the timer is currently disabled. + + @retval EFI_SUCCESS The timer period was returned in TimerPeriod. + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +{ + if (TimerPeriod == NULL) { + return EFI_INVALID_PARAMETER; + } + + *TimerPeriod = mTimerPeriod; + + return EFI_SUCCESS; +} + +/** + This function generates a soft timer interrupt. If the platform does not support soft + timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned. + If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler() + service, then a soft timer interrupt will be generated. If the timer interrupt is + enabled when this service is called, then the registered handler will be invoked. The + registered handler should not be able to distinguish a hardware-generated timer + interrupt from a software-generated timer interrupt. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS The soft timer interrupt was generated. + @retval EFI_UNSUPPORTED The platform does not support the generation of soft + timer interrupts. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGenerateSoftInterrupt ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ) +{ + UINT64 MainCounter; + EFI_TPL Tpl; + UINT64 TimerPeriod; + UINT64 Delta; + + // + // Disable interrupts + // + Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + // + // Capture main counter value + // + MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET); + + // + // Check to see if there is a registered notification function + // + if (mTimerNotifyFunction != NULL) { + // + // Compute time since last interrupt in 100 ns units (10 ^ -7) + // + if (MainCounter > mPreviousMainCounter) { + // + // Main counter does not overflow + // + Delta = MainCounter - mPreviousMainCounter; + } else { + // + // Main counter overflows, first usb, then add + // + Delta = (mCounterMask - mPreviousMainCounter) + MainCounter; + } + + TimerPeriod = DivU64x32 ( + MultU64x32 ( + Delta & mCounterMask, + mHpetGeneralCapabilities.Bits.CounterClockPeriod + ), + 100000000 + ); + + // + // Call registered notification function passing in the time since the last + // interrupt in 100 ns units. + // + mTimerNotifyFunction (TimerPeriod); + } + + // + // Save main counter value + // + mPreviousMainCounter = MainCounter; + + // + // Restore interrupts + // + gBS->RestoreTPL (Tpl); + + return EFI_SUCCESS; +} + +/** + Initialize the Timer Architectural Protocol driver + + @param ImageHandle ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Timer Architectural Protocol created + @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver. + @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver. + +**/ +EFI_STATUS +EFIAPI +TimerDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN TimerIndex; + UINTN MsiTimerIndex; + HPET_TIMER_MSI_ROUTE_REGISTER HpetTimerMsiRoute; + + DEBUG ((DEBUG_INFO, "Init HPET Timer Driver\n")); + + // + // Make sure the Timer Architectural Protocol is not already installed in the system + // + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiTimerArchProtocolGuid); + + // + // Find the CPU architectural protocol. + // + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mCpu); + ASSERT_EFI_ERROR (Status); + + // + // Retrieve HPET Capabilities and Configuration Information + // + mHpetGeneralCapabilities.Uint64 = HpetRead (HPET_GENERAL_CAPABILITIES_ID_OFFSET); + mHpetGeneralConfiguration.Uint64 = HpetRead (HPET_GENERAL_CONFIGURATION_OFFSET); + + // + // If Revision is not valid, then ASSERT() and unload the driver because the HPET + // device is not present. + // + ASSERT (mHpetGeneralCapabilities.Uint64 != 0); + ASSERT (mHpetGeneralCapabilities.Uint64 != 0xFFFFFFFFFFFFFFFFULL); + if (mHpetGeneralCapabilities.Uint64 == 0 || mHpetGeneralCapabilities.Uint64 == 0xFFFFFFFFFFFFFFFFULL) { + DEBUG ((DEBUG_ERROR, "HPET device is not present. Unload HPET driver.\n")); + return EFI_DEVICE_ERROR; + } + + // + // Force the HPET timer to be disabled while setting everything up + // + HpetEnable (FALSE); + + // + // Dump HPET Configuration Information + // + DEBUG_CODE ( + DEBUG ((DEBUG_INFO, "HPET Base Address = 0x%08x\n", PcdGet32 (PcdHpetBaseAddress))); + DEBUG ((DEBUG_INFO, " HPET_GENERAL_CAPABILITIES_ID = 0x%016lx\n", mHpetGeneralCapabilities)); + DEBUG ((DEBUG_INFO, " HPET_GENERAL_CONFIGURATION = 0x%016lx\n", mHpetGeneralConfiguration.Uint64)); + DEBUG ((DEBUG_INFO, " HPET_GENERAL_INTERRUPT_STATUS = 0x%016lx\n", HpetRead (HPET_GENERAL_INTERRUPT_STATUS_OFFSET))); + DEBUG ((DEBUG_INFO, " HPET_MAIN_COUNTER = 0x%016lx\n", HpetRead (HPET_MAIN_COUNTER_OFFSET))); + DEBUG ((DEBUG_INFO, " HPET Main Counter Period = %d (fs)\n", mHpetGeneralCapabilities.Bits.CounterClockPeriod)); + for (TimerIndex = 0; TimerIndex <= mHpetGeneralCapabilities.Bits.NumberOfTimers; TimerIndex++) { + DEBUG ((DEBUG_INFO, " HPET_TIMER%d_CONFIGURATION = 0x%016lx\n", TimerIndex, HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + TimerIndex * HPET_TIMER_STRIDE))); + DEBUG ((DEBUG_INFO, " HPET_TIMER%d_COMPARATOR = 0x%016lx\n", TimerIndex, HpetRead (HPET_TIMER_COMPARATOR_OFFSET + TimerIndex * HPET_TIMER_STRIDE))); + DEBUG ((DEBUG_INFO, " HPET_TIMER%d_MSI_ROUTE = 0x%016lx\n", TimerIndex, HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET + TimerIndex * HPET_TIMER_STRIDE))); + } + ); + + // + // Capture the current HPET main counter value. + // + mPreviousMainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET); + + // + // Determine the interrupt mode to use for the HPET Timer. + // Look for MSI first, then unused PIC mode interrupt, then I/O APIC mode interrupt + // + MsiTimerIndex = HPET_INVALID_TIMER_INDEX; + mTimerIndex = HPET_INVALID_TIMER_INDEX; + for (TimerIndex = 0; TimerIndex <= mHpetGeneralCapabilities.Bits.NumberOfTimers; TimerIndex++) { + // + // Read the HPET Timer Capabilities and Configuration register + // + mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + TimerIndex * HPET_TIMER_STRIDE); + + // + // Check to see if this HPET Timer supports MSI + // + if (mTimerConfiguration.Bits.MsiInterruptCapability != 0) { + // + // Save the index of the first HPET Timer that supports MSI interrupts + // + if (MsiTimerIndex == HPET_INVALID_TIMER_INDEX) { + MsiTimerIndex = TimerIndex; + } + } + + // + // Check to see if this HPET Timer supports I/O APIC interrupts + // + if (mTimerConfiguration.Bits.InterruptRouteCapability != 0) { + // + // Save the index of the first HPET Timer that supports I/O APIC interrupts + // + if (mTimerIndex == HPET_INVALID_TIMER_INDEX) { + mTimerIndex = TimerIndex; + mTimerIrq = (UINT32)LowBitSet32 (mTimerConfiguration.Bits.InterruptRouteCapability); + } + } + } + + if (FeaturePcdGet (PcdHpetMsiEnable) && MsiTimerIndex != HPET_INVALID_TIMER_INDEX) { + // + // Use MSI interrupt if supported + // + mTimerIndex = MsiTimerIndex; + + // + // Program MSI Address and MSI Data values in the selected HPET Timer + // + HpetTimerMsiRoute.Bits.Address = GetApicMsiAddress (); + HpetTimerMsiRoute.Bits.Value = (UINT32)GetApicMsiValue (PcdGet8 (PcdHpetLocalApicVector), LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY, FALSE, FALSE); + HpetWrite (HPET_TIMER_MSI_ROUTE_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, HpetTimerMsiRoute.Uint64); + + // + // Read the HPET Timer Capabilities and Configuration register and initialize for MSI mode + // Clear LevelTriggeredInterrupt to use edge triggered interrupts when in MSI mode + // + mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE); + mTimerConfiguration.Bits.LevelTriggeredInterrupt = 0; + } else { + // + // If no HPET timers support MSI or I/O APIC modes, then ASSERT() and unload the driver. + // + ASSERT (mTimerIndex != HPET_INVALID_TIMER_INDEX); + if (mTimerIndex == HPET_INVALID_TIMER_INDEX) { + DEBUG ((DEBUG_ERROR, "No HPET timers support MSI or I/O APIC mode. Unload HPET driver.\n")); + return EFI_DEVICE_ERROR; + } + + // + // Initialize I/O APIC entry for HPET Timer Interrupt + // Fixed Delivery Mode, Level Triggered, Asserted Low + // + IoApicConfigureInterrupt (mTimerIrq, PcdGet8 (PcdHpetLocalApicVector), IO_APIC_DELIVERY_MODE_LOWEST_PRIORITY, TRUE, FALSE); + + // + // Read the HPET Timer Capabilities and Configuration register and initialize for I/O APIC mode + // Clear MsiInterruptCapability to force rest of driver to use I/O APIC mode + // Set LevelTriggeredInterrupt to use level triggered interrupts when in I/O APIC mode + // Set InterruptRoute field based in mTimerIrq + // + mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE); + mTimerConfiguration.Bits.LevelTriggeredInterrupt = 1; + mTimerConfiguration.Bits.InterruptRoute = mTimerIrq; + } + + // + // Configure the selected HPET Timer with settings common to both MSI mode and I/O APIC mode + // Clear InterruptEnable to keep interrupts disabled until full init is complete + // Clear PeriodicInterruptEnable to use one-shot mode + // Configure as a 32-bit counter + // + mTimerConfiguration.Bits.InterruptEnable = 0; + mTimerConfiguration.Bits.PeriodicInterruptEnable = 0; + mTimerConfiguration.Bits.CounterSizeEnable = 1; + HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64); + + // + // Read the HPET Timer Capabilities and Configuration register back again. + // CounterSizeEnable will be read back as a 0 if it is a 32-bit only timer + // + mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE); + if ((mTimerConfiguration.Bits.CounterSizeEnable == 1) && (sizeof (UINTN) == sizeof (UINT64))) { + DEBUG ((DEBUG_INFO, "Choose 64-bit HPET timer.\n")); + // + // 64-bit BIOS can use 64-bit HPET timer + // + mCounterMask = 0xffffffffffffffffULL; + // + // Set timer back to 64-bit + // + mTimerConfiguration.Bits.CounterSizeEnable = 0; + HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64); + } else { + DEBUG ((DEBUG_INFO, "Choose 32-bit HPET timer.\n")); + mCounterMask = 0x00000000ffffffffULL; + } + + // + // Install interrupt handler for selected HPET Timer + // + Status = mCpu->RegisterInterruptHandler (mCpu, PcdGet8 (PcdHpetLocalApicVector), TimerInterruptHandler); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to register HPET interrupt with CPU Arch Protocol. Unload HPET driver.\n")); + return EFI_DEVICE_ERROR; + } + + // + // Force the HPET Timer to be enabled at its default period + // + Status = TimerDriverSetTimerPeriod (&mTimer, PcdGet64 (PcdHpetDefaultTimerPeriod)); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to set HPET default timer rate. Unload HPET driver.\n")); + return EFI_DEVICE_ERROR; + } + + // + // Show state of enabled HPET timer + // + DEBUG_CODE ( + if (mTimerConfiguration.Bits.MsiInterruptCapability != 0 && FeaturePcdGet (PcdHpetMsiEnable)) { + DEBUG ((DEBUG_INFO, "HPET Interrupt Mode MSI\n")); + } else { + DEBUG ((DEBUG_INFO, "HPET Interrupt Mode I/O APIC\n")); + DEBUG ((DEBUG_INFO, "HPET I/O APIC IRQ = 0x%02x\n", mTimerIrq)); + } + DEBUG ((DEBUG_INFO, "HPET Interrupt Vector = 0x%02x\n", PcdGet8 (PcdHpetLocalApicVector))); + DEBUG ((DEBUG_INFO, "HPET Counter Mask = 0x%016lx\n", mCounterMask)); + DEBUG ((DEBUG_INFO, "HPET Timer Period = %d\n", mTimerPeriod)); + DEBUG ((DEBUG_INFO, "HPET Timer Count = 0x%016lx\n", mTimerCount)); + DEBUG ((DEBUG_INFO, "HPET_TIMER%d_CONFIGURATION = 0x%016lx\n", mTimerIndex, HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE))); + DEBUG ((DEBUG_INFO, "HPET_TIMER%d_COMPARATOR = 0x%016lx\n", mTimerIndex, HpetRead (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE))); + DEBUG ((DEBUG_INFO, "HPET_TIMER%d_MSI_ROUTE = 0x%016lx\n", mTimerIndex, HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET + mTimerIndex * HPET_TIMER_STRIDE))); + + // + // Wait for a few timer interrupts to fire before continuing + // + while (mNumTicks < 10); + ); + + // + // Install the Timer Architectural Protocol onto a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mTimerHandle, + &gEfiTimerArchProtocolGuid, &mTimer, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf new file mode 100644 index 00000000..9327f65d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf @@ -0,0 +1,58 @@ +## @file +# Timer Architectural Protocol module using High Precision Event Timer (HPET). +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HpetTimerDxe + MODULE_UNI_FILE = HpetTimerDxe.uni + FILE_GUID = 6CE6B0DE-781C-4f6c-B42D-98346C614BEC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TimerDriverInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# + +[Sources] + HpetTimer.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + PcdLib + IoLib + DebugLib + UefiDriverEntryPoint + UefiBootServicesTableLib + BaseLib + LocalApicLib + IoApicLib + +[Protocols] + gEfiTimerArchProtocolGuid ## PRODUCES + gEfiCpuArchProtocolGuid ## CONSUMES + +[FeaturePcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetMsiEnable ## CONSUMES + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetBaseAddress ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetLocalApicVector ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetDefaultTimerPeriod ## CONSUMES + +[Depex] + gEfiCpuArchProtocolGuid +[UserExtensions.TianoCore."ExtraFiles"] + HpetTimerDxeExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.uni new file mode 100644 index 00000000..7d1797b1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.uni @@ -0,0 +1,16 @@ +// /** @file
+// Timer Architectural Protocol module using High Precision Event Timer (HPET).
+//
+// Timer Architectural Protocol module using High Precision Event Timer (HPET).
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Timer Architectural Protocol module using High Precision Event Timer (HPET)"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Timer Architectural Protocol module using High Precision Event Timer (HPET)."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxeExtra.uni new file mode 100644 index 00000000..37d99232 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// HpetTimerDxe Localized Strings and Content
+//
+// Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"High Precision Event Timer DXE Driver"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Guid/PcAtChipsetTokenSpace.h b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Guid/PcAtChipsetTokenSpace.h new file mode 100644 index 00000000..fa22a85f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Guid/PcAtChipsetTokenSpace.h @@ -0,0 +1,19 @@ +/** @file + GUID for PcAtChipsetPkg PCD Token Space. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PCATCHIPSET_TOKEN_SPACE_GUID_H_ +#define _PCATCHIPSET_TOKEN_SPACE_GUID_H_ + +#define PCATCHIPSET_TOKEN_SPACE_GUID \ + { \ + 0x326ae723, 0xae32, 0x4589, { 0x98, 0xb8, 0xca, 0xc2, 0x3c, 0xdc, 0xc1, 0xb1 } \ + } + +extern EFI_GUID gPcAtChipsetPkgTokenSpaceGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Library/IoApicLib.h b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Library/IoApicLib.h new file mode 100644 index 00000000..063fed23 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Library/IoApicLib.h @@ -0,0 +1,99 @@ +/** @file + Public include file for I/O APIC library. + + I/O APIC library assumes I/O APIC is enabled. It does not + handles cases where I/O APIC is disabled. + + Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#ifndef __IO_APIC_LIB_H__ +#define __IO_APIC_LIB_H__ + +/** + Read a 32-bit I/O APIC register. + + If Index is >= 0x100, then ASSERT(). + + @param Index Specifies the I/O APIC register to read. + + @return The 32-bit value read from the I/O APIC register specified by Index. +**/ +UINT32 +EFIAPI +IoApicRead ( + IN UINTN Index + ); + +/** + Write a 32-bit I/O APIC register. + + If Index is >= 0x100, then ASSERT(). + + @param Index Specifies the I/O APIC register to write. + @param Value Specifies the value to write to the I/O APIC register specified by Index. + + @return The 32-bit value written to I/O APIC register specified by Index. +**/ +UINT32 +EFIAPI +IoApicWrite ( + IN UINTN Index, + IN UINT32 Value + ); + +/** + Set the interrupt mask of an I/O APIC interrupt. + + If Irq is larger than the maximum number I/O APIC redirection entries, then ASSERT(). + + @param Irq Specifies the I/O APIC interrupt to enable or disable. + @param Enable If TRUE, then enable the I/O APIC interrupt specified by Irq. + If FALSE, then disable the I/O APIC interrupt specified by Irq. +**/ +VOID +EFIAPI +IoApicEnableInterrupt ( + IN UINTN Irq, + IN BOOLEAN Enable + ); + +/** + Configures an I/O APIC interrupt. + + Configure an I/O APIC Redirection Table Entry to deliver an interrupt in physical + mode to the Local APIC of the currently executing CPU. The default state of the + entry is for the interrupt to be disabled (masked). IoApicEnableInterrupts() must + be used to enable(unmask) the I/O APIC Interrupt. + + If Irq is larger than the maximum number I/O APIC redirection entries, then ASSERT(). + If Vector >= 0x100, then ASSERT(). + If DeliveryMode is not supported, then ASSERT(). + + @param Irq Specifies the I/O APIC interrupt to initialize. + @param Vector The 8-bit interrupt vector associated with the I/O APIC + Interrupt. Must be in the range 0x10..0xFE. + @param DeliveryMode A 3-bit value that specifies how the recept of the I/O APIC + interrupt is handled. The only supported values are: + 0: IO_APIC_DELIVERY_MODE_FIXED + 1: IO_APIC_DELIVERY_MODE_LOWEST_PRIORITY + 2: IO_APIC_DELIVERY_MODE_SMI + 4: IO_APIC_DELIVERY_MODE_NMI + 5: IO_APIC_DELIVERY_MODE_INIT + 7: IO_APIC_DELIVERY_MODE_EXTINT + @param LevelTriggered TRUE specifies a level triggered interrupt. + FALSE specifies an edge triggered interrupt. + @param AssertionLevel TRUE specified an active high interrupt. + FALSE specifies an active low interrupt. +**/ +VOID +EFIAPI +IoApicConfigureInterrupt ( + IN UINTN Irq, + IN UINTN Vector, + IN UINTN DeliveryMode, + IN BOOLEAN LevelTriggered, + IN BOOLEAN AssertionLevel + ); +#endif diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Register/Hpet.h b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Register/Hpet.h new file mode 100644 index 00000000..61ee14bb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Register/Hpet.h @@ -0,0 +1,100 @@ +/** @file + HPET register definitions from the IA-PC HPET (High Precision Event Timers) + Specification, Revision 1.0a, October 2004. + + Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __HPET_REGISTER_H__ +#define __HPET_REGISTER_H__ + +/// +/// HPET General Register Offsets +/// +#define HPET_GENERAL_CAPABILITIES_ID_OFFSET 0x000 +#define HPET_GENERAL_CONFIGURATION_OFFSET 0x010 +#define HPET_GENERAL_INTERRUPT_STATUS_OFFSET 0x020 + +/// +/// HPET Timer Register Offsets +/// +#define HPET_MAIN_COUNTER_OFFSET 0x0F0 +#define HPET_TIMER_CONFIGURATION_OFFSET 0x100 +#define HPET_TIMER_COMPARATOR_OFFSET 0x108 +#define HPET_TIMER_MSI_ROUTE_OFFSET 0x110 + +/// +/// Stride between sets of HPET Timer Registers +/// +#define HPET_TIMER_STRIDE 0x20 + +#pragma pack(1) + +/// +/// HPET General Capabilities and ID Register +/// +typedef union { + struct { + UINT32 Revision:8; + UINT32 NumberOfTimers:5; + UINT32 CounterSize:1; + UINT32 Reserved0:1; + UINT32 LegacyRoute:1; + UINT32 VendorId:16; + UINT32 CounterClockPeriod:32; + } Bits; + UINT64 Uint64; +} HPET_GENERAL_CAPABILITIES_ID_REGISTER; + +/// +/// HPET General Configuration Register +/// +typedef union { + struct { + UINT32 MainCounterEnable:1; + UINT32 LegacyRouteEnable:1; + UINT32 Reserved0:30; + UINT32 Reserved1:32; + } Bits; + UINT64 Uint64; +} HPET_GENERAL_CONFIGURATION_REGISTER; + +/// +/// HPET Timer Configuration Register +/// +typedef union { + struct { + UINT32 Reserved0:1; + UINT32 LevelTriggeredInterrupt:1; + UINT32 InterruptEnable:1; + UINT32 PeriodicInterruptEnable:1; + UINT32 PeriodicInterruptCapability:1; + UINT32 CounterSizeCapability:1; + UINT32 ValueSetEnable:1; + UINT32 Reserved1:1; + UINT32 CounterSizeEnable:1; + UINT32 InterruptRoute:5; + UINT32 MsiInterruptEnable:1; + UINT32 MsiInterruptCapability:1; + UINT32 Reserved2:16; + UINT32 InterruptRouteCapability; + } Bits; + UINT64 Uint64; +} HPET_TIMER_CONFIGURATION_REGISTER; + +/// +/// HPET Timer MSI Route Register +/// +typedef union { + struct { + UINT32 Value:32; + UINT32 Address:32; + } Bits; + UINT64 Uint64; +} HPET_TIMER_MSI_ROUTE_REGISTER; + +#pragma pack() + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Register/IoApic.h b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Register/IoApic.h new file mode 100644 index 00000000..6394aac8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Include/Register/IoApic.h @@ -0,0 +1,80 @@ +/** @file + I/O APIC Register Definitions from 82093AA I/O Advanced Programmable Interrupt + Controller (IOAPIC), 1996. + + Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __IO_APIC_H__ +#define __IO_APIC_H__ + +/// +/// I/O APIC Register Offsets +/// +#define IOAPIC_INDEX_OFFSET 0x00 +#define IOAPIC_DATA_OFFSET 0x10 + +/// +/// I/O APIC Indirect Register Indexes +/// +#define IO_APIC_IDENTIFICATION_REGISTER_INDEX 0x00 +#define IO_APIC_VERSION_REGISTER_INDEX 0x01 +#define IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX 0x10 + +/// +/// I/O APIC Interrupt Deliver Modes +/// +#define IO_APIC_DELIVERY_MODE_FIXED 0 +#define IO_APIC_DELIVERY_MODE_LOWEST_PRIORITY 1 +#define IO_APIC_DELIVERY_MODE_SMI 2 +#define IO_APIC_DELIVERY_MODE_NMI 4 +#define IO_APIC_DELIVERY_MODE_INIT 5 +#define IO_APIC_DELIVERY_MODE_EXTINT 7 + +#pragma pack(1) + +typedef union { + struct { + UINT32 Reserved0:24; + UINT32 Identification:4; + UINT32 Reserved1:4; + } Bits; + UINT32 Uint32; +} IO_APIC_IDENTIFICATION_REGISTER; + +typedef union { + struct { + UINT32 Version:8; + UINT32 Reserved0:8; + UINT32 MaximumRedirectionEntry:8; + UINT32 Reserved1:8; + } Bits; + UINT32 Uint32; +} IO_APIC_VERSION_REGISTER; + +typedef union { + struct { + UINT32 Vector: 8; + UINT32 DeliveryMode: 3; + UINT32 DestinationMode: 1; + UINT32 DeliveryStatus: 1; + UINT32 Polarity: 1; + UINT32 RemoteIRR: 1; + UINT32 TriggerMode: 1; + UINT32 Mask: 1; + UINT32 Reserved0: 15; + UINT32 Reserved1: 24; + UINT32 DestinationID: 8; + } Bits; + struct { + UINT32 Low; + UINT32 High; + } Uint32; + UINT64 Uint64; +} IO_APIC_REDIRECTION_TABLE_ENTRY; + +#pragma pack() + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c new file mode 100644 index 00000000..9d2a9030 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c @@ -0,0 +1,393 @@ +/** @file + ACPI Timer implements one instance of Timer Library. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> +#include <Library/TimerLib.h> +#include <Library/BaseLib.h> +#include <Library/PcdLib.h> +#include <Library/PciLib.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <IndustryStandard/Acpi.h> + +GUID mFrequencyHobGuid = { 0x3fca54f6, 0xe1a2, 0x4b20, { 0xbe, 0x76, 0x92, 0x6b, 0x4b, 0x48, 0xbf, 0xaa }}; + +/** + Internal function to retrieves the 64-bit frequency in Hz. + + Internal function to retrieves the 64-bit frequency in Hz. + + @return The frequency in Hz. + +**/ +UINT64 +InternalGetPerformanceCounterFrequency ( + VOID + ); + +/** + The constructor function enables ACPI IO space. + + If ACPI I/O space not enabled, this function will enable it. + It will always return RETURN_SUCCESS. + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +AcpiTimerLibConstructor ( + VOID + ) +{ + UINTN Bus; + UINTN Device; + UINTN Function; + UINTN EnableRegister; + UINT8 EnableMask; + + // + // ASSERT for the invalid PCD values. They must be configured to the real value. + // + ASSERT (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0xFFFF); + ASSERT (PcdGet16 (PcdAcpiIoPortBaseAddress) != 0xFFFF); + + // + // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then + // no PCI register programming is required to enable access to the ACPI registers + // specified by PcdAcpiIoPortBaseAddress + // + if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) { + return RETURN_SUCCESS; + } + + // + // ASSERT for the invalid PCD values. They must be configured to the real value. + // + ASSERT (PcdGet8 (PcdAcpiIoPciDeviceNumber) != 0xFF); + ASSERT (PcdGet8 (PcdAcpiIoPciFunctionNumber) != 0xFF); + ASSERT (PcdGet16 (PcdAcpiIoPciEnableRegisterOffset) != 0xFFFF); + + // + // Retrieve the PCD values for the PCI configuration space required to program the ACPI I/O Port Base Address + // + Bus = PcdGet8 (PcdAcpiIoPciBusNumber); + Device = PcdGet8 (PcdAcpiIoPciDeviceNumber); + Function = PcdGet8 (PcdAcpiIoPciFunctionNumber); + EnableRegister = PcdGet16 (PcdAcpiIoPciEnableRegisterOffset); + EnableMask = PcdGet8 (PcdAcpiIoBarEnableMask); + + // + // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. + // + if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister)) & EnableMask) != EnableMask) { + PciWrite16 ( + PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)), + PcdGet16 (PcdAcpiIoPortBaseAddress) + ); + PciOr8 ( + PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister), + EnableMask + ); + } + + return RETURN_SUCCESS; +} + +/** + Internal function to retrieve the ACPI I/O Port Base Address. + + Internal function to retrieve the ACPI I/O Port Base Address. + + @return The 16-bit ACPI I/O Port Base Address. + +**/ +UINT16 +InternalAcpiGetAcpiTimerIoPort ( + VOID + ) +{ + UINT16 Port; + + Port = PcdGet16 (PcdAcpiIoPortBaseAddress); + + // + // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then + // read the PCI register for the ACPI BAR value in case the BAR has been programmed to a + // value other than PcdAcpiIoPortBaseAddress + // + if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0x0000) { + Port = PciRead16 (PCI_LIB_ADDRESS ( + PcdGet8 (PcdAcpiIoPciBusNumber), + PcdGet8 (PcdAcpiIoPciDeviceNumber), + PcdGet8 (PcdAcpiIoPciFunctionNumber), + PcdGet16 (PcdAcpiIoPciBarRegisterOffset) + )); + } + + return (Port & PcdGet16 (PcdAcpiIoPortBaseAddressMask)) + PcdGet16 (PcdAcpiPm1TmrOffset); +} + +/** + Stalls the CPU for at least the given number of ticks. + + Stalls the CPU for at least the given number of ticks. It's invoked by + MicroSecondDelay() and NanoSecondDelay(). + + @param Delay A period of time to delay in ticks. + +**/ +VOID +InternalAcpiDelay ( + IN UINT32 Delay + ) +{ + UINT16 Port; + UINT32 Ticks; + UINT32 Times; + + Port = InternalAcpiGetAcpiTimerIoPort (); + Times = Delay >> 22; + Delay &= BIT22 - 1; + do { + // + // The target timer count is calculated here + // + Ticks = IoBitFieldRead32 (Port, 0, 23) + Delay; + Delay = BIT22; + // + // Wait until time out + // Delay >= 2^23 could not be handled by this function + // Timer wrap-arounds are handled correctly by this function + // + while (((Ticks - IoBitFieldRead32 (Port, 0, 23)) & BIT23) == 0) { + CpuPause (); + } + } while (Times-- > 0); +} + +/** + Stalls the CPU for at least the given number of microseconds. + + Stalls the CPU for the number of microseconds specified by MicroSeconds. + + @param MicroSeconds The minimum number of microseconds to delay. + + @return MicroSeconds + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + InternalAcpiDelay ( + (UINT32)DivU64x32 ( + MultU64x32 ( + MicroSeconds, + ACPI_TIMER_FREQUENCY + ), + 1000000u + ) + ); + return MicroSeconds; +} + +/** + Stalls the CPU for at least the given number of nanoseconds. + + Stalls the CPU for the number of nanoseconds specified by NanoSeconds. + + @param NanoSeconds The minimum number of nanoseconds to delay. + + @return NanoSeconds + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + InternalAcpiDelay ( + (UINT32)DivU64x32 ( + MultU64x32 ( + NanoSeconds, + ACPI_TIMER_FREQUENCY + ), + 1000000000u + ) + ); + return NanoSeconds; +} + +/** + Retrieves the current value of a 64-bit free running performance counter. + + Retrieves the current value of a 64-bit free running performance counter. The + counter can either count up by 1 or count down by 1. If the physical + performance counter counts by a larger increment, then the counter values + must be translated. The properties of the counter can be retrieved from + GetPerformanceCounterProperties(). + + @return The current value of the free running performance counter. + +**/ +UINT64 +EFIAPI +GetPerformanceCounter ( + VOID + ) +{ + return AsmReadTsc (); +} + +/** + Retrieves the 64-bit frequency in Hz and the range of performance counter + values. + + If StartValue is not NULL, then the value that the performance counter starts + with immediately after is it rolls over is returned in StartValue. If + EndValue is not NULL, then the value that the performance counter end with + immediately before it rolls over is returned in EndValue. The 64-bit + frequency of the performance counter in Hz is always returned. If StartValue + is less than EndValue, then the performance counter counts up. If StartValue + is greater than EndValue, then the performance counter counts down. For + example, a 64-bit free running counter that counts up would have a StartValue + of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter + that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. + + @param StartValue The value the performance counter starts with when it + rolls over. + @param EndValue The value that the performance counter ends with before + it rolls over. + + @return The frequency in Hz. + +**/ +UINT64 +EFIAPI +GetPerformanceCounterProperties ( + OUT UINT64 *StartValue, OPTIONAL + OUT UINT64 *EndValue OPTIONAL + ) +{ + if (StartValue != NULL) { + *StartValue = 0; + } + + if (EndValue != NULL) { + *EndValue = 0xffffffffffffffffULL; + } + return InternalGetPerformanceCounterFrequency (); +} + +/** + Converts elapsed ticks of performance counter to time in nanoseconds. + + This function converts the elapsed ticks of running performance counter to + time value in unit of nanoseconds. + + @param Ticks The number of elapsed ticks of running performance counter. + + @return The elapsed time in nanoseconds. + +**/ +UINT64 +EFIAPI +GetTimeInNanoSecond ( + IN UINT64 Ticks + ) +{ + UINT64 Frequency; + UINT64 NanoSeconds; + UINT64 Remainder; + INTN Shift; + + Frequency = GetPerformanceCounterProperties (NULL, NULL); + + // + // Ticks + // Time = --------- x 1,000,000,000 + // Frequency + // + NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u); + + // + // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit. + // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34, + // i.e. highest bit set in Remainder should <= 33. + // + Shift = MAX (0, HighBitSet64 (Remainder) - 33); + Remainder = RShiftU64 (Remainder, (UINTN) Shift); + Frequency = RShiftU64 (Frequency, (UINTN) Shift); + NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL); + + return NanoSeconds; +} + +/** + Calculate TSC frequency. + + The TSC counting frequency is determined by comparing how far it counts + during a 101.4 us period as determined by the ACPI timer. + The ACPI timer is used because it counts at a known frequency. + The TSC is sampled, followed by waiting 363 counts of the ACPI timer, + or 101.4 us. The TSC is then sampled again. The difference multiplied by + 9861 is the TSC frequency. There will be a small error because of the + overhead of reading the ACPI timer. An attempt is made to determine and + compensate for this error. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalCalculateTscFrequency ( + VOID + ) +{ + UINT64 StartTSC; + UINT64 EndTSC; + UINT16 TimerAddr; + UINT32 Ticks; + UINT64 TscFrequency; + BOOLEAN InterruptState; + + InterruptState = SaveAndDisableInterrupts (); + + TimerAddr = InternalAcpiGetAcpiTimerIoPort (); + // + // Compute the number of ticks to wait to measure TSC frequency. + // Use 363 * 9861 = 3579543 Hz which is within 2 Hz of ACPI_TIMER_FREQUENCY. + // 363 counts is a calibration time of 101.4 uS. + // + Ticks = IoBitFieldRead32 (TimerAddr, 0, 23) + 363; + + StartTSC = AsmReadTsc (); // Get base value for the TSC + // + // Wait until the ACPI timer has counted 101.4 us. + // Timer wrap-arounds are handled correctly by this function. + // When the current ACPI timer value is greater than 'Ticks', + // the while loop will exit. + // + while (((Ticks - IoBitFieldRead32 (TimerAddr, 0, 23)) & BIT23) == 0) { + CpuPause(); + } + EndTSC = AsmReadTsc (); // TSC value 101.4 us later + + TscFrequency = MultU64x32 ( + (EndTSC - StartTSC), // Number of TSC counts in 101.4 us + 9861 // Number of 101.4 us in a second + ); + + SetInterruptState (InterruptState); + + return TscFrequency; +} + diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.c new file mode 100644 index 00000000..436e4509 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.c @@ -0,0 +1,47 @@ +/** @file + ACPI Timer implements one instance of Timer Library. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> +#include <Library/TimerLib.h> +#include <Library/BaseLib.h> + +/** + Calculate TSC frequency. + + The TSC counting frequency is determined by comparing how far it counts + during a 101.4 us period as determined by the ACPI timer. + The ACPI timer is used because it counts at a known frequency. + The TSC is sampled, followed by waiting 363 counts of the ACPI timer, + or 101.4 us. The TSC is then sampled again. The difference multiplied by + 9861 is the TSC frequency. There will be a small error because of the + overhead of reading the ACPI timer. An attempt is made to determine and + compensate for this error. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalCalculateTscFrequency ( + VOID + ); + +/** + Internal function to retrieves the 64-bit frequency in Hz. + + Internal function to retrieves the 64-bit frequency in Hz. + + @return The frequency in Hz. + +**/ +UINT64 +InternalGetPerformanceCounterFrequency ( + VOID + ) +{ + return InternalCalculateTscFrequency (); +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf new file mode 100644 index 00000000..d5d6c957 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf @@ -0,0 +1,49 @@ +## @file +# Base ACPI Timer Library +# +# Provides basic timer support using the ACPI timer hardware. The performance +# counter features are provided by the processors time stamp counter. +# +# Note: The implementation uses the lower 24-bits of the ACPI timer and +# is compatible with both 24-bit and 32-bit ACPI timers. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseAcpiTimerLib + FILE_GUID = 564DE85F-049E-4481-BF7A-CA04D2788CF9 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM + CONSTRUCTOR = AcpiTimerLibConstructor + MODULE_UNI_FILE = BaseAcpiTimerLib.uni + +[Sources] + AcpiTimerLib.c + BaseAcpiTimerLib.c + +[Packages] + MdePkg/MdePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + PciLib + IoLib + DebugLib + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddressMask ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.uni new file mode 100644 index 00000000..a9814557 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.uni @@ -0,0 +1,17 @@ +// /** @file
+// Base ACPI Timer Library
+//
+// Provides basic timer support using the ACPI timer hardware. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "ACPI Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using the ACPI timer hardware."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.c new file mode 100644 index 00000000..5fe2e865 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.c @@ -0,0 +1,31 @@ +/** @file + ACPI Timer implements one instance of Timer Library. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include "DxeStandaloneMmAcpiTimerLib.h" + +/** + The constructor function enables ACPI IO space, and caches PerformanceCounterFrequency. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +DxeAcpiTimerLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return CommonAcpiTimerLibConstructor (); +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf new file mode 100644 index 00000000..5568dd30 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf @@ -0,0 +1,52 @@ +## @file +# DXE ACPI Timer Library +# +# Provides basic timer support using the ACPI timer hardware. The performance +# counter features are provided by the processors time stamp counter. +# +# Note: The implementation uses the lower 24-bits of the ACPI timer and +# is compatible with both 24-bit and 32-bit ACPI timers. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeAcpiTimerLib + FILE_GUID = E624B98C-845A-4b94-9B50-B20475D552B9 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE + CONSTRUCTOR = DxeAcpiTimerLibConstructor + MODULE_UNI_FILE = DxeAcpiTimerLib.uni + +[Sources] + AcpiTimerLib.c + DxeAcpiTimerLib.c + DxeStandaloneMmAcpiTimerLib.c + DxeStandaloneMmAcpiTimerLib.h + +[Packages] + MdePkg/MdePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + PciLib + IoLib + DebugLib + HobLib + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddressMask ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.uni new file mode 100644 index 00000000..e732ab6b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.uni @@ -0,0 +1,17 @@ +// /** @file
+// DXE ACPI Timer Library
+//
+// Provides basic timer support using the ACPI timer hardware. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "ACPI Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using the ACPI timer hardware."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeStandaloneMmAcpiTimerLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeStandaloneMmAcpiTimerLib.c new file mode 100644 index 00000000..de84d6c4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeStandaloneMmAcpiTimerLib.c @@ -0,0 +1,101 @@ +/** @file + ACPI Timer implements one instance of Timer Library. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/TimerLib.h> +#include <Library/BaseLib.h> +#include <Library/HobLib.h> + +extern GUID mFrequencyHobGuid; + +/** + The constructor function enables ACPI IO space. + + If ACPI I/O space not enabled, this function will enable it. + It will always return RETURN_SUCCESS. + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +AcpiTimerLibConstructor ( + VOID + ); + +/** + Calculate TSC frequency. + + The TSC counting frequency is determined by comparing how far it counts + during a 101.4 us period as determined by the ACPI timer. + The ACPI timer is used because it counts at a known frequency. + The TSC is sampled, followed by waiting 363 counts of the ACPI timer, + or 101.4 us. The TSC is then sampled again. The difference multiplied by + 9861 is the TSC frequency. There will be a small error because of the + overhead of reading the ACPI timer. An attempt is made to determine and + compensate for this error. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalCalculateTscFrequency ( + VOID + ); + +// +// Cached performance counter frequency +// +UINT64 mPerformanceCounterFrequency = 0; + +/** + Internal function to retrieves the 64-bit frequency in Hz. + + Internal function to retrieves the 64-bit frequency in Hz. + + @return The frequency in Hz. + +**/ +UINT64 +InternalGetPerformanceCounterFrequency ( + VOID + ) +{ + return mPerformanceCounterFrequency; +} + +/** + The constructor function enables ACPI IO space, and caches PerformanceCounterFrequency. + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +EFI_STATUS +CommonAcpiTimerLibConstructor ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + // + // Enable ACPI IO space. + // + AcpiTimerLibConstructor (); + + // + // Initialize PerformanceCounterFrequency + // + GuidHob = GetFirstGuidHob (&mFrequencyHobGuid); + if (GuidHob != NULL) { + mPerformanceCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA (GuidHob); + } else { + mPerformanceCounterFrequency = InternalCalculateTscFrequency (); + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeStandaloneMmAcpiTimerLib.h b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeStandaloneMmAcpiTimerLib.h new file mode 100644 index 00000000..981d41e3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/DxeStandaloneMmAcpiTimerLib.h @@ -0,0 +1,24 @@ +/** @file + Header file internal to ACPI TimerLib. + +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _DXE_STANDALONE_MM_ACPI_TIMER_LIB_H_ +#define _DXE_STANDALONE_MM_ACPI_TIMER_LIB_H_ + +/** + The constructor function enables ACPI IO space, and caches PerformanceCounterFrequency. + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +EFI_STATUS +CommonAcpiTimerLibConstructor ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.c new file mode 100644 index 00000000..05dc81b2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.c @@ -0,0 +1,64 @@ +/** @file + ACPI Timer implements one instance of Timer Library. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/TimerLib.h> +#include <Library/BaseLib.h> +#include <Library/HobLib.h> +#include <Library/DebugLib.h> + +extern GUID mFrequencyHobGuid; + +/** + Calculate TSC frequency. + + The TSC counting frequency is determined by comparing how far it counts + during a 101.4 us period as determined by the ACPI timer. + The ACPI timer is used because it counts at a known frequency. + The TSC is sampled, followed by waiting 363 counts of the ACPI timer, + or 101.4 us. The TSC is then sampled again. The difference multiplied by + 9861 is the TSC frequency. There will be a small error because of the + overhead of reading the ACPI timer. An attempt is made to determine and + compensate for this error. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalCalculateTscFrequency ( + VOID + ); + +/** + Internal function to retrieves the 64-bit frequency in Hz. + + Internal function to retrieves the 64-bit frequency in Hz. + + @return The frequency in Hz. + +**/ +UINT64 +InternalGetPerformanceCounterFrequency ( + VOID + ) +{ + UINT64 *PerformanceCounterFrequency; + EFI_HOB_GUID_TYPE *GuidHob; + + PerformanceCounterFrequency = NULL; + GuidHob = GetFirstGuidHob (&mFrequencyHobGuid); + if (GuidHob == NULL) { + PerformanceCounterFrequency = (UINT64*)BuildGuidHob(&mFrequencyHobGuid, sizeof (*PerformanceCounterFrequency)); + ASSERT (PerformanceCounterFrequency != NULL); + *PerformanceCounterFrequency = InternalCalculateTscFrequency (); + } else { + PerformanceCounterFrequency = (UINT64*)GET_GUID_HOB_DATA (GuidHob); + } + + return *PerformanceCounterFrequency; +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf new file mode 100644 index 00000000..99f71764 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf @@ -0,0 +1,50 @@ +## @file +# PEI ACPI Timer Library +# +# Provides basic timer support using the ACPI timer hardware. The performance +# counter features are provided by the processors time stamp counter. +# +# Note: The implementation uses the lower 24-bits of the ACPI timer and +# is compatible with both 24-bit and 32-bit ACPI timers. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiAcpiTimerLib + FILE_GUID = 3FCA54F6-E1A2-4B20-BE76-926B4B48BFAA + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib|PEI_CORE PEIM + CONSTRUCTOR = AcpiTimerLibConstructor + MODULE_UNI_FILE = PeiAcpiTimerLib.uni + +[Sources] + AcpiTimerLib.c + PeiAcpiTimerLib.c + +[Packages] + MdePkg/MdePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + PciLib + IoLib + DebugLib + HobLib + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddressMask ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.uni new file mode 100644 index 00000000..b6e96e4e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.uni @@ -0,0 +1,17 @@ +// /** @file
+// PEI ACPI Timer Library
+//
+// Provides basic timer support using the ACPI timer hardware. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "ACPI Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using the ACPI timer hardware."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.c new file mode 100644 index 00000000..3484eff3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.c @@ -0,0 +1,31 @@ +/** @file + ACPI Timer implements one instance of Timer Library. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> + Copyright (c) Microsoft Corporation. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include "DxeStandaloneMmAcpiTimerLib.h" + +/** + The constructor function enables ACPI IO space, and caches PerformanceCounterFrequency. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +StandaloneMmAcpiTimerLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_MM_SYSTEM_TABLE *SystemTable + ) +{ + return CommonAcpiTimerLibConstructor (); +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.inf new file mode 100644 index 00000000..2628c744 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.inf @@ -0,0 +1,53 @@ +## @file +# Standalone MM ACPI Timer Library +# +# Provides basic timer support using the ACPI timer hardware. The performance +# counter features are provided by the processors time stamp counter. +# +# Note: The implementation uses the lower 24-bits of the ACPI timer and +# is compatible with both 24-bit and 32-bit ACPI timers. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = StandaloneMmAcpiTimerLib + FILE_GUID = C771858D-AF09-4D1A-B2F3-C7F081C3F076 + MODULE_TYPE = MM_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = TimerLib|MM_CORE_STANDALONE MM_STANDALONE + CONSTRUCTOR = StandaloneMmAcpiTimerLibConstructor + +[Sources] + AcpiTimerLib.c + StandaloneMmAcpiTimerLib.c + DxeStandaloneMmAcpiTimerLib.c + DxeStandaloneMmAcpiTimerLib.h + +[Packages] + MdePkg/MdePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + PciLib + IoLib + DebugLib + HobLib + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddressMask ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf new file mode 100644 index 00000000..441af96f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf @@ -0,0 +1,34 @@ +## @file +# Library instance for I/O APIC library class +# +# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseIoApicLib + MODULE_UNI_FILE = BaseIoApicLib.uni + FILE_GUID = 58ED6E5A-E36A-462a-9ED6-6E62C9A26DF8 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = IoApicLib + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + DebugLib + IoLib + PcdLib + LocalApicLib + +[Sources] + IoApicLib.c + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdIoApicBaseAddress ## CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.uni new file mode 100644 index 00000000..5931b252 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Library instance for I/O APIC library class
+//
+// Library instance for I/O APIC library class.
+//
+// Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Library instance for I/O APIC library class"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Library instance for I/O APIC library class."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/IoApicLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/IoApicLib.c new file mode 100644 index 00000000..61bc3bf6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/BaseIoApicLib/IoApicLib.c @@ -0,0 +1,152 @@ +/** @file + I/O APIC library. + + I/O APIC library assumes I/O APIC is enabled. It does not + handles cases where I/O APIC is disabled. + + Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> + +#include <Library/IoApicLib.h> + +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/LocalApicLib.h> + +#include <Register/IoApic.h> + +/** + Read a 32-bit I/O APIC register. + + If Index is >= 0x100, then ASSERT(). + + @param Index Specifies the I/O APIC register to read. + + @return The 32-bit value read from the I/O APIC register specified by Index. +**/ +UINT32 +EFIAPI +IoApicRead ( + IN UINTN Index + ) +{ + ASSERT (Index < 0x100); + MmioWrite8 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_INDEX_OFFSET, (UINT8)Index); + return MmioRead32 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_DATA_OFFSET); +} + +/** + Write a 32-bit I/O APIC register. + + If Index is >= 0x100, then ASSERT(). + + @param Index Specifies the I/O APIC register to write. + @param Value Specifies the value to write to the I/O APIC register specified by Index. + + @return The 32-bit value written to I/O APIC register specified by Index. +**/ +UINT32 +EFIAPI +IoApicWrite ( + IN UINTN Index, + IN UINT32 Value + ) +{ + ASSERT (Index < 0x100); + MmioWrite8 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_INDEX_OFFSET, (UINT8)Index); + return MmioWrite32 (PcdGet32 (PcdIoApicBaseAddress) + IOAPIC_DATA_OFFSET, Value); +} + +/** + Set the interrupt mask of an I/O APIC interrupt. + + If Irq is larger than the maximum number I/O APIC redirection entries, then ASSERT(). + + @param Irq Specifies the I/O APIC interrupt to enable or disable. + @param Enable If TRUE, then enable the I/O APIC interrupt specified by Irq. + If FALSE, then disable the I/O APIC interrupt specified by Irq. +**/ +VOID +EFIAPI +IoApicEnableInterrupt ( + IN UINTN Irq, + IN BOOLEAN Enable + ) +{ + IO_APIC_VERSION_REGISTER Version; + IO_APIC_REDIRECTION_TABLE_ENTRY Entry; + + Version.Uint32 = IoApicRead (IO_APIC_VERSION_REGISTER_INDEX); + ASSERT (Version.Bits.MaximumRedirectionEntry < 0xF0); + ASSERT (Irq <= Version.Bits.MaximumRedirectionEntry); + + Entry.Uint32.Low = IoApicRead (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2); + Entry.Bits.Mask = Enable ? 0 : 1; + IoApicWrite (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2, Entry.Uint32.Low); +} + +/** + Configures an I/O APIC interrupt. + + Configure an I/O APIC Redirection Table Entry to deliver an interrupt in physical + mode to the Local APIC of the currently executing CPU. The default state of the + entry is for the interrupt to be disabled (masked). IoApicEnableInterrupts() must + be used to enable(unmask) the I/O APIC Interrupt. + + If Irq is larger than the maximum number I/O APIC redirection entries, then ASSERT(). + If Vector >= 0x100, then ASSERT(). + If DeliveryMode is not supported, then ASSERT(). + + @param Irq Specifies the I/O APIC interrupt to initialize. + @param Vector The 8-bit interrupt vector associated with the I/O APIC + Interrupt. Must be in the range 0x10..0xFE. + @param DeliveryMode A 3-bit value that specifies how the recept of the I/O APIC + interrupt is handled. The only supported values are: + 0: IO_APIC_DELIVERY_MODE_FIXED + 1: IO_APIC_DELIVERY_MODE_LOWEST_PRIORITY + 2: IO_APIC_DELIVERY_MODE_SMI + 4: IO_APIC_DELIVERY_MODE_NMI + 5: IO_APIC_DELIVERY_MODE_INIT + 7: IO_APIC_DELIVERY_MODE_EXTINT + @param LevelTriggered TRUE specifies a level triggered interrupt. + FALSE specifies an edge triggered interrupt. + @param AssertionLevel TRUE specified an active high interrupt. + FALSE specifies an active low interrupt. +**/ +VOID +EFIAPI +IoApicConfigureInterrupt ( + IN UINTN Irq, + IN UINTN Vector, + IN UINTN DeliveryMode, + IN BOOLEAN LevelTriggered, + IN BOOLEAN AssertionLevel + ) +{ + IO_APIC_VERSION_REGISTER Version; + IO_APIC_REDIRECTION_TABLE_ENTRY Entry; + + Version.Uint32 = IoApicRead (IO_APIC_VERSION_REGISTER_INDEX); + ASSERT (Version.Bits.MaximumRedirectionEntry < 0xF0); + ASSERT (Irq <= Version.Bits.MaximumRedirectionEntry); + ASSERT (Vector <= 0xFF); + ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3); + + Entry.Uint32.Low = IoApicRead (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2); + Entry.Bits.Vector = (UINT8)Vector; + Entry.Bits.DeliveryMode = (UINT32)DeliveryMode; + Entry.Bits.DestinationMode = 0; + Entry.Bits.Polarity = AssertionLevel ? 0 : 1; + Entry.Bits.TriggerMode = LevelTriggered ? 1 : 0; + Entry.Bits.Mask = 1; + IoApicWrite (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2, Entry.Uint32.Low); + + Entry.Uint32.High = IoApicRead (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2 + 1); + Entry.Bits.DestinationID = GetApicId (); + IoApicWrite (IO_APIC_REDIRECTION_TABLE_ENTRY_INDEX + Irq * 2 + 1, Entry.Uint32.High); +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.c new file mode 100644 index 00000000..d8021df0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.c @@ -0,0 +1,130 @@ +/** @file + Reset System Library functions for PCAT platforms + + Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> + +#include <Uefi/UefiBaseType.h> +#include <Uefi/UefiMultiPhase.h> + +#include <Library/DebugLib.h> +#include <Library/IoLib.h> + +/** + Calling this function causes a system-wide reset. This sets + all circuitry within the system to its initial state. This type of reset + is asynchronous to system operation and operates without regard to + cycle boundaries. + + System reset should not return, if it returns, it means the system does + not support cold reset. +**/ +VOID +EFIAPI +ResetCold ( + VOID + ) +{ + IoWrite8 ((UINTN) PcdGet64 (PcdResetControlRegister), PcdGet8 (PcdResetControlValueColdReset)); +} + +/** + Calling this function causes a system-wide initialization. The processors + are set to their initial state, and pending cycles are not corrupted. + + System reset should not return, if it returns, it means the system does + not support warm reset. +**/ +VOID +EFIAPI +ResetWarm ( + VOID + ) +{ + IoWrite8 ((UINTN) PcdGet64 (PcdResetControlRegister), PcdGet8 (PcdResetControlValueColdReset)); +} + +/** + Calling this function causes the system to enter a power state equivalent + to the ACPI G2/S5 or G3 states. + + System shutdown should not return, if it returns, it means the system does + not support shut down reset. +**/ +VOID +EFIAPI +ResetShutdown ( + VOID + ) +{ + ASSERT (FALSE); +} + + +/** + This function causes a systemwide reset. The exact type of the reset is + defined by the EFI_GUID that follows the Null-terminated Unicode string passed + into ResetData. If the platform does not recognize the EFI_GUID in ResetData + the platform must pick a supported reset type to perform.The platform may + optionally log the parameters from any non-normal reset that occurs. + + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData The data buffer starts with a Null-terminated string, + followed by the EFI_GUID. +**/ +VOID +EFIAPI +ResetPlatformSpecific ( + IN UINTN DataSize, + IN VOID *ResetData + ) +{ + ResetCold (); +} + +/** + The ResetSystem function resets the entire platform. + + @param[in] ResetType The type of reset to perform. + @param[in] ResetStatus The status code for the reset. + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown + the data buffer starts with a Null-terminated string, optionally + followed by additional binary data. The string is a description + that the caller may use to further indicate the reason for the + system reset. +**/ +VOID +EFIAPI +ResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + switch (ResetType) { + case EfiResetWarm: + ResetWarm (); + break; + + case EfiResetCold: + ResetCold (); + break; + + case EfiResetShutdown: + ResetShutdown (); + return; + + case EfiResetPlatformSpecific: + ResetPlatformSpecific (DataSize, ResetData); + return; + + default: + return; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.inf new file mode 100644 index 00000000..375d3dcd --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.inf @@ -0,0 +1,37 @@ +## @file +# Library instance for ResetSystem library class for PCAT systems +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ResetSystemLib + MODULE_UNI_FILE = ResetSystemLib.uni + FILE_GUID = EC4F3E59-F879-418b-9E4C-7D6F434714A0 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ResetSystemLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + ResetSystemLib.c + +[Packages] + MdePkg/MdePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + DebugLib + IoLib + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdResetControlRegister ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdResetControlValueColdReset ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.uni new file mode 100644 index 00000000..ea2a9103 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Library instance for ResetSystem library class for PCAT systems
+//
+// Library instance for ResetSystem library class for PCAT systems
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Library instance for ResetSystem library class for PCAT systems"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Library instance for ResetSystem library class for PCAT systems"
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/PcAtSerialPortLib.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/PcAtSerialPortLib.uni new file mode 100644 index 00000000..2efd21ca --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/PcAtSerialPortLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Library instance for SerialIo library class
+//
+// Library instance for SerialIO library class.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Library instance for SerialIO library class"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Library instance for SerialIO library class."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf new file mode 100644 index 00000000..6d3bad36 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf @@ -0,0 +1,27 @@ +## @file +# Library instance for SerialIo library class +# +# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PcAtSerialPortLib + MODULE_UNI_FILE = PcAtSerialPortLib.uni + FILE_GUID = 1B25AF84-1EA8-4b52-894E-BFA6880B97FF + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + IoLib + +[Sources] + SerialPortLib.c + diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c new file mode 100644 index 00000000..6c126504 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/Library/SerialIoLib/SerialPortLib.c @@ -0,0 +1,483 @@ +/** @file + UART Serial Port library functions + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Base.h> +#include <Library/IoLib.h> +#include <Library/SerialPortLib.h> + +//--------------------------------------------- +// UART Register Offsets +//--------------------------------------------- +#define BAUD_LOW_OFFSET 0x00 +#define BAUD_HIGH_OFFSET 0x01 +#define IER_OFFSET 0x01 +#define LCR_SHADOW_OFFSET 0x01 +#define FCR_SHADOW_OFFSET 0x02 +#define IR_CONTROL_OFFSET 0x02 +#define FCR_OFFSET 0x02 +#define EIR_OFFSET 0x02 +#define BSR_OFFSET 0x03 +#define LCR_OFFSET 0x03 +#define MCR_OFFSET 0x04 +#define LSR_OFFSET 0x05 +#define MSR_OFFSET 0x06 + +//--------------------------------------------- +// UART Register Bit Defines +//--------------------------------------------- +#define LSR_TXRDY 0x20 +#define LSR_RXDA 0x01 +#define DLAB 0x01 +#define MCR_DTRC 0x01 +#define MCR_RTS 0x02 +#define MSR_CTS 0x10 +#define MSR_DSR 0x20 +#define MSR_RI 0x40 +#define MSR_DCD 0x80 + +//--------------------------------------------- +// UART Settings +//--------------------------------------------- +UINT16 gUartBase = 0x3F8; +UINTN gBps = 115200; +UINT8 gData = 8; +UINT8 gStop = 1; +UINT8 gParity = 0; +UINT8 gBreakSet = 0; + +/** + Initialize the serial device hardware. + + If no initialization is required, then return RETURN_SUCCESS. + If the serial device was successfully initialized, then return RETURN_SUCCESS. + If the serial device could not be initialized, then return RETURN_DEVICE_ERROR. + + @retval RETURN_SUCCESS The serial device was initialized. + @retval RETURN_DEVICE_ERROR The serial device could not be initialized. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + UINTN Divisor; + UINT8 OutputData; + UINT8 Data; + + // + // Map 5..8 to 0..3 + // + Data = (UINT8) (gData - (UINT8) 5); + + // + // Calculate divisor for baud generator + // + Divisor = 115200 / gBps; + + // + // Set communications format + // + OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data); + IoWrite8 (gUartBase + LCR_OFFSET, OutputData); + + // + // Configure baud rate + // + IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8) (Divisor >> 8)); + IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8) (Divisor & 0xff)); + + // + // Switch back to bank 0 + // + OutputData = (UINT8) ( (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data); + IoWrite8 (gUartBase + LCR_OFFSET, OutputData); + + return RETURN_SUCCESS; +} + +/** + Write data from buffer to serial device. + + Writes NumberOfBytes data bytes from Buffer to the serial device. + The number of bytes actually written to the serial device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + + If Buffer is NULL, then ASSERT(). + + If NumberOfBytes is zero, then return 0. + + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the serial device. + If this value is less than NumberOfBytes, then the write operation failed. + +**/ +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Result; + UINT8 Data; + + if (Buffer == NULL) { + return 0; + } + + Result = NumberOfBytes; + + while ((NumberOfBytes--) != 0) { + // + // Wait for the serial port to be ready. + // + do { + Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET); + } while ((Data & LSR_TXRDY) == 0); + IoWrite8 ((UINT16) gUartBase, *Buffer++); + } + + return Result; +} + + +/** + Reads data from a serial device into a buffer. + + @param Buffer Pointer to the data buffer to store the data read from the serial device. + @param NumberOfBytes Number of bytes to read from the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes read from the serial device. + If this value is less than NumberOfBytes, then the read operation failed. + +**/ +UINTN +EFIAPI +SerialPortRead ( + OUT UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINTN Result; + UINT8 Data; + + if (NULL == Buffer) { + return 0; + } + + Result = NumberOfBytes; + + while ((NumberOfBytes--) != 0) { + // + // Wait for the serial port to be ready. + // + do { + Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET); + } while ((Data & LSR_RXDA) == 0); + + *Buffer++ = IoRead8 ((UINT16) gUartBase); + } + + return Result; +} + +/** + Polls a serial device to see if there is any data waiting to be read. + + Polls a serial device to see if there is any data waiting to be read. + If there is data waiting to be read from the serial device, then TRUE is returned. + If there is no data waiting to be read from the serial device, then FALSE is returned. + + @retval TRUE Data is waiting to be read from the serial device. + @retval FALSE There is no data waiting to be read from the serial device. + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( + VOID + ) +{ + UINT8 Data; + + // + // Read the serial port status. + // + Data = IoRead8 ((UINT16) gUartBase + LSR_OFFSET); + + return (BOOLEAN) ((Data & LSR_RXDA) != 0); +} + +/** + Sets the control bits on a serial device. + + @param Control Sets the bits of Control that are settable. + + @retval RETURN_SUCCESS The new control bits were set on the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetControl ( + IN UINT32 Control + ) +{ + UINT8 Mcr; + + // + // First determine the parameter is invalid. + // + if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY))) != 0) { + return RETURN_UNSUPPORTED; + } + + // + // Read the Modem Control Register. + // + Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET); + Mcr &= (~(MCR_DTRC | MCR_RTS)); + + if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) { + Mcr |= MCR_DTRC; + } + + if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) { + Mcr |= MCR_RTS; + } + + // + // Write the Modem Control Register. + // + IoWrite8 ((UINT16) gUartBase + MCR_OFFSET, Mcr); + + return RETURN_SUCCESS; +} + +/** + Retrieve the status of the control bits on a serial device. + + @param Control A pointer to return the current control signals from the serial device. + + @retval RETURN_SUCCESS The control bits were read from the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortGetControl ( + OUT UINT32 *Control + ) +{ + UINT8 Msr; + UINT8 Mcr; + UINT8 Lsr; + + *Control = 0; + + // + // Read the Modem Status Register. + // + Msr = IoRead8 ((UINT16) gUartBase + MSR_OFFSET); + + if ((Msr & MSR_CTS) == MSR_CTS) { + *Control |= EFI_SERIAL_CLEAR_TO_SEND; + } + + if ((Msr & MSR_DSR) == MSR_DSR) { + *Control |= EFI_SERIAL_DATA_SET_READY; + } + + if ((Msr & MSR_RI) == MSR_RI) { + *Control |= EFI_SERIAL_RING_INDICATE; + } + + if ((Msr & MSR_DCD) == MSR_DCD) { + *Control |= EFI_SERIAL_CARRIER_DETECT; + } + + // + // Read the Modem Control Register. + // + Mcr = IoRead8 ((UINT16) gUartBase + MCR_OFFSET); + + if ((Mcr & MCR_DTRC) == MCR_DTRC) { + *Control |= EFI_SERIAL_DATA_TERMINAL_READY; + } + + if ((Mcr & MCR_RTS) == MCR_RTS) { + *Control |= EFI_SERIAL_REQUEST_TO_SEND; + } + + // + // Read the Line Status Register. + // + Lsr = IoRead8 ((UINT16) gUartBase + LSR_OFFSET); + + if ((Lsr & LSR_TXRDY) == LSR_TXRDY) { + *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } + + if ((Lsr & LSR_RXDA) == 0) { + *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY; + } + + return RETURN_SUCCESS; +} + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data bits, and stop bits on a serial device. + + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the + device's default interface speed. + On output, the value actually set. + @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the + serial interface. A ReceiveFifoDepth value of 0 will use + the device's default FIFO depth. + On output, the value actually set. + @param Timeout The requested time out for a single character in microseconds. + This timeout applies to both the transmit and receive side of the + interface. A Timeout value of 0 will use the device's default time + out value. + On output, the value actually set. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + On output, the value actually set. + @param DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + On output, the value actually set. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + On output, the value actually set. + + @retval RETURN_SUCCESS The new attributes were set on the serial device. + @retval RETURN_UNSUPPORTED The serial device does not support this operation. + @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value. + @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +RETURN_STATUS +EFIAPI +SerialPortSetAttributes ( + IN OUT UINT64 *BaudRate, + IN OUT UINT32 *ReceiveFifoDepth, + IN OUT UINT32 *Timeout, + IN OUT EFI_PARITY_TYPE *Parity, + IN OUT UINT8 *DataBits, + IN OUT EFI_STOP_BITS_TYPE *StopBits + ) +{ + UINTN Divisor; + UINT8 OutputData; + UINT8 LcrData; + UINT8 LcrParity; + UINT8 LcrStop; + + // + // Check for default settings and fill in actual values. + // + if (*BaudRate == 0) { + *BaudRate = gBps; + } + + if (*DataBits == 0) { + *DataBits = gData; + } + + if (*Parity == DefaultParity) { + *Parity = NoParity; + } + + if (*StopBits == DefaultStopBits) { + *StopBits = OneStopBit; + } + + if ((*DataBits < 5) || (*DataBits > 8)) { + return RETURN_INVALID_PARAMETER; + } + + // + // Map 5..8 to 0..3 + // + LcrData = (UINT8) (*DataBits - (UINT8) 5); + + switch (*Parity) { + case NoParity: + LcrParity = 0; + break; + + case EvenParity: + LcrParity = 3; + break; + + case OddParity: + LcrParity = 1; + break; + + case SpaceParity: + LcrParity = 7; + break; + + case MarkParity: + LcrParity = 5; + break; + + default: + return RETURN_INVALID_PARAMETER; + } + + switch (*StopBits) { + case OneStopBit: + LcrStop = 0; + break; + + case OneFiveStopBits: + case TwoStopBits: + LcrStop = 1; + break; + + default: + return RETURN_INVALID_PARAMETER; + } + + // + // Calculate divisor for baud generator + // + Divisor = 115200 / (UINTN) *BaudRate; + + // + // Set communications format + // + OutputData = (UINT8) ((DLAB << 7) | (gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData); + IoWrite8 (gUartBase + LCR_OFFSET, OutputData); + + // + // Configure baud rate + // + IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8) (Divisor >> 8)); + IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8) (Divisor & 0xff)); + + // + // Switch back to bank 0 + // + OutputData = (UINT8) ((gBreakSet << 6) | (LcrParity << 3) | (LcrStop << 2) | LcrData); + IoWrite8 (gUartBase + LCR_OFFSET, OutputData); + + return RETURN_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.ci.yaml b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.ci.yaml new file mode 100644 index 00000000..1e796e8b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.ci.yaml @@ -0,0 +1,62 @@ +## @file +# CI configuration for PcAtChipsetPkg +# +# Copyright (c) Microsoft Corporation +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +{ + ## options defined .pytool/Plugin/LicenseCheck + "LicenseCheck": { + "IgnoreFiles": [] + }, + "EccCheck": { + ## Exception sample looks like below: + ## "ExceptionList": [ + ## "<ErrorID>", "<KeyWord>" + ## ] + "ExceptionList": [ + ], + ## Both file path and directory path are accepted. + "IgnoreFiles": [ + ] + }, + "CompilerPlugin": { + "DscPath": "PcAtChipsetPkg.dsc" + }, + "CharEncodingCheck": { + "IgnoreFiles": [] + }, + "DependencyCheck": { + "AcceptableDependencies": [ + "MdePkg/MdePkg.dec", + "PcAtChipsetPkg/PcAtChipsetPkg.dec", + "UefiCpuPkg/UefiCpuPkg.dec" + ], + # For host based unit tests + "AcceptableDependencies-HOST_APPLICATION":[], + # For UEFI shell based apps + "AcceptableDependencies-UEFI_APPLICATION":[], + "IgnoreInf": [] + }, + "DscCompleteCheck": { + "DscPath": "PcAtChipsetPkg.dsc", + "IgnoreInf": [] + }, + "GuidCheck": { + "IgnoreGuidName": [], + "IgnoreGuidValue": [], + "IgnoreFoldersAndFiles": [], + "IgnoreDuplicates": [] + }, + "LibraryClassCheck": { + "IgnoreHeaderFile": [] + }, + "SpellCheck": { + "ExtendWords": [ + "ENUMER", # this is part of an IDE enum + "PCATCHIPSET", + "TXRDY" + ] + } +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.dec b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.dec new file mode 100644 index 00000000..1fff8365 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.dec @@ -0,0 +1,162 @@ +## @file +# Public definitions for PcAtChipset package. +# +# This package is designed to public interfaces and implementation which follows +# PcAt defacto standard. +# +# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2017, AMD Inc. All rights reserved.<BR> +# Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = PcAtChipsetPkg + PACKAGE_UNI_FILE = PcAtChipsetPkg.uni + PACKAGE_GUID = B728689A-52D3-4b8c-AE89-2CE5514CC6DC + PACKAGE_VERSION = 0.3 + +[Includes] + Include + +[LibraryClasses] + ## @libraryclass Provides functions to manage I/O APIC Redirection Table Entries. + # + IoApicLib|Include/Library/IoApicLib.h + +[Guids] + gPcAtChipsetPkgTokenSpaceGuid = { 0x326ae723, 0xae32, 0x4589, { 0x98, 0xb8, 0xca, 0xc2, 0x3c, 0xdc, 0xc1, 0xb1 } } + +# +# [Error.gPcAtChipsetPkgTokenSpaceGuid] +# 0x80000001 | Invalid value provided. +# + +[PcdsFeatureFlag] + ## Indicates the HPET Timer will be configured to use MSI interrupts if the HPET timer supports them, or use I/O APIC interrupts.<BR><BR> + # TRUE - Configures the HPET Timer to use MSI interrupts if the HPET Timer supports them.<BR> + # FALSE - Configures the HPET Timer to use I/O APIC interrupts.<BR> + # @Prompt Configure HPET to use MSI. + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetMsiEnable|TRUE|BOOLEAN|0x00001000 + + ## Indicates the RTC port registers are in MMIO space, or in I/O space. + # Default is I/O space.<BR><BR> + # TRUE - RTC port registers are in MMIO space.<BR> + # FALSE - RTC port registers are in I/O space.<BR> + # @Prompt RTC port registers use MMIO. + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|FALSE|BOOLEAN|0x00000021 + +[PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx, PcdsPatchableInModule] + ## This PCD specifies the base address of the HPET timer. + # @Prompt HPET base address. + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetBaseAddress|0xFED00000|UINT32|0x00000009 + + ## This PCD specifies the Local APIC Interrupt Vector for the HPET Timer. + # @Prompt HPET local APIC vector. + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetLocalApicVector|0x40|UINT8|0x0000000A + + ## This PCD specifies the default period of the HPET Timer in 100 ns units. + # The default value of 100000 100 ns units is the same as 10 ms. + # @Prompt Default period of HPET timer. + gPcAtChipsetPkgTokenSpaceGuid.PcdHpetDefaultTimerPeriod|100000|UINT64|0x0000000B + + ## This PCD specifies the base address of the IO APIC. + # @Prompt IO APIC base address. + gPcAtChipsetPkgTokenSpaceGuid.PcdIoApicBaseAddress|0xFEC00000|UINT32|0x0000000C + + ## This PCD specifies the minimal valid year in RTC. + # @Prompt Minimal valid year in RTC. + gPcAtChipsetPkgTokenSpaceGuid.PcdMinimalValidYear|1998|UINT16|0x0000000D + + ## This PCD specifies the maximal valid year in RTC. + # @Prompt Maximal valid year in RTC. + # @Expression 0x80000001 | gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear < gPcAtChipsetPkgTokenSpaceGuid.PcdMinimalValidYear + 100 + gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear|2097|UINT16|0x0000000E + + ## Specifies RTC Index Register address in MMIO space. + # @Prompt RTC Index Register address + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister64|0x0|UINT64|0x00000022 + + ## Specifies RTC Target Register address in MMIO space. + # @Prompt RTC Target Register address + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister64|0x0|UINT64|0x00000023 + +[PcdsFixedAtBuild, PcdsPatchableInModule] + ## Defines the ACPI register set base address. + # The invalid 0xFFFF is as its default value. It must be configured to the real value. + # @Prompt ACPI Timer IO Port Address + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress |0xFFFF|UINT16|0x00000010 + + ## Defines the PCI Bus Number of the PCI device that contains the BAR and Enable for ACPI hardware registers. + # @Prompt ACPI Hardware PCI Bus Number + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber | 0x00| UINT8|0x00000011 + + ## Defines the PCI Device Number of the PCI device that contains the BAR and Enable for ACPI hardware registers. + # The invalid 0xFF is as its default value. It must be configured to the real value. + # @Prompt ACPI Hardware PCI Device Number + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber | 0xFF| UINT8|0x00000012 + + ## Defines the PCI Function Number of the PCI device that contains the BAR and Enable for ACPI hardware registers. + # The invalid 0xFF is as its default value. It must be configured to the real value. + # @Prompt ACPI Hardware PCI Function Number + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber | 0xFF| UINT8|0x00000013 + + ## Defines the PCI Register Offset of the PCI device that contains the Enable for ACPI hardware registers. + # The invalid 0xFFFF is as its default value. It must be configured to the real value. + # @Prompt ACPI Hardware PCI Register Offset + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset |0xFFFF|UINT16|0x00000014 + + ## Defines the bit mask that must be set to enable the APIC hardware register BAR. + # @Prompt ACPI Hardware PCI Bar Enable BitMask + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask | 0x00| UINT8|0x00000015 + + ## Defines the PCI Register Offset of the PCI device that contains the BAR for ACPI hardware registers. + # The invalid 0xFFFF is as its default value. It must be configured to the real value. + # @Prompt ACPI Hardware PCI Bar Register Offset + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset |0xFFFF|UINT16|0x00000016 + + ## Defines the offset to the 32-bit Timer Value register that resides within the ACPI BAR. + # @Prompt Offset to 32-bit Timer register in ACPI BAR + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset |0x0008|UINT16|0x00000017 + + ## Defines the bit mask to retrieve ACPI IO Port Base Address + # @Prompt ACPI IO Port Base Address Mask + gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddressMask |0xFFFE|UINT16|0x00000018 + + ## Reset Control Register address in I/O space. + # @Prompt Reset Control Register address + gPcAtChipsetPkgTokenSpaceGuid.PcdResetControlRegister|0x64|UINT64|0x00000019 + + ## 8bit Reset Control Register value for cold reset. + # @Prompt Reset Control Register value for cold reset + gPcAtChipsetPkgTokenSpaceGuid.PcdResetControlValueColdReset|0xFE|UINT8|0x0000001A + + ## Specifies the initial value for Register_A in RTC. + # @Prompt Initial value for Register_A in RTC. + gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterA|0x26|UINT8|0x0000001B + + ## Specifies the initial value for Register_B in RTC. + # @Prompt Initial value for Register_B in RTC. + gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterB|0x02|UINT8|0x0000001C + + ## Specifies the initial value for Register_D in RTC. + # @Prompt Initial value for Register_D in RTC. + gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterD|0x00|UINT8|0x0000001D + + ## Specifies RTC Index Register address in I/O space. + # @Prompt RTC Index Register address + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister|0x70|UINT8|0x0000001E + + ## Specifies RTC Target Register address in I/O space. + # @Prompt RTC Target Register address + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister|0x71|UINT8|0x0000001F + + ## RTC Update Timeout Value(microsecond). + # @Prompt RTC Update Timeout Value. + gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout|100000|UINT32|0x00000020 + +[UserExtensions.TianoCore."ExtraFiles"] + PcAtChipsetPkgExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.dsc b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.dsc new file mode 100644 index 00000000..b580c934 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.dsc @@ -0,0 +1,62 @@ +## @file +# PC/AT Chipset Package +# +# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2020, AMD Incorporated. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + PLATFORM_NAME = PcAtChipset + PLATFORM_GUID = a653167b-34d7-4b91-bfe3-f0c7608f48da + PLATFORM_VERSION = 0.3 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/PcAtChipset + SUPPORTED_ARCHITECTURES = IA32|X64 + BUILD_TARGETS = DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER = DEFAULT + +!include MdePkg/MdeLibs.dsc.inc + +[LibraryClasses] + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf + PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf + ResetSystemLib|PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.inf + IoApicLib|PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf + LocalApicLib|UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf + UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + +[Components] + PcAtChipsetPkg/HpetTimerDxe/HpetTimerDxe.inf + PcAtChipsetPkg/Bus/Pci/IdeControllerDxe/IdeControllerDxe.inf + PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf + PcAtChipsetPkg/Library/ResetSystemLib/ResetSystemLib.inf + PcAtChipsetPkg/Library/BaseIoApicLib/BaseIoApicLib.inf + PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf + PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf + PcAtChipsetPkg/Library/AcpiTimerLib/PeiAcpiTimerLib.inf + PcAtChipsetPkg/Library/AcpiTimerLib/StandaloneMmAcpiTimerLib.inf + PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf + +[BuildOptions] + *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.uni new file mode 100644 index 00000000..d290dcf1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkg.uni @@ -0,0 +1,120 @@ +// /** @file
+// Public definitions for PcAtChipset package.
+//
+// This package is designed to public interfaces and implementation which follows
+// PcAt defacto standard.
+//
+// Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_PACKAGE_ABSTRACT #language en-US "Public definitions for PcAtChipset package"
+
+#string STR_PACKAGE_DESCRIPTION #language en-US "This package is designed to public interfaces and implementation which follows PcAt de facto standard."
+
+
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetBaseAddress_PROMPT #language en-US "HPET base address"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetBaseAddress_HELP #language en-US "This PCD specifies the base address of the HPET timer."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetLocalApicVector_PROMPT #language en-US "HPET local APIC vector"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetLocalApicVector_HELP #language en-US "This PCD specifies the Local APIC Interrupt Vector for the HPET Timer."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetDefaultTimerPeriod_PROMPT #language en-US "Default period of HPET timer"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetDefaultTimerPeriod_HELP #language en-US "This PCD specifies the default period of the HPET Timer in 100 ns units. The value of 100000 (in 100 ns units) is equal to 10 ms."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdIoApicBaseAddress_PROMPT #language en-US "IO APIC base address"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdIoApicBaseAddress_HELP #language en-US "This PCD specifies the base address of the IO APIC."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPortBaseAddress_PROMPT #language en-US "ACPI Timer IO Port Address"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPortBaseAddress_HELP #language en-US "Defines the ACPI register set base address. The invalid 0xFFFF is as its default value. It must be configured to the real value."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciBusNumber_PROMPT #language en-US "ACPI Hardware PCI Bus Number"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciBusNumber_HELP #language en-US "Defines the PCI Bus Number of the PCI device that contains the BAR and Enable for ACPI hardware registers."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciDeviceNumber_PROMPT #language en-US "ACPI Hardware PCI Device Number"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciDeviceNumber_HELP #language en-US "Defines the PCI Device Number of the PCI device that contains the BAR and Enable for ACPI hardware registers. The invalid 0xFF is as its default value. It must be configured to the real value."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciFunctionNumber_PROMPT #language en-US "ACPI Hardware PCI Function Number"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciFunctionNumber_HELP #language en-US "Defines the PCI Function Number of the PCI device that contains the BAR and Enable for ACPI hardware registers. The invalid 0xFF is as its default value. It must be configured to the real value."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciEnableRegisterOffset_PROMPT #language en-US "ACPI Hardware PCI Register Offset"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciEnableRegisterOffset_HELP #language en-US "Defines the PCI Register Offset of the PCI device that contains the Enable for ACPI hardware registers. The invalid 0xFFFF is as its default value. It must be configured to the real value."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoBarEnableMask_PROMPT #language en-US "ACPI Hardware PCI Bar Enable BitMask"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoBarEnableMask_HELP #language en-US "Defines the bit mask that must be set to enable the APIC hardware register BAR."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciBarRegisterOffset_PROMPT #language en-US "ACPI Hardware PCI Bar Register Offset"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPciBarRegisterOffset_HELP #language en-US "Defines the PCI Register Offset of the PCI device that contains the BAR for ACPI hardware registers. The invalid 0xFFFF is as its default value. It must be configured to the real value."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiPm1TmrOffset_PROMPT #language en-US "Offset to 32-bit Timer register in ACPI BAR"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiPm1TmrOffset_HELP #language en-US "Defines the offset to the 32-bit Timer Value register that resides within the ACPI BAR."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetMsiEnable_PROMPT #language en-US "Configure HPET to use MSI"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdHpetMsiEnable_HELP #language en-US "Indicates the HPET Timer will be configured to use MSI interrupts if the HPET timer supports them, or use I/O APIC interrupts.<BR><BR>\n"
+ "TRUE - Configures the HPET Timer to use MSI interrupts if the HPET Timer supports them.<BR>\n"
+ "FALSE - Configures the HPET Timer to use I/O APIC interrupts.<BR>"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdMinimalValidYear_PROMPT #language en-US "Minimal valid year in RTC"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdMinimalValidYear_HELP #language en-US "This PCD specifies the minimal valid year in RTC."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdMaximalValidYear_PROMPT #language en-US "Maximal valid year in RTC"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdMaximalValidYear_HELP #language en-US "This PCD specifies the maximal valid year in RTC."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPortBaseAddressMask_PROMPT #language en-US "ACPI IO Port Base Address Mask"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdAcpiIoPortBaseAddressMask_HELP #language en-US "Defines the bit mask to retrieve ACPI IO Port Base Address."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_ERR_80000001 #language en-US "Invalid value provided."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdResetControlRegister_PROMPT
+#language en-US
+"Reset Control Register address"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdResetControlRegister_HELP
+#language en-US
+"Reset Control Register address in I/O space."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdResetControlValueColdReset_PROMPT
+#language en-US
+"Reset Control Register value for cold reset"
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdResetControlValueColdReset_HELP
+#language en-US
+"8bit Reset Control Register value for cold reset."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdInitialValueRtcRegisterA_PROMPT #language en-US "Initial value for Register_A in RTC."
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdInitialValueRtcRegisterA_HELP #language en-US "Specifies the initial value for Register_A in RTC."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdInitialValueRtcRegisterB_PROMPT #language en-US "Initial value for Register_B in RTC."
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdInitialValueRtcRegisterB_HELP #language en-US "Specifies the initial value for Register_B in RTC."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdInitialValueRtcRegisterD_PROMPT #language en-US "Initial value for Register_D in RTC."
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdInitialValueRtcRegisterD_HELP #language en-US "Specifies the initial value for Register_D in RTC."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdRtcIndexRegister_PROMPT #language en-US "RTC Index Register address"
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdRtcIndexRegister_HELP #language en-US "Specifies RTC Index Register address in I/O space."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdRtcTargetRegister_PROMPT #language en-US "RTC Target Register address"
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdRtcTargetRegister_HELP #language en-US "Specifies RTC Target Register address in I/O space."
+
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdRealTimeClockUpdateTimeout_PROMPT #language en-US "RTC Update Timeout Value"
+#string STR_gPcAtChipsetPkgTokenSpaceGuid_PcdRealTimeClockUpdateTimeout_HELP #language en-US "RTC Update Timeout Value(microsecond)."
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkgExtra.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkgExtra.uni new file mode 100644 index 00000000..889b8793 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcAtChipsetPkgExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// PcAtChipset Package Localized Strings and Content.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_PACKAGE_NAME
+#language en-US
+"PcAtChipset package"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c new file mode 100644 index 00000000..6620d811 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c @@ -0,0 +1,1355 @@ +/** @file + RTC Architectural Protocol GUID as defined in DxeCis 0.96. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2017, AMD Inc. All rights reserved.<BR> +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PcRtc.h" + +extern UINTN mRtcIndexRegister; +extern UINTN mRtcTargetRegister; + +// +// Days of month. +// +UINTN mDayOfMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +// +// The name of NV variable to store the timezone and daylight saving information. +// +CHAR16 mTimeZoneVariableName[] = L"RTC"; + +/** + Compare the Hour, Minute and Second of the From time and the To time. + + Only compare H/M/S in EFI_TIME and ignore other fields here. + + @param From the first time + @param To the second time + + @return >0 The H/M/S of the From time is later than those of To time + @return ==0 The H/M/S of the From time is same as those of To time + @return <0 The H/M/S of the From time is earlier than those of To time +**/ +INTN +CompareHMS ( + IN EFI_TIME *From, + IN EFI_TIME *To + ); + +/** + To check if second date is later than first date within 24 hours. + + @param From the first date + @param To the second date + + @retval TRUE From is previous to To within 24 hours. + @retval FALSE From is later, or it is previous to To more than 24 hours. +**/ +BOOLEAN +IsWithinOneDay ( + IN EFI_TIME *From, + IN EFI_TIME *To + ); + +/** + Read RTC content through its registers using IO access. + + @param Address Address offset of RTC. It is recommended to use + macros such as RTC_ADDRESS_SECONDS. + + @return The data of UINT8 type read from RTC. +**/ +STATIC +UINT8 +IoRtcRead ( + IN UINTN Address + ) +{ + IoWrite8 ( + PcdGet8 (PcdRtcIndexRegister), + (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)) + ); + return IoRead8 (PcdGet8 (PcdRtcTargetRegister)); +} + +/** + Write RTC through its registers using IO access. + + @param Address Address offset of RTC. It is recommended to use + macros such as RTC_ADDRESS_SECONDS. + @param Data The content you want to write into RTC. + +**/ +STATIC +VOID +IoRtcWrite ( + IN UINTN Address, + IN UINT8 Data + ) +{ + IoWrite8 ( + PcdGet8 (PcdRtcIndexRegister), + (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)) + ); + IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data); +} + +/** + Read RTC content through its registers using MMIO access. + + @param Address Address offset of RTC. It is recommended to use + macros such as RTC_ADDRESS_SECONDS. + + @return The data of UINT8 type read from RTC. +**/ +STATIC +UINT8 +MmioRtcRead ( + IN UINTN Address + ) +{ + MmioWrite8 ( + mRtcIndexRegister, + (UINT8)(Address | (UINT8)(MmioRead8 (mRtcIndexRegister) & 0x80)) + ); + return MmioRead8 (mRtcTargetRegister); +} + +/** + Write RTC through its registers using MMIO access. + + @param Address Address offset of RTC. It is recommended to use + macros such as RTC_ADDRESS_SECONDS. + @param Data The content you want to write into RTC. + +**/ +STATIC +VOID +MmioRtcWrite ( + IN UINTN Address, + IN UINT8 Data + ) +{ + MmioWrite8 ( + mRtcIndexRegister, + (UINT8)(Address | (UINT8)(MmioRead8 (mRtcIndexRegister) & 0x80)) + ); + MmioWrite8 (mRtcTargetRegister, Data); +} + +/** + Read RTC content through its registers. + + @param Address Address offset of RTC. It is recommended to use + macros such as RTC_ADDRESS_SECONDS. + + @return The data of UINT8 type read from RTC. +**/ +STATIC +UINT8 +RtcRead ( + IN UINTN Address + ) +{ + if (FeaturePcdGet (PcdRtcUseMmio)) { + return MmioRtcRead (Address); + } + + return IoRtcRead (Address); +} + +/** + Write RTC through its registers. + + @param Address Address offset of RTC. It is recommended to use + macros such as RTC_ADDRESS_SECONDS. + @param Data The content you want to write into RTC. + +**/ +STATIC +VOID +RtcWrite ( + IN UINTN Address, + IN UINT8 Data + ) +{ + if (FeaturePcdGet (PcdRtcUseMmio)) { + MmioRtcWrite (Address, Data); + } else { + IoRtcWrite (Address, Data); + } +} + +/** + Initialize RTC. + + @param Global For global use inside this module. + + @retval EFI_DEVICE_ERROR Initialization failed due to device error. + @retval EFI_SUCCESS Initialization successful. + +**/ +EFI_STATUS +PcRtcInit ( + IN PC_RTC_MODULE_GLOBALS *Global + ) +{ + EFI_STATUS Status; + RTC_REGISTER_A RegisterA; + RTC_REGISTER_B RegisterB; + RTC_REGISTER_D RegisterD; + EFI_TIME Time; + UINTN DataSize; + UINT32 TimerVar; + BOOLEAN Enabled; + BOOLEAN Pending; + + // + // Acquire RTC Lock to make access to RTC atomic + // + if (!EfiAtRuntime ()) { + EfiAcquireLock (&Global->RtcLock); + } + // + // Initialize RTC Register + // + // Make sure Division Chain is properly configured, + // or RTC clock won't "tick" -- time won't increment + // + RegisterA.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterA); + RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data); + + // + // Read Register B + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + // + // Clear RTC flag register + // + RtcRead (RTC_ADDRESS_REGISTER_C); + + // + // Clear RTC register D + // + RegisterD.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterD); + RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout)); + if (EFI_ERROR (Status)) { + // + // Set the variable with default value if the RTC is functioning incorrectly. + // + Global->SavedTimeZone = EFI_UNSPECIFIED_TIMEZONE; + Global->Daylight = 0; + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_DEVICE_ERROR; + } + // + // Get the Time/Date/Daylight Savings values. + // + Time.Second = RtcRead (RTC_ADDRESS_SECONDS); + Time.Minute = RtcRead (RTC_ADDRESS_MINUTES); + Time.Hour = RtcRead (RTC_ADDRESS_HOURS); + Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time.Month = RtcRead (RTC_ADDRESS_MONTH); + Time.Year = RtcRead (RTC_ADDRESS_YEAR); + + // + // Set RTC configuration after get original time + // The value of bit AIE should be reserved. + // + RegisterB.Data = FixedPcdGet8 (PcdInitialValueRtcRegisterB) | (RegisterB.Data & BIT5); + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + + // + // Get the data of Daylight saving and time zone, if they have been + // stored in NV variable during previous boot. + // + DataSize = sizeof (UINT32); + Status = EfiGetVariable ( + mTimeZoneVariableName, + &gEfiCallerIdGuid, + NULL, + &DataSize, + &TimerVar + ); + if (!EFI_ERROR (Status)) { + Time.TimeZone = (INT16) TimerVar; + Time.Daylight = (UINT8) (TimerVar >> 16); + } else { + Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Time.Daylight = 0; + } + + // + // Validate time fields + // + Status = ConvertRtcTimeToEfiTime (&Time, RegisterB); + if (!EFI_ERROR (Status)) { + Status = RtcTimeFieldsValid (&Time); + } + if (EFI_ERROR (Status)) { + // + // Report Status Code to indicate that the RTC has bad date and time + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_SOFTWARE_DXE_RT_DRIVER | EFI_SW_EC_BAD_DATE_TIME) + ); + Time.Second = RTC_INIT_SECOND; + Time.Minute = RTC_INIT_MINUTE; + Time.Hour = RTC_INIT_HOUR; + Time.Day = RTC_INIT_DAY; + Time.Month = RTC_INIT_MONTH; + Time.Year = PcdGet16 (PcdMinimalValidYear); + Time.Nanosecond = 0; + Time.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Time.Daylight = 0; + } + + // + // Reset time value according to new RTC configuration + // + Status = PcRtcSetTime (&Time, Global); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Reset wakeup time value to valid state when wakeup alarm is disabled and wakeup time is invalid. + // Global variable has already had valid SavedTimeZone and Daylight, + // so we can use them to get and set wakeup time. + // + Status = PcRtcGetWakeupTime (&Enabled, &Pending, &Time, Global); + if ((Enabled) || (!EFI_ERROR (Status))) { + return EFI_SUCCESS; + } + + // + // When wakeup time is disabled and invalid, reset wakeup time register to valid state + // but keep wakeup alarm disabled. + // + Time.Second = RTC_INIT_SECOND; + Time.Minute = RTC_INIT_MINUTE; + Time.Hour = RTC_INIT_HOUR; + Time.Day = RTC_INIT_DAY; + Time.Month = RTC_INIT_MONTH; + Time.Year = PcdGet16 (PcdMinimalValidYear); + Time.Nanosecond = 0; + Time.TimeZone = Global->SavedTimeZone; + Time.Daylight = Global->Daylight;; + + // + // Acquire RTC Lock to make access to RTC atomic + // + if (!EfiAtRuntime ()) { + EfiAcquireLock (&Global->RtcLock); + } + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout)); + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_DEVICE_ERROR; + } + + ConvertEfiTimeToRtcTime (&Time, RegisterB); + + // + // Set the Y/M/D info to variable as it has no corresponding hw registers. + // + Status = EfiSetVariable ( + L"RTCALARM", + &gEfiCallerIdGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (Time), + &Time + ); + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_DEVICE_ERROR; + } + + // + // Inhibit updates of the RTC + // + RegisterB.Bits.Set = 1; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Set RTC alarm time registers + // + RtcWrite (RTC_ADDRESS_SECONDS_ALARM, Time.Second); + RtcWrite (RTC_ADDRESS_MINUTES_ALARM, Time.Minute); + RtcWrite (RTC_ADDRESS_HOURS_ALARM, Time.Hour); + + // + // Allow updates of the RTC registers + // + RegisterB.Bits.Set = 0; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_SUCCESS; +} + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + @param Global For global use inside this module. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +PcRtcGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities, OPTIONAL + IN PC_RTC_MODULE_GLOBALS *Global + ) +{ + EFI_STATUS Status; + RTC_REGISTER_B RegisterB; + + // + // Check parameters for null pointer + // + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + if (!EfiAtRuntime ()) { + EfiAcquireLock (&Global->RtcLock); + } + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout)); + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return Status; + } + // + // Read Register B + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + // + // Get the Time/Date/Daylight Savings values. + // + Time->Second = RtcRead (RTC_ADDRESS_SECONDS); + Time->Minute = RtcRead (RTC_ADDRESS_MINUTES); + Time->Hour = RtcRead (RTC_ADDRESS_HOURS); + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + + // + // Release RTC Lock. + // + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + + // + // Get the variable that contains the TimeZone and Daylight fields + // + Time->TimeZone = Global->SavedTimeZone; + Time->Daylight = Global->Daylight; + + // + // Make sure all field values are in correct range + // + Status = ConvertRtcTimeToEfiTime (Time, RegisterB); + if (!EFI_ERROR (Status)) { + Status = RtcTimeFieldsValid (Time); + } + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Fill in Capabilities if it was passed in + // + if (Capabilities != NULL) { + Capabilities->Resolution = 1; + // + // 1 hertz + // + Capabilities->Accuracy = 50000000; + // + // 50 ppm + // + Capabilities->SetsToZero = FALSE; + } + + return EFI_SUCCESS; +} + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + @param Global For global use inside this module. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +PcRtcSetTime ( + IN EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +{ + EFI_STATUS Status; + EFI_TIME RtcTime; + RTC_REGISTER_B RegisterB; + UINT32 TimerVar; + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure that the time fields are valid + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); + + // + // Acquire RTC Lock to make access to RTC atomic + // + if (!EfiAtRuntime ()) { + EfiAcquireLock (&Global->RtcLock); + } + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout)); + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return Status; + } + + // + // Write timezone and daylight to RTC variable + // + if ((Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE) && (Time->Daylight == 0)) { + Status = EfiSetVariable ( + mTimeZoneVariableName, + &gEfiCallerIdGuid, + 0, + 0, + NULL + ); + if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + } + } else { + TimerVar = Time->Daylight; + TimerVar = (UINT32) ((TimerVar << 16) | (UINT16)(Time->TimeZone)); + Status = EfiSetVariable ( + mTimeZoneVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (TimerVar), + &TimerVar + ); + } + + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_DEVICE_ERROR; + } + + // + // Read Register B, and inhibit updates of the RTC + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + RegisterB.Bits.Set = 1; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Store the century value to RTC before converting to BCD format. + // + if (Global->CenturyRtcAddress != 0) { + RtcWrite (Global->CenturyRtcAddress, DecimalToBcd8 ((UINT8) (RtcTime.Year / 100))); + } + + ConvertEfiTimeToRtcTime (&RtcTime, RegisterB); + + RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second); + RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute); + RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour); + RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day); + RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month); + RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year); + + // + // Allow updates of the RTC registers + // + RegisterB.Bits.Set = 0; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + // + // Set the variable that contains the TimeZone and Daylight fields + // + Global->SavedTimeZone = Time->TimeZone; + Global->Daylight = Time->Daylight; + + return EFI_SUCCESS; +} + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgment. + @param Time The current alarm setting. + @param Global For global use inside this module. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Enabled is NULL. + @retval EFI_INVALID_PARAMETER Pending is NULL. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +PcRtcGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ) +{ + EFI_STATUS Status; + RTC_REGISTER_B RegisterB; + RTC_REGISTER_C RegisterC; + EFI_TIME RtcTime; + UINTN DataSize; + + // + // Check parameters for null pointers + // + if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) { + return EFI_INVALID_PARAMETER; + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + if (!EfiAtRuntime ()) { + EfiAcquireLock (&Global->RtcLock); + } + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout)); + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_DEVICE_ERROR; + } + // + // Read Register B and Register C + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C); + + // + // Get the Time/Date/Daylight Savings values. + // + *Enabled = RegisterB.Bits.Aie; + *Pending = RegisterC.Bits.Af; + + Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM); + Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM); + Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM); + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + Time->TimeZone = Global->SavedTimeZone; + Time->Daylight = Global->Daylight; + + // + // Get the alarm info from variable + // + DataSize = sizeof (EFI_TIME); + Status = EfiGetVariable ( + L"RTCALARM", + &gEfiCallerIdGuid, + NULL, + &DataSize, + &RtcTime + ); + if (!EFI_ERROR (Status)) { + // + // The alarm variable exists. In this case, we read variable to get info. + // + Time->Day = RtcTime.Day; + Time->Month = RtcTime.Month; + Time->Year = RtcTime.Year; + } + + // + // Release RTC Lock. + // + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + + // + // Make sure all field values are in correct range + // + Status = ConvertRtcTimeToEfiTime (Time, RegisterB); + if (!EFI_ERROR (Status)) { + Status = RtcTimeFieldsValid (Time); + } + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + If Enable is FALSE, then this parameter is optional, and may be NULL. + @param Global For global use inside this module. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. + If Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +PcRtcSetWakeupTime ( + IN BOOLEAN Enable, + IN EFI_TIME *Time, OPTIONAL + IN PC_RTC_MODULE_GLOBALS *Global + ) +{ + EFI_STATUS Status; + EFI_TIME RtcTime; + RTC_REGISTER_B RegisterB; + EFI_TIME_CAPABILITIES Capabilities; + + ZeroMem (&RtcTime, sizeof (RtcTime)); + + if (Enable) { + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure that the time fields are valid + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + // + // Just support set alarm time within 24 hours + // + PcRtcGetTime (&RtcTime, &Capabilities, Global); + Status = RtcTimeFieldsValid (&RtcTime); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + if (!IsWithinOneDay (&RtcTime, Time)) { + return EFI_UNSUPPORTED; + } + // + // Make a local copy of the time and date + // + CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + if (!EfiAtRuntime ()) { + EfiAcquireLock (&Global->RtcLock); + } + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout)); + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_DEVICE_ERROR; + } + // + // Read Register B + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + if (Enable) { + ConvertEfiTimeToRtcTime (&RtcTime, RegisterB); + } else { + // + // if the alarm is disable, record the current setting. + // + RtcTime.Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM); + RtcTime.Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM); + RtcTime.Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM); + RtcTime.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + RtcTime.Month = RtcRead (RTC_ADDRESS_MONTH); + RtcTime.Year = RtcRead (RTC_ADDRESS_YEAR); + RtcTime.TimeZone = Global->SavedTimeZone; + RtcTime.Daylight = Global->Daylight; + } + + // + // Set the Y/M/D info to variable as it has no corresponding hw registers. + // + Status = EfiSetVariable ( + L"RTCALARM", + &gEfiCallerIdGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (RtcTime), + &RtcTime + ); + if (EFI_ERROR (Status)) { + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_DEVICE_ERROR; + } + + // + // Inhibit updates of the RTC + // + RegisterB.Bits.Set = 1; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + if (Enable) { + // + // Set RTC alarm time + // + RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second); + RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute); + RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour); + + RegisterB.Bits.Aie = 1; + + } else { + RegisterB.Bits.Aie = 0; + } + // + // Allow updates of the RTC registers + // + RegisterB.Bits.Set = 0; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + if (!EfiAtRuntime ()) { + EfiReleaseLock (&Global->RtcLock); + } + return EFI_SUCCESS; +} + + +/** + Checks an 8-bit BCD value, and converts to an 8-bit value if valid. + + This function checks the 8-bit BCD value specified by Value. + If valid, the function converts it to an 8-bit value and returns it. + Otherwise, return 0xff. + + @param Value The 8-bit BCD value to check and convert + + @return The 8-bit value converted. Or 0xff if Value is invalid. + +**/ +UINT8 +CheckAndConvertBcd8ToDecimal8 ( + IN UINT8 Value + ) +{ + if ((Value < 0xa0) && ((Value & 0xf) < 0xa)) { + return BcdToDecimal8 (Value); + } + + return 0xff; +} + +/** + Converts time read from RTC to EFI_TIME format defined by UEFI spec. + + This function converts raw time data read from RTC to the EFI_TIME format + defined by UEFI spec. + If data mode of RTC is BCD, then converts it to decimal, + If RTC is in 12-hour format, then converts it to 24-hour format. + + @param Time On input, the time data read from RTC to convert + On output, the time converted to UEFI format + @param RegisterB Value of Register B of RTC, indicating data mode + and hour format. + + @retval EFI_INVALID_PARAMETER Parameters passed in are invalid. + @retval EFI_SUCCESS Convert RTC time to EFI time successfully. + +**/ +EFI_STATUS +ConvertRtcTimeToEfiTime ( + IN OUT EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB + ) +{ + BOOLEAN IsPM; + UINT8 Century; + + if ((Time->Hour & 0x80) != 0) { + IsPM = TRUE; + } else { + IsPM = FALSE; + } + + Time->Hour = (UINT8) (Time->Hour & 0x7f); + + if (RegisterB.Bits.Dm == 0) { + Time->Year = CheckAndConvertBcd8ToDecimal8 ((UINT8) Time->Year); + Time->Month = CheckAndConvertBcd8ToDecimal8 (Time->Month); + Time->Day = CheckAndConvertBcd8ToDecimal8 (Time->Day); + Time->Hour = CheckAndConvertBcd8ToDecimal8 (Time->Hour); + Time->Minute = CheckAndConvertBcd8ToDecimal8 (Time->Minute); + Time->Second = CheckAndConvertBcd8ToDecimal8 (Time->Second); + } + + if (Time->Year == 0xff || Time->Month == 0xff || Time->Day == 0xff || + Time->Hour == 0xff || Time->Minute == 0xff || Time->Second == 0xff) { + return EFI_INVALID_PARAMETER; + } + + // + // For minimal/maximum year range [1970, 2069], + // Century is 19 if RTC year >= 70, + // Century is 20 otherwise. + // + Century = (UINT8) (PcdGet16 (PcdMinimalValidYear) / 100); + if (Time->Year < PcdGet16 (PcdMinimalValidYear) % 100) { + Century++; + } + Time->Year = (UINT16) (Century * 100 + Time->Year); + + // + // If time is in 12 hour format, convert it to 24 hour format + // + if (RegisterB.Bits.Mil == 0) { + if (IsPM && Time->Hour < 12) { + Time->Hour = (UINT8) (Time->Hour + 12); + } + + if (!IsPM && Time->Hour == 12) { + Time->Hour = 0; + } + } + + Time->Nanosecond = 0; + + return EFI_SUCCESS; +} + +/** + Wait for a period for the RTC to be ready. + + @param Timeout Tell how long it should take to wait. + + @retval EFI_DEVICE_ERROR RTC device error. + @retval EFI_SUCCESS RTC is updated and ready. +**/ +EFI_STATUS +RtcWaitToUpdate ( + UINTN Timeout + ) +{ + RTC_REGISTER_A RegisterA; + RTC_REGISTER_D RegisterD; + + // + // See if the RTC is functioning correctly + // + RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); + + if (RegisterD.Bits.Vrt == 0) { + return EFI_DEVICE_ERROR; + } + // + // Wait for up to 0.1 seconds for the RTC to be ready. + // + Timeout = (Timeout / 10) + 1; + RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); + while (RegisterA.Bits.Uip == 1 && Timeout > 0) { + MicroSecondDelay (10); + RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); + Timeout--; + } + + RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); + if (Timeout == 0 || RegisterD.Bits.Vrt == 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + See if all fields of a variable of EFI_TIME type is correct. + + @param Time The time to be checked. + + @retval EFI_INVALID_PARAMETER Some fields of Time are not correct. + @retval EFI_SUCCESS Time is a valid EFI_TIME variable. + +**/ +EFI_STATUS +RtcTimeFieldsValid ( + IN EFI_TIME *Time + ) +{ + if (Time->Year < PcdGet16 (PcdMinimalValidYear) || + Time->Year > PcdGet16 (PcdMaximalValidYear) || + Time->Month < 1 || + Time->Month > 12 || + (!DayValid (Time)) || + Time->Hour > 23 || + Time->Minute > 59 || + Time->Second > 59 || + Time->Nanosecond > 999999999 || + (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) || + ((Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT))) != 0)) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + See if field Day of an EFI_TIME is correct. + + @param Time Its Day field is to be checked. + + @retval TRUE Day field of Time is correct. + @retval FALSE Day field of Time is NOT correct. +**/ +BOOLEAN +DayValid ( + IN EFI_TIME *Time + ) +{ + // + // The validity of Time->Month field should be checked before + // + ASSERT (Time->Month >=1); + ASSERT (Time->Month <=12); + if (Time->Day < 1 || + Time->Day > mDayOfMonth[Time->Month - 1] || + (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28)) + ) { + return FALSE; + } + + return TRUE; +} + +/** + Check if it is a leap year. + + @param Time The time to be checked. + + @retval TRUE It is a leap year. + @retval FALSE It is NOT a leap year. +**/ +BOOLEAN +IsLeapYear ( + IN EFI_TIME *Time + ) +{ + if (Time->Year % 4 == 0) { + if (Time->Year % 100 == 0) { + if (Time->Year % 400 == 0) { + return TRUE; + } else { + return FALSE; + } + } else { + return TRUE; + } + } else { + return FALSE; + } +} + +/** + Converts time from EFI_TIME format defined by UEFI spec to RTC format. + + This function converts time from EFI_TIME format defined by UEFI spec to RTC format. + If data mode of RTC is BCD, then converts EFI_TIME to it. + If RTC is in 12-hour format, then converts EFI_TIME to it. + + @param Time On input, the time data read from UEFI to convert + On output, the time converted to RTC format + @param RegisterB Value of Register B of RTC, indicating data mode +**/ +VOID +ConvertEfiTimeToRtcTime ( + IN OUT EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB + ) +{ + BOOLEAN IsPM; + + IsPM = TRUE; + // + // Adjust hour field if RTC is in 12 hour mode + // + if (RegisterB.Bits.Mil == 0) { + if (Time->Hour < 12) { + IsPM = FALSE; + } + + if (Time->Hour >= 13) { + Time->Hour = (UINT8) (Time->Hour - 12); + } else if (Time->Hour == 0) { + Time->Hour = 12; + } + } + // + // Set the Time/Date values. + // + Time->Year = (UINT16) (Time->Year % 100); + + if (RegisterB.Bits.Dm == 0) { + Time->Year = DecimalToBcd8 ((UINT8) Time->Year); + Time->Month = DecimalToBcd8 (Time->Month); + Time->Day = DecimalToBcd8 (Time->Day); + Time->Hour = DecimalToBcd8 (Time->Hour); + Time->Minute = DecimalToBcd8 (Time->Minute); + Time->Second = DecimalToBcd8 (Time->Second); + } + // + // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field. + // + if (RegisterB.Bits.Mil == 0 && IsPM) { + Time->Hour = (UINT8) (Time->Hour | 0x80); + } +} + +/** + Compare the Hour, Minute and Second of the From time and the To time. + + Only compare H/M/S in EFI_TIME and ignore other fields here. + + @param From the first time + @param To the second time + + @return >0 The H/M/S of the From time is later than those of To time + @return ==0 The H/M/S of the From time is same as those of To time + @return <0 The H/M/S of the From time is earlier than those of To time +**/ +INTN +CompareHMS ( + IN EFI_TIME *From, + IN EFI_TIME *To + ) +{ + if ((From->Hour > To->Hour) || + ((From->Hour == To->Hour) && (From->Minute > To->Minute)) || + ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second > To->Second))) { + return 1; + } else if ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second == To->Second)) { + return 0; + } else { + return -1; + } +} + +/** + To check if second date is later than first date within 24 hours. + + @param From the first date + @param To the second date + + @retval TRUE From is previous to To within 24 hours. + @retval FALSE From is later, or it is previous to To more than 24 hours. +**/ +BOOLEAN +IsWithinOneDay ( + IN EFI_TIME *From, + IN EFI_TIME *To + ) +{ + BOOLEAN Adjacent; + + Adjacent = FALSE; + + // + // The validity of From->Month field should be checked before + // + ASSERT (From->Month >=1); + ASSERT (From->Month <=12); + + if (From->Year == To->Year) { + if (From->Month == To->Month) { + if ((From->Day + 1) == To->Day) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } else if (From->Day == To->Day) { + if ((CompareHMS(From, To) <= 0)) { + Adjacent = TRUE; + } + } + } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) { + if ((From->Month == 2) && !IsLeapYear(From)) { + if (From->Day == 28) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } + } else if (From->Day == mDayOfMonth[From->Month - 1]) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } + } + } else if (((From->Year + 1) == To->Year) && + (From->Month == 12) && + (From->Day == 31) && + (To->Month == 1) && + (To->Day == 1)) { + if ((CompareHMS(From, To) >= 0)) { + Adjacent = TRUE; + } + } + + return Adjacent; +} + +/** + Get the century RTC address from the ACPI FADT table. + + @return The century RTC address or 0 if not found. +**/ +UINT8 +GetCenturyRtcAddress ( + VOID + ) +{ + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt; + + Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) EfiLocateFirstAcpiTable ( + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE + ); + + if ((Fadt != NULL) && + (Fadt->Century > RTC_ADDRESS_REGISTER_D) && (Fadt->Century < 0x80) + ) { + return Fadt->Century; + } else { + return 0; + } +} + +/** + Notification function of ACPI Table change. + + This is a notification function registered on ACPI Table change event. + It saves the Century address stored in ACPI FADT table. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +PcRtcAcpiTableChangeCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_TIME Time; + UINT8 CenturyRtcAddress; + UINT8 Century; + + CenturyRtcAddress = GetCenturyRtcAddress (); + if ((CenturyRtcAddress != 0) && (mModuleGlobal.CenturyRtcAddress != CenturyRtcAddress)) { + mModuleGlobal.CenturyRtcAddress = CenturyRtcAddress; + Status = PcRtcGetTime (&Time, NULL, &mModuleGlobal); + if (!EFI_ERROR (Status)) { + Century = (UINT8) (Time.Year / 100); + Century = DecimalToBcd8 (Century); + DEBUG ((EFI_D_INFO, "PcRtc: Write 0x%x to CMOS location 0x%x\n", Century, mModuleGlobal.CenturyRtcAddress)); + RtcWrite (mModuleGlobal.CenturyRtcAddress, Century); + } + } +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h new file mode 100644 index 00000000..00cd82c6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h @@ -0,0 +1,374 @@ +/** @file + Header file for real time clock driver. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2017, AMD Inc. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _RTC_H_ +#define _RTC_H_ + + +#include <Uefi.h> + +#include <Guid/Acpi.h> + +#include <Protocol/RealTimeClock.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/PcdLib.h> +#include <Library/ReportStatusCodeLib.h> + +typedef struct { + EFI_LOCK RtcLock; + INT16 SavedTimeZone; + UINT8 Daylight; + UINT8 CenturyRtcAddress; +} PC_RTC_MODULE_GLOBALS; + +extern PC_RTC_MODULE_GLOBALS mModuleGlobal; + +// +// Dallas DS12C887 Real Time Clock +// +#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59 +#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59 +#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59 +#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59 +#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM +#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM +#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7 +#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31 +#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12 +#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99 +#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7] +#define RTC_ADDRESS_REGISTER_B 11 // R/W +#define RTC_ADDRESS_REGISTER_C 12 // RO +#define RTC_ADDRESS_REGISTER_D 13 // RO +// +// Date and time initial values. +// They are used if the RTC values are invalid during driver initialization +// +#define RTC_INIT_SECOND 0 +#define RTC_INIT_MINUTE 0 +#define RTC_INIT_HOUR 0 +#define RTC_INIT_DAY 1 +#define RTC_INIT_MONTH 1 + +#pragma pack(1) +// +// Register A +// +typedef struct { + UINT8 Rs : 4; // Rate Selection Bits + UINT8 Dv : 3; // Divisor + UINT8 Uip : 1; // Update in progress +} RTC_REGISTER_A_BITS; + +typedef union { + RTC_REGISTER_A_BITS Bits; + UINT8 Data; +} RTC_REGISTER_A; + +// +// Register B +// +typedef struct { + UINT8 Dse : 1; // 0 - Daylight saving disabled 1 - Daylight savings enabled + UINT8 Mil : 1; // 0 - 12 hour mode 1 - 24 hour mode + UINT8 Dm : 1; // 0 - BCD Format 1 - Binary Format + UINT8 Sqwe : 1; // 0 - Disable SQWE output 1 - Enable SQWE output + UINT8 Uie : 1; // 0 - Update INT disabled 1 - Update INT enabled + UINT8 Aie : 1; // 0 - Alarm INT disabled 1 - Alarm INT Enabled + UINT8 Pie : 1; // 0 - Periodic INT disabled 1 - Periodic INT Enabled + UINT8 Set : 1; // 0 - Normal operation. 1 - Updates inhibited +} RTC_REGISTER_B_BITS; + +typedef union { + RTC_REGISTER_B_BITS Bits; + UINT8 Data; +} RTC_REGISTER_B; + +// +// Register C +// +typedef struct { + UINT8 Reserved : 4; // Read as zero. Can not be written. + UINT8 Uf : 1; // Update End Interrupt Flag + UINT8 Af : 1; // Alarm Interrupt Flag + UINT8 Pf : 1; // Periodic Interrupt Flag + UINT8 Irqf : 1; // Interrupt Request Flag = PF & PIE | AF & AIE | UF & UIE +} RTC_REGISTER_C_BITS; + +typedef union { + RTC_REGISTER_C_BITS Bits; + UINT8 Data; +} RTC_REGISTER_C; + +// +// Register D +// +typedef struct { + UINT8 Reserved : 7; // Read as zero. Can not be written. + UINT8 Vrt : 1; // Valid RAM and Time +} RTC_REGISTER_D_BITS; + +typedef union { + RTC_REGISTER_D_BITS Bits; + UINT8 Data; +} RTC_REGISTER_D; + +#pragma pack() + +/** + Initialize RTC. + + @param Global For global use inside this module. + + @retval EFI_DEVICE_ERROR Initialization failed due to device error. + @retval EFI_SUCCESS Initialization successful. + +**/ +EFI_STATUS +PcRtcInit ( + IN PC_RTC_MODULE_GLOBALS *Global + ); + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + @param Global For global use inside this module. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +PcRtcSetTime ( + IN EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ); + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + @param Global For global use inside this module. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +PcRtcGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities, OPTIONAL + IN PC_RTC_MODULE_GLOBALS *Global + ); + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + If Enable is FALSE, then this parameter is optional, and may be NULL. + @param Global For global use inside this module. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. + If Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +PcRtcSetWakeupTime ( + IN BOOLEAN Enable, + IN EFI_TIME *Time, OPTIONAL + IN PC_RTC_MODULE_GLOBALS *Global + ); + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + @param Global For global use inside this module. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Enabled is NULL. + @retval EFI_INVALID_PARAMETER Pending is NULL. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +PcRtcGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time, + IN PC_RTC_MODULE_GLOBALS *Global + ); + +/** + The user Entry Point for PcRTC module. + + This is the entry point for PcRTC module. It installs the UEFI runtime service + including GetTime(),SetTime(),GetWakeupTime(),and SetWakeupTime(). + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializePcRtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + See if all fields of a variable of EFI_TIME type is correct. + + @param Time The time to be checked. + + @retval EFI_INVALID_PARAMETER Some fields of Time are not correct. + @retval EFI_SUCCESS Time is a valid EFI_TIME variable. + +**/ +EFI_STATUS +RtcTimeFieldsValid ( + IN EFI_TIME *Time + ); + +/** + Converts time from EFI_TIME format defined by UEFI spec to RTC format. + + This function converts time from EFI_TIME format defined by UEFI spec to RTC format. + If data mode of RTC is BCD, then converts EFI_TIME to it. + If RTC is in 12-hour format, then converts EFI_TIME to it. + + @param Time On input, the time data read from UEFI to convert + On output, the time converted to RTC format + @param RegisterB Value of Register B of RTC, indicating data mode +**/ +VOID +ConvertEfiTimeToRtcTime ( + IN OUT EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB + ); + + +/** + Converts time read from RTC to EFI_TIME format defined by UEFI spec. + + This function converts raw time data read from RTC to the EFI_TIME format + defined by UEFI spec. + If data mode of RTC is BCD, then converts it to decimal, + If RTC is in 12-hour format, then converts it to 24-hour format. + + @param Time On input, the time data read from RTC to convert + On output, the time converted to UEFI format + @param RegisterB Value of Register B of RTC, indicating data mode + and hour format. + + @retval EFI_INVALID_PARAMETER Parameters passed in are invalid. + @retval EFI_SUCCESS Convert RTC time to EFI time successfully. + +**/ +EFI_STATUS +ConvertRtcTimeToEfiTime ( + IN OUT EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB + ); + +/** + Wait for a period for the RTC to be ready. + + @param Timeout Tell how long it should take to wait. + + @retval EFI_DEVICE_ERROR RTC device error. + @retval EFI_SUCCESS RTC is updated and ready. +**/ +EFI_STATUS +RtcWaitToUpdate ( + UINTN Timeout + ); + +/** + See if field Day of an EFI_TIME is correct. + + @param Time Its Day field is to be checked. + + @retval TRUE Day field of Time is correct. + @retval FALSE Day field of Time is NOT correct. +**/ +BOOLEAN +DayValid ( + IN EFI_TIME *Time + ); + +/** + Check if it is a leapyear. + + @param Time The time to be checked. + + @retval TRUE It is a leapyear. + @retval FALSE It is NOT a leapyear. +**/ +BOOLEAN +IsLeapYear ( + IN EFI_TIME *Time + ); + +/** + Get the century RTC address from the ACPI FADT table. + + @return The century RTC address or 0 if not found. +**/ +UINT8 +GetCenturyRtcAddress ( + VOID + ); + +/** + Notification function of ACPI Table change. + + This is a notification function registered on ACPI Table change event. + It saves the Century address stored in ACPI FADT table. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +PcRtcAcpiTableChangeCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); +#endif diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.uni new file mode 100644 index 00000000..f3fe8343 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.uni @@ -0,0 +1,19 @@ +// /** @file
+// PcRtc driver to install EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL
+//
+// PcRtc driver to install EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL.
+//
+// This driver provides GetTime, SetTime, GetWakeupTime, SetWakeupTime services to Runtime Service Table.
+// It will install a tagging protocol with gEfiRealTimeClockArchProtocolGuid.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PcRtc driver to install EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver provides GetTime, SetTime, GetWakeupTime, SetWakeupTime services to Runtime Service Table. It will install a tagging protocol with gEfiRealTimeClockArchProtocolGuid."
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c new file mode 100644 index 00000000..f9b1606e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c @@ -0,0 +1,223 @@ +/** @file + Provides Set/Get time operations. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/DxeServicesTableLib.h> +#include "PcRtc.h" + +PC_RTC_MODULE_GLOBALS mModuleGlobal; + +EFI_HANDLE mHandle = NULL; + +STATIC EFI_EVENT mVirtualAddrChangeEvent; + +UINTN mRtcIndexRegister; +UINTN mRtcTargetRegister; + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time + clock device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +PcRtcEfiGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL + ) +{ + return PcRtcGetTime (Time, Capabilities, &mModuleGlobal); +} + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +PcRtcEfiSetTime ( + IN EFI_TIME *Time + ) +{ + return PcRtcSetTime (Time, &mModuleGlobal); +} + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Enabled is NULL. + @retval EFI_INVALID_PARAMETER Pending is NULL. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +PcRtcEfiGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + return PcRtcGetWakeupTime (Enabled, Pending, Time, &mModuleGlobal); +} + + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + If Enable is FALSE, then this parameter is optional, and may be NULL. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. + If Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +PcRtcEfiSetWakeupTime ( + IN BOOLEAN Enabled, + IN EFI_TIME *Time OPTIONAL + ) +{ + return PcRtcSetWakeupTime (Enabled, Time, &mModuleGlobal); +} + +/** + Fixup internal data so that EFI can be called in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // Only needed if you are going to support the OS calling RTC functions in + // virtual mode. You will need to call EfiConvertPointer (). To convert any + // stored physical addresses to virtual address. After the OS transitions to + // calling in virtual mode, all future runtime calls will be made in virtual + // mode. + EfiConvertPointer (0x0, (VOID**)&mRtcIndexRegister); + EfiConvertPointer (0x0, (VOID**)&mRtcTargetRegister); +} + +/** + The user Entry Point for PcRTC module. + + This is the entry point for PcRTC module. It installs the UEFI runtime service + including GetTime(),SetTime(),GetWakeupTime(),and SetWakeupTime(). + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializePcRtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_CALLBACK); + mModuleGlobal.CenturyRtcAddress = GetCenturyRtcAddress (); + + if (FeaturePcdGet (PcdRtcUseMmio)) { + mRtcIndexRegister = (UINTN)PcdGet64 (PcdRtcIndexRegister64); + mRtcTargetRegister = (UINTN)PcdGet64 (PcdRtcTargetRegister64); + } + + Status = PcRtcInit (&mModuleGlobal); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + PcRtcAcpiTableChangeCallback, + NULL, + &gEfiAcpi10TableGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + PcRtcAcpiTableChangeCallback, + NULL, + &gEfiAcpiTableGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + gRT->GetTime = PcRtcEfiGetTime; + gRT->SetTime = PcRtcEfiSetTime; + gRT->GetWakeupTime = PcRtcEfiGetWakeupTime; + gRT->SetWakeupTime = PcRtcEfiSetWakeupTime; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHandle, + &gEfiRealTimeClockArchProtocolGuid, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + if (FeaturePcdGet (PcdRtcUseMmio)) { + // Register for the virtual address change event + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + LibRtcVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddrChangeEvent + ); + ASSERT_EFI_ERROR (Status); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcExtra.uni b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcExtra.uni new file mode 100644 index 00000000..d9600435 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// PcRtc Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"PCAT Real Time Clock DXE Driver"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf new file mode 100644 index 00000000..76e87506 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf @@ -0,0 +1,88 @@ +## @file +# PcRtc driver to install EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL. +# +# This driver provides GetTime, SetTime, GetWakeupTime, SetWakeupTime services to Runtime Service Table. +# It will install a tagging protocol with gEfiRealTimeClockArchProtocolGuid. +# +# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2017, AMD Inc. All rights reserved.<BR> +# Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PcRtc + MODULE_UNI_FILE = PcRtc.uni + FILE_GUID = 378D7B65-8DA9-4773-B6E4-A47826A833E1 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializePcRtc + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + PcRtcEntry.c + PcRtc.c + PcRtc.h + +[Packages] + MdePkg/MdePkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiRuntimeLib + UefiBootServicesTableLib + UefiDriverEntryPoint + TimerLib + IoLib + BaseMemoryLib + UefiLib + DebugLib + BaseLib + PcdLib + ReportStatusCodeLib + +[Protocols] + gEfiRealTimeClockArchProtocolGuid ## PRODUCES + +[Guids] + ## SOMETIMES_CONSUMES ## Event + ## SOMETIMES_CONSUMES ## SystemTable + gEfiAcpi10TableGuid + + ## SOMETIMES_CONSUMES ## Event + ## SOMETIMES_CONSUMES ## SystemTable + gEfiAcpiTableGuid + + gEfiEventVirtualAddressChangeGuid + +[FeaturePcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio ## CONSUMES + +[FixedPcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterA ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterB ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterD ## CONSUMES + +[Pcd] + gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdMinimalValidYear ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdMaximalValidYear ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister64 ## CONSUMES + gPcAtChipsetPkgTokenSpaceGuid.PcdRtcTargetRegister64 ## CONSUMES + +[Depex] + gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + PcRtcExtra.uni |