/*-
* Copyright (c) 2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Benno Rice under sponsorship from
* the FreeBSD Foundation.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
__FBSDID("$FreeBSD$");
#include <bootstrap.h>
#include <stand.h>
#include <efi.h>
#include <efilib.h>
#include <efiuga.h>
#include <efipciio.h>
#include <machine/metadata.h>
#include "framebuffer.h"
static u_int
{
if (mask == 0)
return (0);
mask >>= 1;
return (depth);
}
static int
{
int result;
result = 0;
switch (pixfmt) {
break;
break;
case PixelBitMask:
break;
default:
result = 1;
break;
}
return (result);
}
static int
{
int result;
&info->PixelInformation);
return (result);
}
static ssize_t
{
printf("UGA BLT operation failed (video->buffer)");
return (-1);
}
printf("Unable to allocate memory");
return (-1);
}
ofs = 0;
while (size > 0) {
data1);
printf("Error reading frame buffer (before)");
goto fail;
}
printf("UGA BLT operation failed (modify)");
goto fail;
}
data2);
printf("Error reading frame buffer (after)");
goto fail;
}
printf("UGA BLT operation failed (restore)");
goto fail;
}
}
}
}
printf("No change detected in frame buffer");
fail:
return (-1);
}
static EFI_PCI_IO_PROTOCOL *
efifb_uga_get_pciio(void)
{
/* Get all handles that support the UGA protocol. */
bufsz = 0;
if (status != EFI_BUFFER_TOO_SMALL)
return (NULL);
if (status != EFI_SUCCESS) {
return (NULL);
}
bufsz /= sizeof(EFI_HANDLE);
/* Get the PCI I/O interface of the first handle that supports it. */
if (status == EFI_SUCCESS) {
return (pciio);
}
}
return (NULL);
}
static EFI_STATUS
{
return (EFI_DEVICE_ERROR);
/* Attempt to get the frame buffer address (imprecise). */
*addrp = 0;
*sizep = 0;
(void **)&resattr);
if (status != EFI_SUCCESS)
continue;
/* XXX magic offsets and constants. */
/* 32-bit address space descriptor (MEMIO) */
/* 64-bit address space descriptor (MEMIO) */
} else {
addr = 0;
size = 0;
}
continue;
/* We assume the largest BAR is the frame buffer. */
}
}
}
static int
{
char *ev, *p;
return (1);
/* Paranoia... */
return (1);
/* The color masks are fixed AFAICT. */
NULL);
/* pciio can be NULL on return! */
pciio = efifb_uga_get_pciio();
/* Try to find the frame buffer. */
}
/*
* 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;
/* These are the expected values we should have. */
horiz = 1680;
vert = 1050;
fbaddr = 0xc0000000;
/* These are the missing bits. */
offset = 0x10000;
stride = 1728;
/* 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.
*/
return (0);
} else if (offset >= 0) {
"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...
*/
do {
if (np) {
}
} while (np);
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.
*/
if (offset == -1) {
printf("Unable to reliably detect frame buffer.\n");
} else if (offset > 0) {
}
} else {
offset = 0;
if (*p != '\0')
return (1);
}
/* Determine the stride. */
if (offset != -1)
} else {
printf("Unable to reliably detect the stride.\n");
}
} else {
if (*p != '\0')
return (1);
}
/*
* We finalized on the stride, so recalculate the size of the
* frame buffer.
*/
return (0);
}
int
{
if (status == EFI_SUCCESS)
if (status == EFI_SUCCESS)
return (1);
}
static void
{
if (mode >= 0)
if (verbose) {
printf("\n frame buffer: address=%jx, size=%jx",
printf("\n color mask: R=%08x, G=%08x, B=%08x\n",
}
}
static int
{
"%s: Graphics Output Protocol not present (error=%lu)",
return (CMD_ERROR);
}
if (argc < 2)
goto usage;
char *cp;
if (argc != 3)
goto usage;
if (cp[0] != '\0') {
return (CMD_ERROR);
}
"%s: Unable to set mode to %u (error=%lu)",
return (CMD_ERROR);
}
if (argc != 2)
goto usage;
printf("\n");
if (argc != 2)
goto usage;
pager_open();
continue;
if (pager_output("\n"))
break;
}
pager_close();
}
return (CMD_OK);
"usage: %s [list | get | set <mode>]", argv[0]);
return (CMD_ERROR);
}
static int
{
"%s: UGA Protocol not present (error=%lu)",
return (CMD_ERROR);
}
if (argc != 1)
goto usage;
"%s: Unable to get UGA information", argv[0]);
return (CMD_ERROR);
}
printf("\n");
return (CMD_OK);
return (CMD_ERROR);
}