Page MenuHomeFreeBSD

D35982.diff
No OneTemporary

D35982.diff

Index: libexec/rc/rc.d/Makefile
===================================================================
--- libexec/rc/rc.d/Makefile
+++ libexec/rc/rc.d/Makefile
@@ -188,6 +188,10 @@
CONFS+= ccd
.endif
+.if ${MK_EFI} != "no"
+CONFS+= uefivars
+.endif
+
.if ${MK_FTP} != "no"
CONFS+= ftpd
.endif
Index: libexec/rc/rc.d/uefivars
===================================================================
--- /dev/null
+++ libexec/rc/rc.d/uefivars
@@ -0,0 +1,89 @@
+#!/bin/sh
+#
+# Copyright (c) 2003 The FreeBSD Project. All rights reserved.
+#
+# 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
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+#
+# $FreeBSD$
+#
+
+# PROVIDE: uefivars
+# REQUIRE: FILESYSTEMS
+# KEYWORD: shutdown
+
+. /etc/rc.subr
+
+name="uefivars"
+desc="Synchronize UEFI with loader.conf variables"
+start_cmd="uefivars_start"
+stop_cmd="uefivars_start"
+
+efivar="/usr/sbin/efivar -q"
+freebsd_guid='cfee69ad-a0de-47a9-93a8-f63106f8ae99'
+iconv="/usr/bin/iconv -t UCS-2-INTERNAL"
+loader_conf="/boot/loader.conf"
+
+loader_variable_defined()
+{
+ local line_number
+ line_number=`sed -n -e 's/#.*//' -e "/^${1}=/=" $loader_conf`
+ echo -n "$line_number"
+}
+
+loader_variable_value()
+{
+ local value
+ value=`sed -n -e 's/#.*//' -e "/^${1}=/s/^.*=\"\([^\"]*\)\"/\1/p" $loader_conf`
+ echo -n "$value"
+}
+
+uefivars_start()
+{
+ # List of UEFI and loader.conf variables to synchronize.
+ uefivars_variables='LoaderRotate'
+ uefivars_config_LoaderRotate='screen.rotate'
+
+ local var loader_var config_value UEFI_value
+ for var in $uefivars_variables
+ do
+ eval loader_var=\$uefivars_config_$var
+ if [ -z "`loader_variable_defined $loader_var`" ]
+ then
+ debug "DELETE LoaderRotate"
+ # Delete UEFI variables not referenced in loader.conf.
+ $efivar -D ${freebsd_guid}-${var}
+ else
+ # Update UEFI variables that differ from the loader.conf value.
+ config_value=`loader_variable_value $loader_var`
+ UEFI_value=`$efivar -p -N -u ${freebsd_guid}-${var}`
+ if [ "$config_value" != "$UEFI_value" ]
+ then
+ debug "UPDATE LoaderRotate $config_value"
+ echo -n $config_value | $iconv | \
+ $efivar -w ${freebsd_guid}-${var}
+ fi
+ fi
+ done
+}
+
+load_rc_config $name
+run_rc_command "$1"
Index: stand/common/gfx_fb.h
===================================================================
--- stand/common/gfx_fb.h
+++ stand/common/gfx_fb.h
@@ -260,6 +260,9 @@
extern const int cons_to_vga_colors[NCOLORS];
+/* Set by freebsd-LoaderRotate UEFI variable, determines rotation of framebuffer. */
+extern uint32_t rotation;
+
/* Screen buffer to track changes on the terminal screen. */
extern struct text_pixel *screen_buffer;
bool is_same_pixel(struct text_pixel *, struct text_pixel *);
Index: stand/common/gfx_fb.c
===================================================================
--- stand/common/gfx_fb.c
+++ stand/common/gfx_fb.c
@@ -773,6 +773,282 @@
}
}
+#if defined(EFI)
+/*
+ * Rotate a UEFI Blt buffer of pixels by the specified angle (0,90,180,270) clockwise.
+ * Returns NULL if no rotation is performed, or a pointer to a static buffer
+ * containing the rotated data.
+ * We build the rotated buffer with Delta = 0 since there's no way to know what
+ * it should be if the rotation is 90 or 270 degrees.
+ */
+static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *
+RotateBuffer(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *inbuf,
+ UINTN angle, UINTN SourceX, UINTN SourceY,
+ UINTN Width, UINTN Height,
+ UINTN Delta)
+{
+ EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private;
+ UINTN srcWidth, destOffset, srcOffset;
+ static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *outbuf = NULL;
+
+ if (angle != 90 && angle != 180 && angle != 270)
+ return NULL;
+
+ if (outbuf == NULL &&
+ (outbuf = malloc(gop->Mode->Info->VerticalResolution *
+ gop->Mode->Info->HorizontalResolution *
+ sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) == NULL)
+ return NULL;
+
+ srcWidth = Width;
+ if (Delta != 0)
+ srcWidth = Delta;
+
+ /* Check for out-of-bounds access. */
+ if (srcWidth < SourceX + Width ||
+ srcWidth > gop->Mode->Info->HorizontalResolution ||
+ SourceX + Width > gop->Mode->Info->HorizontalResolution ||
+ SourceY + Height > gop->Mode->Info->VerticalResolution)
+ return NULL;
+
+ for (UINTN y = 0; y < Height; y++) {
+ for (UINTN x = 0; x < Width; x++) {
+ srcOffset = (SourceX + x) + (SourceY + y) * srcWidth;
+ switch ((int)angle) {
+ case 0: /* For reference */
+ destOffset = (SourceX + x) + (SourceY + y) * Width;
+ break;
+ case 90:
+ destOffset = (SourceY + ((Height - 1) - y)) +
+ (SourceX + x) * Height;
+ break;
+ case 180:
+ destOffset = (SourceX + ((Width - 1) - x)) +
+ (SourceY + ((Height - 1) - y)) * Width;
+ break;
+ case 270:
+ destOffset = (SourceY + y) +
+ (SourceX + ((Width - 1) - x)) * Height;
+ break;
+ }
+ outbuf[destOffset] = inbuf[srcOffset];
+ }
+ }
+ return (outbuf);
+}
+
+/* Macros to facilitate rotation. */
+#define SWITCH_VALIDATE
+#ifdef SWITCH_VALIDATE
+#define SWITCH(DIR, AXIS, ORIENT, EXTENT) \
+ if (Panel##DIR##AXIS + Rotated##EXTENT > \
+ gop->Mode->Info->ORIENT##Resolution - 1) \
+ Panel##DIR##AXIS = 0; \
+ else \
+ Panel##DIR##AXIS = (gop->Mode->Info->ORIENT##Resolution - 1) - \
+ (Panel##DIR##AXIS + Rotated##EXTENT)
+#define NO_SWITCH(DIR, AXIS, ORIENTATION) \
+ if (Panel##DIR##AXIS > gop->Mode->Info->ORIENTATION##Resolution - 1) \
+ Panel##DIR##AXIS = gop->Mode->Info->ORIENTATION##Resolution - 1
+#else
+#define SWITCH(DIR, AXIS, ORIENT, EXTENT) \
+ Panel##DIR##AXIS = (gop->Mode->Info->ORIENT##Resolution - 1) - \
+ (Panel##DIR##AXIS + Rotated##EXTENT)
+#define NO_SWITCH(DIR, AXIS, ORIENTATION)
+#endif
+#define SWITCH_SRC_X SWITCH(Src, X, Horizontal, Width)
+#define SWITCH_DST_X SWITCH(Dst, X, Horizontal, Width)
+#define SWITCH_SRC_Y SWITCH(Src, Y, Vertical, Height)
+#define SWITCH_DST_Y SWITCH(Dst, Y, Vertical, Height)
+#define NO_SWITCH_SRC_X NO_SWITCH(Src, X, Horizontal)
+#define NO_SWITCH_DST_X NO_SWITCH(Dst, X, Horizontal)
+#define NO_SWITCH_SRC_Y NO_SWITCH(Src, Y, Vertical)
+#define NO_SWITCH_DST_Y NO_SWITCH(Dst, Y, Vertical)
+
+/*
+ * Perhaps better implemented as a separate UEFI gop layer (c.f.
+ * https://github.com/apop2/GopRotate), this rotation layer resides in the
+ * loader itself, above the UEFI, and will rotate gop->Blt() requests by the
+ * specified angle. It is more complex than a simple rotation because the
+ * gop->Blt interface is complex; using the gop direct bitmap interface would be
+ * simpler but would require more changes to the loader graphics code.
+ */
+EFI_STATUS
+BltRot(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
+ EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ UINTN SourceX, UINTN SourceY,
+ UINTN DestinationX, UINTN DestinationY,
+ UINTN Width, UINTN Height,
+ UINTN Delta)
+{
+ EFI_STATUS status;
+ EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *PanelBuffer, *unrotatedBuffer;
+ static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *transformBuffer = NULL;
+ UINTN PanelSrcX, PanelSrcY, PanelDstX, PanelDstY, RotatedWidth, RotatedHeight;
+ UINTN destWidth;
+
+ /*
+ * Translate logical:
+ * BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height
+ * to physical:
+ * PanelBuffer, PanelSrcX, PanelSrcY, PanelDstX, PanelDstY, RotatedWidth,
+ * RotatedHeight
+ * corresponding to the display hardware.
+ *
+ * Typically DestinationX = 0, DestinationY= 0 will correspond to the upper left
+ * pixel of the display in its mounted orientation, whereas PanelDstX = 0,
+ * PanelDstY = 0 will correspond to the hardware panel 0,0 coordinate.
+ */
+ PanelSrcX = SourceX, PanelSrcY = SourceY;
+ PanelDstX = DestinationX, PanelDstY = DestinationY;
+ RotatedWidth = Width, RotatedHeight = Height;
+ PanelBuffer = BltBuffer;
+
+ switch (BltOperation) {
+ /*
+ * Not only do we need to rotate the coordinates, we also need to rotate
+ * the origin of the BltBuffer transfer box (which itself must be
+ * rotated).
+ */
+ case EfiBltBufferToVideo:
+ if (rotation == 0 ||
+ (PanelBuffer = RotateBuffer(BltBuffer, rotation, SourceX, SourceY,
+ Width, Height, Delta)) == NULL) {
+ PanelBuffer = BltBuffer;
+ break;
+ }
+ Delta = 0; /* PanelBuffer is built with no delta */
+ /* Fallthrough */
+
+ /* Rotate the coordinates to the panel coordinates. */
+ case EfiBltVideoFill:
+ if (rotation == 90 || rotation == 270) {
+ PanelDstX = DestinationY, PanelDstY = DestinationX;
+ RotatedWidth = Height, RotatedHeight = Width;
+ }
+ switch (rotation) {
+ case 0:
+ break;
+ case 90:
+ SWITCH_DST_X;
+ NO_SWITCH_DST_Y;
+ break;
+ case 180:
+ SWITCH_DST_X;
+ SWITCH_DST_Y;
+ break;
+ case 270:
+ NO_SWITCH_DST_X;
+ SWITCH_DST_Y;
+ break;
+ }
+ break;
+
+ /* Rotate the coordinates to and from the panel coordinates. */
+ case EfiBltVideoToVideo:
+ if (rotation == 90 || rotation == 270) {
+ PanelSrcX = SourceY, PanelSrcY = SourceX;
+ PanelDstX = DestinationY, PanelDstY = DestinationX;
+ RotatedWidth = Height, RotatedHeight = Width;
+ }
+ switch (rotation) {
+ case 90:
+ SWITCH_SRC_X;
+ SWITCH_DST_X;
+ NO_SWITCH_SRC_Y;
+ NO_SWITCH_DST_Y;
+ break;
+ case 180:
+ SWITCH_SRC_X;
+ SWITCH_DST_X;
+ SWITCH_SRC_Y;
+ SWITCH_DST_Y;
+ break;
+ case 270:
+ NO_SWITCH_SRC_X;
+ NO_SWITCH_DST_X;
+ SWITCH_SRC_Y;
+ SWITCH_DST_Y;
+ break;
+ }
+ break;
+
+ /* Rotate the coordinates from the panel coordinates. */
+ case EfiBltVideoToBltBuffer:
+ if (rotation == 0 ||
+ (transformBuffer == NULL &&
+ (transformBuffer = malloc(gop->Mode->Info->HorizontalResolution *
+ gop->Mode->Info->VerticalResolution *
+ sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) == NULL))
+ break;
+
+ PanelBuffer = transformBuffer;
+ if (rotation == 90 || rotation == 270) {
+ PanelSrcX = SourceY, PanelSrcY = SourceX;
+ RotatedWidth = Height, RotatedHeight = Width;
+ }
+ switch (rotation) {
+ case 90:
+ SWITCH_SRC_X;
+ NO_SWITCH_SRC_Y;
+ break;
+ case 180:
+ SWITCH_SRC_X;
+ SWITCH_SRC_Y;
+ break;
+ case 270:
+ NO_SWITCH_SRC_X;
+ SWITCH_SRC_Y;
+ break;
+ }
+ break;
+ }
+
+ status = gop->Blt(gop, PanelBuffer, BltOperation,
+ PanelSrcX, PanelSrcY, PanelDstX, PanelDstY,
+ RotatedWidth, RotatedHeight, Delta);
+ if (EFI_ERROR(status))
+ return (status);
+
+ /* Unless we need to unrotate and merge data into BltBuffer, we are done. */
+ if (BltOperation != EfiBltVideoToBltBuffer || PanelBuffer == BltBuffer)
+ return (status);
+
+ /*
+ * Until this point, on rotation failure we simply pass the data
+ * unrotated. From here on, we return an error (which will likely cause
+ * loader failure).
+ */
+ unrotatedBuffer = RotateBuffer(PanelBuffer, 360 - rotation,
+ DestinationX, DestinationY, Width, Height, Delta);
+ if (unrotatedBuffer == NULL)
+ return (EFI_OUT_OF_RESOURCES);
+
+ /*
+ * It is not obvious what the correct reconstruction of a non-zero delta
+ * should be. This is likely to work correctly.
+ */
+ destWidth = Width;
+ if (Delta != 0)
+ destWidth = Delta;
+
+ /* Check for out-of-bounds access. */
+ if (destWidth < DestinationX + Width ||
+ destWidth > gop->Mode->Info->HorizontalResolution ||
+ DestinationX + Width > gop->Mode->Info->HorizontalResolution ||
+ DestinationY + Height > gop->Mode->Info->VerticalResolution)
+ return (EFI_INVALID_PARAMETER);
+
+ for (UINTN y = DestinationY; y < DestinationY + Height; y++) {
+ for (UINTN x = DestinationX; x < DestinationX + Width; x++) {
+ BltBuffer[x + y * destWidth] = unrotatedBuffer[x + y * Width];
+ }
+ }
+ return (status);
+}
+#endif
+
int
gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
uint32_t SourceX, uint32_t SourceY,
@@ -794,28 +1070,26 @@
tpl = BS->RaiseTPL(TPL_NOTIFY);
switch (BltOperation) {
case GfxFbBltVideoFill:
- gfxfb_shadow_fill(BltBuffer, DestinationX,
- DestinationY, Width, Height);
- status = gop->Blt(gop, BltBuffer, EfiBltVideoFill,
+ status = BltRot(BltBuffer, EfiBltVideoFill,
SourceX, SourceY, DestinationX, DestinationY,
Width, Height, Delta);
break;
case GfxFbBltVideoToBltBuffer:
- status = gop->Blt(gop, BltBuffer,
+ status = BltRot(BltBuffer,
EfiBltVideoToBltBuffer,
SourceX, SourceY, DestinationX, DestinationY,
Width, Height, Delta);
break;
case GfxFbBltBufferToVideo:
- status = gop->Blt(gop, BltBuffer, EfiBltBufferToVideo,
+ status = BltRot(BltBuffer, EfiBltBufferToVideo,
SourceX, SourceY, DestinationX, DestinationY,
Width, Height, Delta);
break;
case GfxFbBltVideoToVideo:
- status = gop->Blt(gop, BltBuffer, EfiBltVideoToVideo,
+ status = BltRot(BltBuffer, EfiBltVideoToVideo,
SourceX, SourceY, DestinationX, DestinationY,
Width, Height, Delta);
break;
Index: stand/efi/libefi/env.c
===================================================================
--- stand/efi/libefi/env.c
+++ stand/efi/libefi/env.c
@@ -469,7 +469,7 @@
/*
* Print FreeBSD variables.
- * We have LoaderPath and LoaderDev as CHAR16 strings.
+ * We have LoaderRotate, LoaderPath and LoaderDev as CHAR16 strings.
*/
static int
efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data,
@@ -481,7 +481,8 @@
if (ucs2_to_utf8(varnamearg, &var) != 0)
return (CMD_ERROR);
- if (strcmp("LoaderPath", var) == 0 ||
+ if (strcmp("LoaderRotate", var) == 0 ||
+ strcmp("LoaderPath", var) == 0 ||
strcmp("LoaderDev", var) == 0) {
printf(" = ");
printf("%S", (CHAR16 *)data);
Index: stand/efi/loader/bootinfo.c
===================================================================
--- stand/efi/loader/bootinfo.c
+++ stand/efi/loader/bootinfo.c
@@ -304,8 +304,17 @@
efifb.fb_addr = gfx_state.tg_fb.fb_addr;
efifb.fb_size = gfx_state.tg_fb.fb_size;
- efifb.fb_height = gfx_state.tg_fb.fb_height;
- efifb.fb_width = gfx_state.tg_fb.fb_width;
+ /*
+ * If we have rotated the framebuffer height and width, rotate them back
+ * before passing them to the kernel
+ */
+ if (rotation == 90 || rotation == 270) {
+ efifb.fb_height = gfx_state.tg_fb.fb_width;
+ efifb.fb_width = gfx_state.tg_fb.fb_height;
+ } else {
+ efifb.fb_height = gfx_state.tg_fb.fb_height;
+ efifb.fb_width = gfx_state.tg_fb.fb_width;
+ }
efifb.fb_stride = gfx_state.tg_fb.fb_stride;
efifb.fb_mask_red = gfx_state.tg_fb.fb_mask_red;
efifb.fb_mask_green = gfx_state.tg_fb.fb_mask_green;
Index: stand/efi/loader/framebuffer.c
===================================================================
--- stand/efi/loader/framebuffer.c
+++ stand/efi/loader/framebuffer.c
@@ -43,7 +43,9 @@
#include <machine/metadata.h>
#include "bootstrap.h"
+#include "efichar.h"
#include "framebuffer.h"
+#include "gfx_fb.h"
static EFI_GUID conout_guid = EFI_CONSOLE_OUT_DEVICE_GUID;
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
@@ -56,6 +58,9 @@
/* Cached EDID. */
struct vesa_edid_info *edid_info = NULL;
+/* Angle to rotate boot console display. */
+uint32_t rotation = 0;
+
static EFI_GRAPHICS_OUTPUT *gop;
static EFI_UGA_DRAW_PROTOCOL *uga;
@@ -147,11 +152,42 @@
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info)
{
int result;
+ size_t len = 0;
+ efi_char *buf;
+ char *angle = NULL;
+ EFI_STATUS rv;
+
+ /*
+ * Use the UEFI variable freebsd-LoaderRotate to rotate the framebuffer
+ * to match the panel orientation. We use a UEFI variable because
+ * the framebuffer is set up very early in the boot process, before
+ * loader variables (even the early /boot/efi/EFI/FreeBSD/loader.env
+ * variables) are set up.
+ *
+ * It is intended that an rc.d script shall use the screen.rotate loader
+ * variable to update freebsd-LoaderRotate for the next boot.
+ */
+ if (efi_freebsd_getenv("LoaderRotate", NULL, &len) == EFI_BUFFER_TOO_SMALL)
+ if ((buf = calloc(len + 1, sizeof(efi_char)))) {
+ if (efi_freebsd_getenv("LoaderRotate", buf, &len) == EFI_SUCCESS)
+ if (ucs2_to_utf8(buf, &angle) == 0) {
+ rotation = strtol(angle, NULL, 0);
+ free(angle);
+ }
+ free(buf);
+ }
+ if (rotation != 90 && rotation != 180 && rotation != 270)
+ rotation = 0;
efifb->fb_addr = mode->FrameBufferBase;
efifb->fb_size = mode->FrameBufferSize;
- efifb->fb_height = info->VerticalResolution;
- efifb->fb_width = info->HorizontalResolution;
+ if (rotation == 90 || rotation == 270) {
+ efifb->fb_width = info->VerticalResolution;
+ efifb->fb_height = info->HorizontalResolution;
+ } else {
+ 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);

File Metadata

Mime Type
text/plain
Expires
Mon, Apr 6, 6:09 AM (8 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30942458
Default Alt Text
D35982.diff (17 KB)

Event Timeline