From 6c628d447ce5c7e865a54b0bea12abd8ddc71a69 Mon Sep 17 00:00:00 2001 From: smh Date: Sat, 20 Feb 2016 10:56:46 +0000 Subject: MFC r272785: Null terminate boot config buffer PR: 207070 Approved by: re (gjb) Sponsored by: Multiplay --- sys/boot/i386/gptboot/gptboot.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sys/boot') diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c index 5316706..a1f46eb 100644 --- a/sys/boot/i386/gptboot/gptboot.c +++ b/sys/boot/i386/gptboot/gptboot.c @@ -132,6 +132,7 @@ int main(void) { char cmd[512], cmdtmp[512]; + ssize_t sz; int autoboot, dskupdated; ufs_ino_t ino; @@ -160,9 +161,10 @@ main(void) for (;;) { *kname = '\0'; if ((ino = lookup(PATH_CONFIG)) || - (ino = lookup(PATH_DOTCONFIG))) - fsread(ino, cmd, sizeof(cmd)); - + (ino = lookup(PATH_DOTCONFIG))) { + sz = fsread(ino, cmd, sizeof(cmd) - 1); + cmd[(sz < 0) ? 0 : sz] = '\0'; + } if (*cmd != '\0') { memcpy(cmdtmp, cmd, sizeof(cmdtmp)); if (parse(cmdtmp, &dskupdated)) -- cgit v1.1 From 4112d41bd632ff2eb376f20f94cfed638b0426bf Mon Sep 17 00:00:00 2001 From: marius Date: Mon, 22 Feb 2016 00:49:35 +0000 Subject: MFC: r287299 [1] Add a gop command to help diagnose VT efifb problems. The gop command has the following sub-commands: list - list all possible modes (paged) get - return the current mode set - set the current mode to MFC: r287317, r287422, r287475, r287489, r287538 [2] Add support for the UGA draw protocol. This includes adding a command called 'uga' to show whether UGA is implemented by the firmware and what the settings are. It also includes filling the efi_fb structure from the UGA information when GOP isn't implemented by the firmware. PR: 207313 [1], 202730 [2] Approved by: re (gjb) --- sys/boot/efi/include/efipciio.h | 557 +++++++++++++++++++++++++++ sys/boot/efi/include/efiuga.h | 168 ++++++++ sys/boot/efi/loader/arch/amd64/framebuffer.c | 525 +++++++++++++++++++++++-- 3 files changed, 1227 insertions(+), 23 deletions(-) create mode 100644 sys/boot/efi/include/efipciio.h create mode 100644 sys/boot/efi/include/efiuga.h (limited to 'sys/boot') diff --git a/sys/boot/efi/include/efipciio.h b/sys/boot/efi/include/efipciio.h new file mode 100644 index 0000000..b00d6ec --- /dev/null +++ b/sys/boot/efi/include/efipciio.h @@ -0,0 +1,557 @@ +/* $FreeBSD$ */ +/** @file + EFI PCI I/O Protocol provides the basic Memory, I/O, PCI configuration, + and DMA interfaces that a driver uses to access its PCI controller. + + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PCI_IO_H__ +#define __PCI_IO_H__ + +/// +/// Global ID for the PCI I/O Protocol +/// +#define EFI_PCI_IO_PROTOCOL_GUID \ + { 0x4cf5b200, 0x68b8, 0x4ca5, {0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a} } + +typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_WIDTH +/// ******************************************************* +/// +typedef enum { + EfiPciIoWidthUint8 = 0, + EfiPciIoWidthUint16, + EfiPciIoWidthUint32, + EfiPciIoWidthUint64, + EfiPciIoWidthFifoUint8, + EfiPciIoWidthFifoUint16, + EfiPciIoWidthFifoUint32, + EfiPciIoWidthFifoUint64, + EfiPciIoWidthFillUint8, + EfiPciIoWidthFillUint16, + EfiPciIoWidthFillUint32, + EfiPciIoWidthFillUint64, + EfiPciIoWidthMaximum +} EFI_PCI_IO_PROTOCOL_WIDTH; + +// +// Complete PCI address generater +// +#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff ///< Special BAR that passes a memory or I/O cycle through unchanged +#define EFI_PCI_IO_ATTRIBUTE_MASK 0x077f ///< All the following I/O and Memory cycles +#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 ///< I/O cycles 0x0000-0x00FF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 ///< I/O cycles 0x0100-0x03FF or greater (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 ///< MEM cycles 0xA0000-0xBFFFF (24 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 ///< I/O cycles 0x1F0-0x1F7, 0x3F6, 0x3F7 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 ///< I/O cycles 0x170-0x177, 0x376, 0x377 (10 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 ///< Map a memory range so writes are combined +#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 ///< Enable the I/O decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 ///< Enable the Memory decode bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 ///< Enable the DMA bit in the PCI Config Header +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 ///< Map a memory range so all r/w accesses are cached +#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 ///< Clear for an add-in PCI Device +#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 ///< Clear for a physical PCI Option ROM accessed through ROM BAR +#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 ///< Clear for PCI controllers that can not genrate a DAC +#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 ///< I/O cycles 0x0100-0x03FF or greater (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 ///< I/O cycles 0x3C6, 0x3C8, 0x3C9 (16 bit decode) +#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 ///< I/O cycles 0x3B0-0x3BB and 0x3C0-0x3DF (16 bit decode) + +#define EFI_PCI_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) +#define EFI_VGA_DEVICE_ENABLE (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_IO) + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_OPERATION +/// ******************************************************* +/// +typedef enum { + /// + /// A read operation from system memory by a bus master. + /// + EfiPciIoOperationBusMasterRead, + /// + /// A write operation from system memory by a bus master. + /// + EfiPciIoOperationBusMasterWrite, + /// + /// Provides both read and write access to system memory by both the processor and a + /// bus master. The buffer is coherent from both the processor's and the bus master's point of view. + /// + EfiPciIoOperationBusMasterCommonBuffer, + EfiPciIoOperationMaximum +} EFI_PCI_IO_PROTOCOL_OPERATION; + +/// +/// ******************************************************* +/// EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION +/// ******************************************************* +/// +typedef enum { + /// + /// Retrieve the PCI controller's current attributes, and return them in Result. + /// + EfiPciIoAttributeOperationGet, + /// + /// Set the PCI controller's current attributes to Attributes. + /// + EfiPciIoAttributeOperationSet, + /// + /// Enable the attributes specified by the bits that are set in Attributes for this PCI controller. + /// + EfiPciIoAttributeOperationEnable, + /// + /// Disable the attributes specified by the bits that are set in Attributes for this PCI controller. + /// + EfiPciIoAttributeOperationDisable, + /// + /// Retrieve the PCI controller's supported attributes, and return them in Result. + /// + EfiPciIoAttributeOperationSupported, + EfiPciIoAttributeOperationMaximum +} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; + +/** + Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is + satisfied or after a defined duration. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param Offset The offset within the selected BAR to start the memory operation. + @param Mask Mask used for the polling criteria. + @param Value The comparison value used for the polling exit criteria. + @param Delay The number of 100 ns units to poll. + @param Result Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS The last data returned from the access matched the poll exit criteria. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED Offset is not valid for the BarIndex of this PCI controller. + @retval EFI_TIMEOUT Delay expired before a match occurred. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_POLL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +/** + Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory or I/O operations. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for the memory or I/O operation to perform. + @param Offset The offset within the selected BAR to start the memory or I/O operation. + @param Count The number of memory or I/O operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI BAR specified by BarIndex. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_IO_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + /// + /// Read PCI controller registers in the PCI memory or I/O space. + /// + EFI_PCI_IO_PROTOCOL_IO_MEM Read; + /// + /// Write PCI controller registers in the PCI memory or I/O space. + /// + EFI_PCI_IO_PROTOCOL_IO_MEM Write; +} EFI_PCI_IO_PROTOCOL_ACCESS; + +/** + Enable a PCI driver to access PCI controller registers in PCI configuration space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param Offset The offset within the PCI configuration space for the PCI controller. + @param Count The number of PCI configuration operations to perform. + @param Buffer For read operations, the destination buffer to store the results. For write + operations, the source buffer to write data from. + + + @retval EFI_SUCCESS The data was read from or written to the PCI controller. + @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not + valid for the PCI configuration header of the PCI controller. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_CONFIG)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +typedef struct { + /// + /// Read PCI controller registers in PCI configuration space. + /// + EFI_PCI_IO_PROTOCOL_CONFIG Read; + /// + /// Write PCI controller registers in PCI configuration space. + /// + EFI_PCI_IO_PROTOCOL_CONFIG Write; +} EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS; + +/** + Enables a PCI driver to copy one region of PCI memory space to another region of PCI + memory space. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Width Signifies the width of the memory operations. + @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param DestOffset The destination offset within the BAR specified by DestBarIndex to + start the memory writes for the copy operation. + @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the + base address for the memory operation to perform. + @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start + the memory reads for the copy operation. + @param Count The number of memory operations to perform. Bytes moved is Width + size * Count, starting at DestOffset and SrcOffset. + + @retval EFI_SUCCESS The data was copied from one memory region to another memory region. + @retval EFI_UNSUPPORTED DestBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED SrcBarIndex not valid for this PCI controller. + @retval EFI_UNSUPPORTED The address range specified by DestOffset, Width, and Count + is not valid for the PCI BAR specified by DestBarIndex. + @retval EFI_UNSUPPORTED The address range specified by SrcOffset, Width, and Count is + not valid for the PCI BAR specified by SrcBarIndex. + @retval EFI_INVALID_PARAMETER Width is invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_COPY_MEM)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ); + +/** + Provides the PCI controller-specific addresses needed to access system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master PCI controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_MAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_UNMAP)( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer + mapping. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + @param Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The PCI posted write transactions were flushed from the PCI host + bridge to system memory. + @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed from the PCI + host bridge due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_FLUSH)( + IN EFI_PCI_IO_PROTOCOL *This + ); + +/** + Retrieves this PCI controller's current PCI bus number, device number, and function number. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param SegmentNumber The PCI controller's current PCI segment number. + @param BusNumber The PCI controller's current PCI bus number. + @param DeviceNumber The PCI controller's current PCI device number. + @param FunctionNumber The PCI controller's current PCI function number. + + @retval EFI_SUCCESS The PCI controller location was returned. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION)( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ); + +/** + Performs an operation on the attributes that this PCI controller supports. The operations include + getting the set of supported attributes, retrieving the current attributes, setting the current + attributes, enabling attributes, and disabling attributes. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Operation The operation to perform on the attributes for this PCI controller. + @param Attributes The mask of attributes that are used for Set, Enable, and Disable + operations. + @param Result A pointer to the result mask of attributes that are returned for the Get + and Supported operations. + + @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED one or more of the bits set in + Attributes are not supported by this PCI controller or one of + its parent bridges when Operation is Set, Enable or Disable. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ); + +/** + Gets the attributes that this PCI controller supports setting on a BAR using + SetBarAttributes(), and retrieves the list of resource descriptors for a BAR. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Supports A pointer to the mask of attributes that this PCI controller supports + setting for this BAR with SetBarAttributes(). + @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current + configuration of this BAR of the PCI controller. + + @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI + controller supports are returned in Supports. If Resources + is not NULL, then the ACPI 2.0 resource descriptors that the PCI + controller is currently using are returned in Resources. + @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate + Resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ); + +/** + Sets the attributes for a range of a BAR on a PCI controller. + + @param This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param Attributes The mask of attributes to set for the resource range specified by + BarIndex, Offset, and Length. + @param BarIndex The BAR index of the standard PCI Configuration header to use as the + base address for resource range. The legal range for this field is 0..5. + @param Offset A pointer to the BAR relative base address of the resource range to be + modified by the attributes specified by Attributes. + @param Length A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS The set of attributes specified by Attributes for the resource + range specified by BarIndex, Offset, and Length were + set on the PCI controller, and the actual resource range is returned + in Offset and Length. + @retval EFI_INVALID_PARAMETER Offset or Length is NULL. + @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the attributes on the + resource range specified by BarIndex, Offset, and + Length. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES)( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ); + +/// +/// The EFI_PCI_IO_PROTOCOL provides the basic Memory, I/O, PCI configuration, +/// and DMA interfaces used to abstract accesses to PCI controllers. +/// There is one EFI_PCI_IO_PROTOCOL instance for each PCI controller on a PCI bus. +/// A device driver that wishes to manage a PCI controller in a system will have to +/// retrieve the EFI_PCI_IO_PROTOCOL instance that is associated with the PCI controller. +/// +struct _EFI_PCI_IO_PROTOCOL { + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem; + EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo; + EFI_PCI_IO_PROTOCOL_ACCESS Mem; + EFI_PCI_IO_PROTOCOL_ACCESS Io; + EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci; + EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_PCI_IO_PROTOCOL_MAP Map; + EFI_PCI_IO_PROTOCOL_UNMAP Unmap; + EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_PCI_IO_PROTOCOL_FLUSH Flush; + EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation; + EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes; + EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes; + EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes; + + /// + /// The size, in bytes, of the ROM image. + /// + UINT64 RomSize; + + /// + /// A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible + /// for allocating memory for the ROM image, and copying the contents of the ROM to memory. + /// The contents of this buffer are either from the PCI option ROM that can be accessed + /// through the ROM BAR of the PCI controller, or it is from a platform-specific location. + /// The Attributes() function can be used to determine from which of these two sources + /// the RomImage buffer was initialized. + /// + VOID *RomImage; +}; + +extern EFI_GUID gEfiPciIoProtocolGuid; + +#endif diff --git a/sys/boot/efi/include/efiuga.h b/sys/boot/efi/include/efiuga.h new file mode 100644 index 0000000..6dfaf50 --- /dev/null +++ b/sys/boot/efi/include/efiuga.h @@ -0,0 +1,168 @@ +/* $FreeBSD$ */ +/** @file + UGA Draw protocol from the EFI 1.1 specification. + + Abstraction of a very simple graphics device. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at: + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + File name: UgaDraw.h + +**/ + +#ifndef __UGA_DRAW_H__ +#define __UGA_DRAW_H__ + +#define EFI_UGA_DRAW_PROTOCOL_GUID \ + { 0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39} } + +typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL; + +/** + Return the current video mode information. + + @param This Protocol instance pointer. + @param HorizontalResolution Current video horizontal resolution in pixels + @param VerticalResolution Current video vertical resolution in pixels + @param ColorDepth Current video color depth in bits per pixel + @param RefreshRate Current video refresh rate in Hz. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + @retval EFI_INVALID_PARAMETER One of the input args was NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) ( + IN EFI_UGA_DRAW_PROTOCOL *This, + OUT UINT32 *HorizontalResolution, + OUT UINT32 *VerticalResolution, + OUT UINT32 *ColorDepth, + OUT UINT32 *RefreshRate + ) +; + +/** + Return the current video mode information. + + @param This Protocol instance pointer. + @param HorizontalResolution Current video horizontal resolution in pixels + @param VerticalResolution Current video vertical resolution in pixels + @param ColorDepth Current video color depth in bits per pixel + @param RefreshRate Current video refresh rate in Hz. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_SET_MODE) ( + IN EFI_UGA_DRAW_PROTOCOL *This, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +; + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} EFI_UGA_PIXEL; + +typedef union { + EFI_UGA_PIXEL Pixel; + UINT32 Raw; +} EFI_UGA_PIXEL_UNION; + +typedef enum { + EfiUgaVideoFill, + EfiUgaVideoToBltBuffer, + EfiUgaBltBufferToVideo, + EfiUgaVideoToVideo, + EfiUgaBltMax +} EFI_UGA_BLT_OPERATION; + +/** + Type specifying a pointer to a function to perform an UGA Blt operation. + + The following table defines actions for BltOperations: + + EfiUgaVideoFill - Write data from the BltBuffer pixel (SourceX, SourceY) + directly to every pixel of the video display rectangle + (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + Only one pixel will be used from the BltBuffer. Delta is NOT used. + + EfiUgaVideoToBltBuffer - Read data from the video display rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in + the BltBuffer rectangle (DestinationX, DestinationY ) + (DestinationX + Width, DestinationY + Height). If DestinationX or + DestinationY is not zero then Delta must be set to the length in bytes + of a row in the BltBuffer. + + EfiUgaBltBufferToVideo - Write data from the BltBuffer rectangle + (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the + video display rectangle (DestinationX, DestinationY) + (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is + not zero then Delta must be set to the length in bytes of a row in the + BltBuffer. + + EfiUgaVideoToVideo - Copy from the video display rectangle (SourceX, SourceY) + (SourceX + Width, SourceY + Height) .to the video display rectangle + (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + The BltBuffer and Delta are not used in this mode. + + + @param[in] This - Protocol instance pointer. + @param[in] BltBuffer - Buffer containing data to blit into video buffer. This + buffer has a size of Width*Height*sizeof(EFI_UGA_PIXEL) + @param[in] BltOperation - Operation to perform on BlitBuffer and video memory + @param[in] SourceX - X coordinate of source for the BltBuffer. + @param[in] SourceY - Y coordinate of source for the BltBuffer. + @param[in] DestinationX - X coordinate of destination for the BltBuffer. + @param[in] DestinationY - Y coordinate of destination for the BltBuffer. + @param[in] Width - Width of rectangle in BltBuffer in pixels. + @param[in] Height - Hight of rectangle in BltBuffer in pixels. + @param[in] Delta - OPTIONAL + + @retval EFI_SUCCESS - The Blt operation completed. + @retval EFI_INVALID_PARAMETER - BltOperation is not valid. + @retval EFI_DEVICE_ERROR - A hardware error occured writting to the video buffer. + +--*/ +typedef +EFI_STATUS +(EFIAPI *EFI_UGA_DRAW_PROTOCOL_BLT) ( + IN EFI_UGA_DRAW_PROTOCOL * This, + IN EFI_UGA_PIXEL * BltBuffer, OPTIONAL + IN EFI_UGA_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ); + +struct _EFI_UGA_DRAW_PROTOCOL { + EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode; + EFI_UGA_DRAW_PROTOCOL_SET_MODE SetMode; + EFI_UGA_DRAW_PROTOCOL_BLT Blt; +}; + +extern EFI_GUID gEfiUgaDrawProtocolGuid; + +#endif diff --git a/sys/boot/efi/loader/arch/amd64/framebuffer.c b/sys/boot/efi/loader/arch/amd64/framebuffer.c index 2adb8b5..c7ced1b 100644 --- a/sys/boot/efi/loader/arch/amd64/framebuffer.c +++ b/sys/boot/efi/loader/arch/amd64/framebuffer.c @@ -29,38 +29,45 @@ #include __FBSDID("$FreeBSD$"); +#include +#include #include #include #include +#include +#include #include #include "framebuffer.h" static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID; +static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID; -int -efi_find_framebuffer(struct efi_fb *efifb) +static u_int +efifb_color_depth(struct efi_fb *efifb) { - EFI_GRAPHICS_OUTPUT *gop; - EFI_STATUS status; - EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode; - EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; + uint32_t mask; + u_int depth; - status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); - if (EFI_ERROR(status)) - return (1); - - mode = gop->Mode; - info = gop->Mode->Info; + mask = efifb->fb_mask_red | efifb->fb_mask_green | + efifb->fb_mask_blue | efifb->fb_mask_reserved; + if (mask == 0) + return (0); + for (depth = 1; mask != 1; depth++) + mask >>= 1; + return (depth); +} - efifb->fb_addr = mode->FrameBufferBase; - efifb->fb_size = mode->FrameBufferSize; - efifb->fb_height = info->VerticalResolution; - efifb->fb_width = info->HorizontalResolution; - efifb->fb_stride = info->PixelsPerScanLine; +static int +efifb_mask_from_pixfmt(struct efi_fb *efifb, EFI_GRAPHICS_PIXEL_FORMAT pixfmt, + EFI_PIXEL_BITMASK *pixinfo) +{ + int result; - switch (info->PixelFormat) { + result = 0; + switch (pixfmt) { case PixelRedGreenBlueReserved8BitPerColor: efifb->fb_mask_red = 0x000000ff; efifb->fb_mask_green = 0x0000ff00; @@ -74,14 +81,486 @@ efi_find_framebuffer(struct efi_fb *efifb) efifb->fb_mask_reserved = 0xff000000; break; case PixelBitMask: - efifb->fb_mask_red = info->PixelInformation.RedMask; - efifb->fb_mask_green = info->PixelInformation.GreenMask; - efifb->fb_mask_blue = info->PixelInformation.BlueMask; - efifb->fb_mask_reserved = - info->PixelInformation.ReservedMask; + efifb->fb_mask_red = pixinfo->RedMask; + efifb->fb_mask_green = pixinfo->GreenMask; + efifb->fb_mask_blue = pixinfo->BlueMask; + efifb->fb_mask_reserved = pixinfo->ReservedMask; break; default: + result = 1; + break; + } + return (result); +} + +static int +efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode, + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info) +{ + int result; + + efifb->fb_addr = mode->FrameBufferBase; + efifb->fb_size = mode->FrameBufferSize; + efifb->fb_height = info->VerticalResolution; + efifb->fb_width = info->HorizontalResolution; + efifb->fb_stride = info->PixelsPerScanLine; + result = efifb_mask_from_pixfmt(efifb, info->PixelFormat, + &info->PixelInformation); + return (result); +} + +static ssize_t +efifb_uga_find_pixel(EFI_UGA_DRAW_PROTOCOL *uga, u_int line, + EFI_PCI_IO_PROTOCOL *pciio, uint64_t addr, uint64_t size) +{ + EFI_UGA_PIXEL pix0, pix1; + uint8_t *data1, *data2; + size_t count, maxcount = 1024; + ssize_t ofs; + EFI_STATUS status; + u_int idx; + + status = uga->Blt(uga, &pix0, EfiUgaVideoToBltBuffer, + 0, line, 0, 0, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (video->buffer)"); + return (-1); + } + pix1.Red = ~pix0.Red; + pix1.Green = ~pix0.Green; + pix1.Blue = ~pix0.Blue; + pix1.Reserved = 0; + + data1 = calloc(maxcount, 2); + if (data1 == NULL) { + printf("Unable to allocate memory"); + return (-1); + } + data2 = data1 + maxcount; + + ofs = 0; + while (size > 0) { + count = min(size, maxcount); + + status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, + data1); + if (EFI_ERROR(status)) { + printf("Error reading frame buffer (before)"); + goto fail; + } + status = uga->Blt(uga, &pix1, EfiUgaBltBufferToVideo, + 0, 0, 0, line, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (modify)"); + goto fail; + } + status = pciio->Mem.Read(pciio, EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, addr + ofs, count >> 2, + data2); + if (EFI_ERROR(status)) { + printf("Error reading frame buffer (after)"); + goto fail; + } + status = uga->Blt(uga, &pix0, EfiUgaBltBufferToVideo, + 0, 0, 0, line, 1, 1, 0); + if (EFI_ERROR(status)) { + printf("UGA BLT operation failed (restore)"); + goto fail; + } + for (idx = 0; idx < count; idx++) { + if (data1[idx] != data2[idx]) { + free(data1); + return (ofs + (idx & ~3)); + } + } + ofs += count; + size -= count; + } + printf("No change detected in frame buffer"); + + fail: + printf(" -- error %lu\n", status & ~EFI_ERROR_MASK); + free(data1); + return (-1); +} + +static EFI_PCI_IO_PROTOCOL * +efifb_uga_get_pciio(void) +{ + EFI_PCI_IO_PROTOCOL *pciio; + EFI_HANDLE *buf, *hp; + EFI_STATUS status; + UINTN bufsz; + + /* Get all handles that support the UGA protocol. */ + bufsz = 0; + status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) + return (NULL); + buf = malloc(bufsz); + status = BS->LocateHandle(ByProtocol, &uga_guid, NULL, &bufsz, buf); + if (status != EFI_SUCCESS) { + free(buf); + return (NULL); + } + bufsz /= sizeof(EFI_HANDLE); + + /* Get the PCI I/O interface of the first handle that supports it. */ + pciio = NULL; + for (hp = buf; hp < buf + bufsz; hp++) { + status = BS->HandleProtocol(*hp, &pciio_guid, (void **)&pciio); + if (status == EFI_SUCCESS) { + free(buf); + return (pciio); + } + } + free(buf); + return (NULL); +} + +static EFI_STATUS +efifb_uga_locate_framebuffer(EFI_PCI_IO_PROTOCOL *pciio, uint64_t *addrp, + uint64_t *sizep) +{ + uint8_t *resattr; + uint64_t addr, size; + EFI_STATUS status; + u_int bar; + + if (pciio == NULL) + return (EFI_DEVICE_ERROR); + + /* Attempt to get the frame buffer address (imprecise). */ + *addrp = 0; + *sizep = 0; + for (bar = 0; bar < 6; bar++) { + status = pciio->GetBarAttributes(pciio, bar, NULL, + (void **)&resattr); + if (status != EFI_SUCCESS) + continue; + /* XXX magic offsets and constants. */ + if (resattr[0] == 0x87 && resattr[3] == 0) { + /* 32-bit address space descriptor (MEMIO) */ + addr = le32dec(resattr + 10); + size = le32dec(resattr + 22); + } else if (resattr[0] == 0x8a && resattr[3] == 0) { + /* 64-bit address space descriptor (MEMIO) */ + addr = le64dec(resattr + 14); + size = le64dec(resattr + 38); + } else { + addr = 0; + size = 0; + } + BS->FreePool(resattr); + if (addr == 0 || size == 0) + continue; + + /* We assume the largest BAR is the frame buffer. */ + if (size > *sizep) { + *addrp = addr; + *sizep = size; + } + } + return ((*addrp == 0 || *sizep == 0) ? EFI_DEVICE_ERROR : 0); +} + +static int +efifb_from_uga(struct efi_fb *efifb, EFI_UGA_DRAW_PROTOCOL *uga) +{ + EFI_PCI_IO_PROTOCOL *pciio; + char *ev, *p; + EFI_STATUS status; + ssize_t offset; + uint64_t fbaddr; + uint32_t horiz, vert, stride; + uint32_t np, depth, refresh; + + status = uga->GetMode(uga, &horiz, &vert, &depth, &refresh); + if (EFI_ERROR(status)) return (1); + efifb->fb_height = vert; + efifb->fb_width = horiz; + /* Paranoia... */ + if (efifb->fb_height == 0 || efifb->fb_width == 0) + return (1); + + /* The color masks are fixed AFAICT. */ + efifb_mask_from_pixfmt(efifb, PixelBlueGreenRedReserved8BitPerColor, + NULL); + + /* pciio can be NULL on return! */ + pciio = efifb_uga_get_pciio(); + + /* Try to find the frame buffer. */ + status = efifb_uga_locate_framebuffer(pciio, &efifb->fb_addr, + &efifb->fb_size); + if (EFI_ERROR(status)) { + efifb->fb_addr = 0; + efifb->fb_size = 0; + } + + /* + * There's no reliable way to detect the frame buffer or the + * offset within the frame buffer of the visible region, nor + * the stride. Our only option is to look at the system and + * fill in the blanks based on that. Luckily, UGA was mostly + * only used on Apple hardware. + */ + offset = -1; + ev = getenv("smbios.system.maker"); + if (ev != NULL && !strcmp(ev, "Apple Inc.")) { + ev = getenv("smbios.system.product"); + if (ev != NULL && !strcmp(ev, "iMac7,1")) { + /* These are the expected values we should have. */ + horiz = 1680; + vert = 1050; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x10000; + stride = 1728; + } else if (ev != NULL && !strcmp(ev, "MacBook3,1")) { + /* These are the expected values we should have. */ + horiz = 1280; + vert = 800; + fbaddr = 0xc0000000; + /* These are the missing bits. */ + offset = 0x0; + stride = 2048; + } + } + + /* + * If this is hardware we know, make sure that it looks familiar + * before we accept our hardcoded values. + */ + if (offset >= 0 && efifb->fb_width == horiz && + efifb->fb_height == vert && efifb->fb_addr == fbaddr) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; + efifb->fb_stride = stride; + return (0); + } else if (offset >= 0) { + printf("Hardware make/model known, but graphics not " + "as expected.\n"); + printf("Console may not work!\n"); + } + + /* + * The stride is equal or larger to the width. Often it's the + * next larger power of two. We'll start with that... + */ + efifb->fb_stride = efifb->fb_width; + do { + np = efifb->fb_stride & (efifb->fb_stride - 1); + if (np) { + efifb->fb_stride |= (np - 1); + efifb->fb_stride++; + } + } while (np); + + ev = getenv("hw.efifb.address"); + if (ev == NULL) { + if (efifb->fb_addr == 0) { + printf("Please set hw.efifb.address and " + "hw.efifb.stride.\n"); + return (1); + } + + /* + * The visible part of the frame buffer may not start at + * offset 0, so try to detect it. Note that we may not + * always be able to read from the frame buffer, which + * means that we may not be able to detect anything. In + * that case, we would take a long time scanning for a + * pixel change in the frame buffer, which would have it + * appear that we're hanging, so we limit the scan to + * 1/256th of the frame buffer. This number is mostly + * based on PR 202730 and the fact that on a MacBoook, + * where we can't read from the frame buffer the offset + * of the visible region is 0. In short: we want to scan + * enough to handle all adapters that have an offset + * larger than 0 and we want to scan as little as we can + * to not appear to hang when we can't read from the + * frame buffer. + */ + offset = efifb_uga_find_pixel(uga, 0, pciio, efifb->fb_addr, + efifb->fb_size >> 8); + if (offset == -1) { + printf("Unable to reliably detect frame buffer.\n"); + } else if (offset > 0) { + efifb->fb_addr += offset; + efifb->fb_size -= offset; + } + } else { + offset = 0; + efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; + efifb->fb_addr = strtoul(ev, &p, 0); + if (*p != '\0') + return (1); + } + + ev = getenv("hw.efifb.stride"); + if (ev == NULL) { + if (pciio != NULL && offset != -1) { + /* Determine the stride. */ + offset = efifb_uga_find_pixel(uga, 1, pciio, + efifb->fb_addr, horiz * 8); + if (offset != -1) + efifb->fb_stride = offset >> 2; + } else { + printf("Unable to reliably detect the stride.\n"); + } + } else { + efifb->fb_stride = strtoul(ev, &p, 0); + if (*p != '\0') + return (1); } + + /* + * We finalized on the stride, so recalculate the size of the + * frame buffer. + */ + efifb->fb_size = efifb->fb_height * efifb->fb_stride * 4; return (0); } + +int +efi_find_framebuffer(struct efi_fb *efifb) +{ + EFI_GRAPHICS_OUTPUT *gop; + EFI_UGA_DRAW_PROTOCOL *uga; + EFI_STATUS status; + + status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); + if (status == EFI_SUCCESS) + return (efifb_from_gop(efifb, gop->Mode, gop->Mode->Info)); + + status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga); + if (status == EFI_SUCCESS) + return (efifb_from_uga(efifb, uga)); + + return (1); +} + +static void +print_efifb(int mode, struct efi_fb *efifb, int verbose) +{ + u_int depth; + + if (mode >= 0) + printf("mode %d: ", mode); + depth = efifb_color_depth(efifb); + printf("%ux%ux%u, stride=%u", efifb->fb_width, efifb->fb_height, + depth, efifb->fb_stride); + if (verbose) { + printf("\n frame buffer: address=%jx, size=%jx", + (uintmax_t)efifb->fb_addr, (uintmax_t)efifb->fb_size); + printf("\n color mask: R=%08x, G=%08x, B=%08x\n", + efifb->fb_mask_red, efifb->fb_mask_green, + efifb->fb_mask_blue); + } +} + +COMMAND_SET(gop, "gop", "graphics output protocol", command_gop); + +static int +command_gop(int argc, char *argv[]) +{ + struct efi_fb efifb; + EFI_GRAPHICS_OUTPUT *gop; + EFI_STATUS status; + u_int mode; + + status = BS->LocateProtocol(&gop_guid, NULL, (VOID **)&gop); + if (EFI_ERROR(status)) { + sprintf(command_errbuf, "%s: Graphics Output Protocol not " + "present (error=%lu)", argv[0], status & ~EFI_ERROR_MASK); + return (CMD_ERROR); + } + + if (argc < 2) + goto usage; + + if (!strcmp(argv[1], "set")) { + char *cp; + + if (argc != 3) + goto usage; + mode = strtol(argv[2], &cp, 0); + if (cp[0] != '\0') { + sprintf(command_errbuf, "mode is an integer"); + return (CMD_ERROR); + } + status = gop->SetMode(gop, mode); + if (EFI_ERROR(status)) { + sprintf(command_errbuf, "%s: Unable to set mode to " + "%u (error=%lu)", argv[0], mode, + status & ~EFI_ERROR_MASK); + return (CMD_ERROR); + } + } else if (!strcmp(argv[1], "get")) { + if (argc != 2) + goto usage; + efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info); + print_efifb(gop->Mode->Mode, &efifb, 1); + printf("\n"); + } else if (!strcmp(argv[1], "list")) { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; + UINTN infosz; + + if (argc != 2) + goto usage; + pager_open(); + for (mode = 0; mode < gop->Mode->MaxMode; mode++) { + status = gop->QueryMode(gop, mode, &infosz, &info); + if (EFI_ERROR(status)) + continue; + efifb_from_gop(&efifb, gop->Mode, info); + print_efifb(mode, &efifb, 0); + if (pager_output("\n")) + break; + } + pager_close(); + } + return (CMD_OK); + + usage: + sprintf(command_errbuf, "usage: %s [list | get | set ]", + argv[0]); + return (CMD_ERROR); +} + +COMMAND_SET(uga, "uga", "universal graphics adapter", command_uga); + +static int +command_uga(int argc, char *argv[]) +{ + struct efi_fb efifb; + EFI_UGA_DRAW_PROTOCOL *uga; + EFI_STATUS status; + + status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga); + if (EFI_ERROR(status)) { + sprintf(command_errbuf, "%s: UGA Protocol not present " + "(error=%lu)", argv[0], status & ~EFI_ERROR_MASK); + return (CMD_ERROR); + } + + if (argc != 1) + goto usage; + + if (efifb_from_uga(&efifb, uga) != CMD_OK) { + sprintf(command_errbuf, "%s: Unable to get UGA information", + argv[0]); + return (CMD_ERROR); + } + + print_efifb(-1, &efifb, 1); + printf("\n"); + return (CMD_OK); + + usage: + sprintf(command_errbuf, "usage: %s", argv[0]); + return (CMD_ERROR); +} -- cgit v1.1