Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150972568
D35982.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D35982.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D35982: Support loader screen rotation for panels mounted at non-native orientations.
Attached
Detach File
Event Timeline
Log In to Comment