Attachment 'loader_rotate-13.3-RELEASE.diff'

Download

   1 diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf
   2 index 824751078833..94888099d4ca 100644
   3 --- a/libexec/rc/rc.conf
   4 +++ b/libexec/rc/rc.conf
   5 @@ -70,6 +70,10 @@ local_startup="${_localbase}/etc/rc.d" # startup script dirs.
   6  script_name_sep=" "	# Change if your startup scripts' names contain spaces
   7  rc_conf_files="/etc/rc.conf /etc/rc.conf.local"
   8  
   9 +# List of UEFI and kenv(1) variables to synchronize.
  10 +uefivars_variables='LoaderRotate'	   # Space separated list of names of variables
  11 +uefivars_kenv_LoaderRotate='screen.rotate' # List kenv(1) keys, one per UEFI variable
  12 +
  13  # ZFS support
  14  zfs_enable="NO"		# Set to YES to automatically mount ZFS file systems
  15  zfskeys_enable="NO"	# Set YES to autoload ZFS encryption keys
  16 diff --git a/libexec/rc/rc.d/Makefile b/libexec/rc/rc.d/Makefile
  17 index ac35a2b5e28f..bc259c290135 100644
  18 --- a/libexec/rc/rc.d/Makefile
  19 +++ b/libexec/rc/rc.d/Makefile
  20 @@ -201,6 +201,10 @@ BSNMPPACKAGE=	bsnmp
  21  CONFS+=		ccd
  22  .endif
  23  
  24 +.if ${MK_EFI} != "no"
  25 +CONFS+=		uefivars
  26 +.endif
  27 +
  28  .if ${MK_FTP} != "no"
  29  CONFS+=		ftpd
  30  .endif
  31 diff --git a/libexec/rc/rc.d/uefivars b/libexec/rc/rc.d/uefivars
  32 new file mode 100755
  33 index 000000000000..18d20cec7aa1
  34 --- /dev/null
  35 +++ b/libexec/rc/rc.d/uefivars
  36 @@ -0,0 +1,71 @@
  37 +#!/bin/sh
  38 +#
  39 +# Copyright (c) 2003 The FreeBSD Project. All rights reserved.
  40 +#
  41 +# Redistribution and use in source and binary forms, with or without
  42 +# modification, are permitted provided that the following conditions
  43 +# are met:
  44 +# 1. Redistributions of source code must retain the above copyright
  45 +#    notice, this list of conditions and the following disclaimer.
  46 +# 2. Redistributions in binary form must reproduce the above copyright
  47 +#    notice, this list of conditions and the following disclaimer in the
  48 +#    documentation and/or other materials provided with the distribution.
  49 +#
  50 +# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  51 +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  52 +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  53 +# ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  54 +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  55 +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  56 +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  57 +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  58 +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  59 +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  60 +# SUCH DAMAGE.
  61 +#
  62 +# $FreeBSD$
  63 +#
  64 +
  65 +# PROVIDE: uefivars
  66 +# REQUIRE: kld
  67 +# KEYWORD: shutdown
  68 +
  69 +. /etc/rc.subr
  70 +
  71 +name="uefivars"
  72 +desc="Synchronize UEFI with kenv(1) variables"
  73 +start_cmd="uefivars_start"
  74 +stop_cmd="uefivars_start"
  75 +
  76 +efivar="/usr/sbin/efivar -q"
  77 +freebsd_guid='cfee69ad-a0de-47a9-93a8-f63106f8ae99'
  78 +iconv="/usr/bin/iconv -t UCS-2-INTERNAL"
  79 +kenv="/bin/kenv -q"
  80 +
  81 +uefivars_start()
  82 +{
  83 +	local var kenv_key kenv_value UEFI_value
  84 +	for var in $uefivars_variables
  85 +	do
  86 +		eval kenv_key=\$uefivars_kenv_$var
  87 +		kenv_value=`$kenv $kenv_key`
  88 +		if [ -z "$kenv_value" ]
  89 +		then
  90 +			debug "DELETE LoaderRotate"
  91 +			# Delete UEFI variables without corresponding kenv(1) key.
  92 +			$efivar -D ${freebsd_guid}-${var}
  93 +		else
  94 +			# Update UEFI variables that differ from $kenv_value.
  95 +			UEFI_value=`$efivar -p -N -u ${freebsd_guid}-${var}`
  96 +			if [ "$kenv_value" != "$UEFI_value" ]
  97 +			then
  98 +				debug "UPDATE LoaderRotate $config_value"
  99 +				echo -n $kenv_value | $iconv | \
 100 +					$efivar -w ${freebsd_guid}-${var}
 101 +			fi
 102 +		fi
 103 +	done
 104 +}
 105 +
 106 +load_rc_config $name
 107 +run_rc_command "$1"
 108 diff --git a/stand/common/gfx_fb.c b/stand/common/gfx_fb.c
 109 index 27ac66f259b1..00e7b77b532c 100644
 110 --- a/stand/common/gfx_fb.c
 111 +++ b/stand/common/gfx_fb.c
 112 @@ -771,6 +771,282 @@ gfxfb_shadow_fill(uint32_t *BltBuffer,
 113  	}
 114  }
 115  
 116 +#if defined(EFI)
 117 +/*
 118 + * Rotate a UEFI Blt buffer of pixels by the specified angle (0,90,180,270) clockwise.
 119 + * Returns NULL if no rotation is performed, or a pointer to a static buffer
 120 + * containing the rotated data.
 121 + * We build the rotated buffer with Delta = 0 since there's no way to know what
 122 + * it should be if the rotation is 90 or 270 degrees.
 123 + */
 124 +static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *
 125 +RotateBuffer(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *inbuf,
 126 +    UINTN angle, UINTN SourceX, UINTN SourceY,
 127 +    UINTN Width, UINTN Height,
 128 +    UINTN Delta)
 129 +{
 130 +	EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private;
 131 +	UINTN srcWidth, destOffset, srcOffset;
 132 +	static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *outbuf = NULL;
 133 +
 134 +	if (angle != 90 && angle != 180 && angle != 270)
 135 +		return NULL;
 136 +
 137 +	if (outbuf == NULL &&
 138 +	    (outbuf = malloc(gop->Mode->Info->VerticalResolution *
 139 +	    gop->Mode->Info->HorizontalResolution *
 140 +	    sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) == NULL)
 141 +		return NULL;
 142 +
 143 +	srcWidth = Width;
 144 +	if (Delta != 0)
 145 +		srcWidth = Delta;
 146 +
 147 +	/* Check for out-of-bounds access. */
 148 +	if (srcWidth < SourceX + Width ||
 149 +	    srcWidth > gop->Mode->Info->HorizontalResolution ||
 150 +	    SourceX + Width > gop->Mode->Info->HorizontalResolution ||
 151 +	    SourceY + Height > gop->Mode->Info->VerticalResolution)
 152 +		return NULL;
 153 +
 154 +	for (UINTN y = 0; y < Height; y++) {
 155 +		for (UINTN x = 0; x < Width; x++) {
 156 +			srcOffset = (SourceX + x) + (SourceY + y) * srcWidth;
 157 +			switch ((int)angle) {
 158 +			case 0:	/* For reference */
 159 +				destOffset = (SourceX + x) + (SourceY + y) * Width;
 160 +				break;
 161 +			case 90:
 162 +				destOffset = (SourceY + ((Height - 1) - y)) +
 163 +				    (SourceX + x) * Height;
 164 +				break;
 165 +			case 180:
 166 +				destOffset = (SourceX + ((Width - 1) - x)) +
 167 +				    (SourceY + ((Height - 1) - y)) * Width;
 168 +				break;
 169 +			case 270:
 170 +				destOffset = (SourceY + y) +
 171 +				    (SourceX + ((Width - 1) - x)) * Height;
 172 +				break;
 173 +			}
 174 +			outbuf[destOffset] = inbuf[srcOffset];
 175 +		}
 176 +	}
 177 +	return (outbuf);
 178 +}
 179 +
 180 +/* Macros to facilitate rotation. */
 181 +#define SWITCH_VALIDATE
 182 +#ifdef  SWITCH_VALIDATE
 183 +#define	SWITCH(DIR, AXIS, ORIENT, EXTENT)					\
 184 +	if (Panel##DIR##AXIS + Rotated##EXTENT >				\
 185 +	    gop->Mode->Info->ORIENT##Resolution - 1)				\
 186 +		Panel##DIR##AXIS = 0;						\
 187 +	else									\
 188 +		Panel##DIR##AXIS = (gop->Mode->Info->ORIENT##Resolution - 1) -	\
 189 +		    (Panel##DIR##AXIS + Rotated##EXTENT)
 190 +#define	NO_SWITCH(DIR, AXIS, ORIENTATION)					\
 191 +	if (Panel##DIR##AXIS > gop->Mode->Info->ORIENTATION##Resolution - 1)	\
 192 +		Panel##DIR##AXIS = gop->Mode->Info->ORIENTATION##Resolution - 1
 193 +#else
 194 +#define	SWITCH(DIR, AXIS, ORIENT, EXTENT)					\
 195 +	Panel##DIR##AXIS = (gop->Mode->Info->ORIENT##Resolution - 1) -		\
 196 +	    (Panel##DIR##AXIS + Rotated##EXTENT)
 197 +#define	NO_SWITCH(DIR, AXIS, ORIENTATION)
 198 +#endif
 199 +#define SWITCH_SRC_X	SWITCH(Src, X, Horizontal, Width)
 200 +#define SWITCH_DST_X	SWITCH(Dst, X, Horizontal, Width)
 201 +#define	SWITCH_SRC_Y	SWITCH(Src, Y, Vertical, Height)
 202 +#define	SWITCH_DST_Y	SWITCH(Dst, Y, Vertical, Height)
 203 +#define NO_SWITCH_SRC_X	NO_SWITCH(Src, X, Horizontal)
 204 +#define NO_SWITCH_DST_X	NO_SWITCH(Dst, X, Horizontal)
 205 +#define	NO_SWITCH_SRC_Y	NO_SWITCH(Src, Y, Vertical)
 206 +#define	NO_SWITCH_DST_Y	NO_SWITCH(Dst, Y, Vertical)
 207 +
 208 +/*
 209 + * Perhaps better implemented as a separate UEFI gop layer (c.f.
 210 + * https://github.com/apop2/GopRotate), this rotation layer resides in the
 211 + * loader itself, above the UEFI, and will rotate gop->Blt() requests by the
 212 + * specified angle.  It is more complex than a simple rotation because the
 213 + * gop->Blt interface is complex; using the gop direct bitmap interface would be
 214 + * simpler but would require more changes to the loader graphics code.
 215 + */
 216 +EFI_STATUS
 217 +BltRot(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
 218 +    EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
 219 +    UINTN SourceX, UINTN SourceY,
 220 +    UINTN DestinationX, UINTN DestinationY,
 221 +    UINTN Width, UINTN Height,
 222 +    UINTN Delta)
 223 +{
 224 +	EFI_STATUS status;
 225 +	EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private;
 226 +	EFI_GRAPHICS_OUTPUT_BLT_PIXEL *PanelBuffer, *unrotatedBuffer;
 227 +	static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *transformBuffer = NULL;
 228 +	UINTN PanelSrcX, PanelSrcY, PanelDstX, PanelDstY, RotatedWidth, RotatedHeight;
 229 +	UINTN destWidth;
 230 +
 231 +	/*
 232 +	 * Translate logical:
 233 +	 * BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height
 234 +	 * to physical:
 235 +	 * PanelBuffer, PanelSrcX, PanelSrcY, PanelDstX, PanelDstY, RotatedWidth,
 236 +	 *  RotatedHeight
 237 +	 * corresponding to the display hardware.
 238 +	 *
 239 +	 * Typically DestinationX = 0, DestinationY= 0 will correspond to the upper left
 240 +	 * pixel of the display in its mounted orientation, whereas PanelDstX = 0,
 241 +	 * PanelDstY = 0 will correspond to the hardware panel 0,0 coordinate.
 242 +	 */
 243 +	PanelSrcX = SourceX, PanelSrcY = SourceY;
 244 +	PanelDstX = DestinationX, PanelDstY = DestinationY;
 245 +	RotatedWidth = Width, RotatedHeight = Height;
 246 +	PanelBuffer = BltBuffer;
 247 +
 248 +	switch (BltOperation) {
 249 +	/*
 250 +	 * Not only do we need to rotate the coordinates, we also need to rotate
 251 +	 * the origin of the BltBuffer transfer box (which itself must be
 252 +	 * rotated).
 253 +	 */
 254 +	case EfiBltBufferToVideo:
 255 +		if (rotation == 0 ||
 256 +		    (PanelBuffer = RotateBuffer(BltBuffer, rotation, SourceX, SourceY,
 257 +		    Width, Height, Delta)) == NULL) {
 258 +			PanelBuffer = BltBuffer;
 259 +			break;
 260 +		}
 261 +		Delta = 0;		/* PanelBuffer is built with no delta */
 262 +		/* Fallthrough */
 263 +
 264 +	/* Rotate the coordinates to the panel coordinates. */
 265 +	case EfiBltVideoFill:
 266 +		if (rotation == 90 || rotation == 270) {
 267 +			PanelDstX = DestinationY, PanelDstY = DestinationX;
 268 +			RotatedWidth = Height, RotatedHeight = Width;
 269 +		}
 270 +		switch (rotation) {
 271 +		case 0:
 272 +			break;
 273 +		case 90:
 274 +			SWITCH_DST_X;
 275 +			NO_SWITCH_DST_Y;
 276 +			break;
 277 +		case 180:
 278 +			SWITCH_DST_X;
 279 +			SWITCH_DST_Y;
 280 +			break;
 281 +		case 270:
 282 +			NO_SWITCH_DST_X;
 283 +			SWITCH_DST_Y;
 284 +			break;
 285 +		}
 286 +		break;
 287 +
 288 +	/* Rotate the coordinates to and from the panel coordinates. */
 289 +	case EfiBltVideoToVideo:
 290 +		if (rotation == 90 || rotation == 270) {
 291 +			PanelSrcX = SourceY, PanelSrcY = SourceX;
 292 +			PanelDstX = DestinationY, PanelDstY = DestinationX;
 293 +			RotatedWidth = Height, RotatedHeight = Width;
 294 +		}
 295 +		switch (rotation) {
 296 +		case 90:
 297 +			SWITCH_SRC_X;
 298 +			SWITCH_DST_X;
 299 +			NO_SWITCH_SRC_Y;
 300 +			NO_SWITCH_DST_Y;
 301 +			break;
 302 +		case 180:
 303 +			SWITCH_SRC_X;
 304 +			SWITCH_DST_X;
 305 +			SWITCH_SRC_Y;
 306 +			SWITCH_DST_Y;
 307 +			break;
 308 +		case 270:
 309 +			NO_SWITCH_SRC_X;
 310 +			NO_SWITCH_DST_X;
 311 +			SWITCH_SRC_Y;
 312 +			SWITCH_DST_Y;
 313 +			break;
 314 +		}
 315 +		break;
 316 +	
 317 +	/* Rotate the coordinates from the panel coordinates. */
 318 +	case EfiBltVideoToBltBuffer:
 319 +		if (rotation == 0 ||
 320 +		    (transformBuffer == NULL &&
 321 +		    (transformBuffer = malloc(gop->Mode->Info->HorizontalResolution *
 322 +		    gop->Mode->Info->VerticalResolution *
 323 +		    sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) == NULL))
 324 +			break;
 325 +
 326 +		PanelBuffer = transformBuffer;
 327 +		if (rotation == 90 || rotation == 270) {
 328 +			PanelSrcX = SourceY, PanelSrcY = SourceX;
 329 +			RotatedWidth = Height, RotatedHeight = Width;
 330 +		}
 331 +		switch (rotation) {
 332 +		case 90:
 333 +			SWITCH_SRC_X;
 334 +			NO_SWITCH_SRC_Y;
 335 +			break;
 336 +		case 180:
 337 +			SWITCH_SRC_X;
 338 +			SWITCH_SRC_Y;
 339 +			break;
 340 +		case 270:
 341 +			NO_SWITCH_SRC_X;
 342 +			SWITCH_SRC_Y;
 343 +			break;
 344 +		}
 345 +		break;
 346 +	}
 347 +
 348 +	status = gop->Blt(gop, PanelBuffer, BltOperation,
 349 +	    PanelSrcX, PanelSrcY, PanelDstX, PanelDstY,
 350 +	    RotatedWidth, RotatedHeight, Delta);
 351 +	if (EFI_ERROR(status))
 352 +		return (status);
 353 +
 354 +	/* Unless we need to unrotate and merge data into BltBuffer, we are done. */
 355 +	if (BltOperation != EfiBltVideoToBltBuffer || PanelBuffer == BltBuffer)
 356 +		return (status);
 357 +
 358 +	/*
 359 +	 * Until this point, on rotation failure we simply pass the data
 360 +	 * unrotated.  From here on, we return an error (which will likely cause
 361 +	 * loader failure).
 362 +	 */
 363 +	unrotatedBuffer = RotateBuffer(PanelBuffer, 360 - rotation,
 364 +	    DestinationX, DestinationY, Width, Height, Delta);
 365 +	if (unrotatedBuffer == NULL)
 366 +		return (EFI_OUT_OF_RESOURCES);
 367 +
 368 +	/*
 369 +	 * It is not obvious what the correct reconstruction of a non-zero delta
 370 +	 * should be.  This is likely to work correctly.
 371 +	 */
 372 +	destWidth = Width;
 373 +	if (Delta != 0)
 374 +		destWidth = Delta;
 375 +
 376 +	/* Check for out-of-bounds access. */
 377 +	if (destWidth < DestinationX + Width ||
 378 +	    destWidth > gop->Mode->Info->HorizontalResolution ||
 379 +	    DestinationX + Width > gop->Mode->Info->HorizontalResolution ||
 380 +	    DestinationY + Height > gop->Mode->Info->VerticalResolution)
 381 +		return (EFI_INVALID_PARAMETER);
 382 +
 383 +	for (UINTN y = DestinationY; y < DestinationY + Height; y++) {
 384 +		for (UINTN x = DestinationX; x < DestinationX + Width; x++) {
 385 +			BltBuffer[x + y * destWidth] = unrotatedBuffer[x + y * Width];
 386 +		}
 387 +	}
 388 +	return (status);
 389 +}
 390 +#endif
 391 +
 392  int
 393  gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
 394      uint32_t SourceX, uint32_t SourceY,
 395 @@ -794,28 +1070,26 @@ gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation,
 396  		tpl = BS->RaiseTPL(TPL_NOTIFY);
 397  		switch (BltOperation) {
 398  		case GfxFbBltVideoFill:
 399 -			gfxfb_shadow_fill(BltBuffer, DestinationX,
 400 -			    DestinationY, Width, Height);
 401 -			status = gop->Blt(gop, BltBuffer, EfiBltVideoFill,
 402 +			status = BltRot(BltBuffer, EfiBltVideoFill,
 403  			    SourceX, SourceY, DestinationX, DestinationY,
 404  			    Width, Height, Delta);
 405  			break;
 406  
 407  		case GfxFbBltVideoToBltBuffer:
 408 -			status = gop->Blt(gop, BltBuffer,
 409 +			status = BltRot(BltBuffer,
 410  			    EfiBltVideoToBltBuffer,
 411  			    SourceX, SourceY, DestinationX, DestinationY,
 412  			    Width, Height, Delta);
 413  			break;
 414  
 415  		case GfxFbBltBufferToVideo:
 416 -			status = gop->Blt(gop, BltBuffer, EfiBltBufferToVideo,
 417 +			status = BltRot(BltBuffer, EfiBltBufferToVideo,
 418  			    SourceX, SourceY, DestinationX, DestinationY,
 419  			    Width, Height, Delta);
 420  			break;
 421  
 422  		case GfxFbBltVideoToVideo:
 423 -			status = gop->Blt(gop, BltBuffer, EfiBltVideoToVideo,
 424 +			status = BltRot(BltBuffer, EfiBltVideoToVideo,
 425  			    SourceX, SourceY, DestinationX, DestinationY,
 426  			    Width, Height, Delta);
 427  			break;
 428 diff --git a/stand/common/gfx_fb.h b/stand/common/gfx_fb.h
 429 index adb60c673ea9..50bfe0748f8d 100644
 430 --- a/stand/common/gfx_fb.h
 431 +++ b/stand/common/gfx_fb.h
 432 @@ -257,6 +257,9 @@ struct text_pixel {
 433  
 434  extern const int cons_to_vga_colors[NCOLORS];
 435  
 436 +/* Set by freebsd-LoaderRotate UEFI variable, determines rotation of framebuffer. */
 437 +extern uint32_t rotation;
 438 +
 439  /* Screen buffer to track changes on the terminal screen. */
 440  extern struct text_pixel *screen_buffer;
 441  bool is_same_pixel(struct text_pixel *, struct text_pixel *);
 442 diff --git a/stand/efi/libefi/env.c b/stand/efi/libefi/env.c
 443 index 6887038fe950..a495580de17d 100644
 444 --- a/stand/efi/libefi/env.c
 445 +++ b/stand/efi/libefi/env.c
 446 @@ -467,7 +467,7 @@ efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data,
 447  
 448  /*
 449   * Print FreeBSD variables.
 450 - * We have LoaderPath and LoaderDev as CHAR16 strings.
 451 + * We have LoaderRotate, LoaderPath and LoaderDev as CHAR16 strings.
 452   */
 453  static int
 454  efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data,
 455 @@ -479,7 +479,8 @@ efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data,
 456  	if (ucs2_to_utf8(varnamearg, &var) != 0)
 457  		return (CMD_ERROR);
 458  
 459 -	if (strcmp("LoaderPath", var) == 0 ||
 460 +	if (strcmp("LoaderRotate", var) == 0 ||
 461 +	    strcmp("LoaderPath", var) == 0 ||
 462  	    strcmp("LoaderDev", var) == 0) {
 463  		printf(" = ");
 464  		printf("%S", (CHAR16 *)data);
 465 diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c
 466 index 1f3664b50948..df004d8808f2 100644
 467 --- a/stand/efi/loader/bootinfo.c
 468 +++ b/stand/efi/loader/bootinfo.c
 469 @@ -184,8 +184,17 @@ bi_load_efi_data(struct preloaded_file *kfp, bool exit_bs)
 470  
 471  	efifb.fb_addr = gfx_state.tg_fb.fb_addr;
 472  	efifb.fb_size = gfx_state.tg_fb.fb_size;
 473 -	efifb.fb_height = gfx_state.tg_fb.fb_height;
 474 -	efifb.fb_width = gfx_state.tg_fb.fb_width;
 475 +	/*
 476 +	 * If we have rotated the framebuffer height and width, rotate them back
 477 +	 * before passing them to the kernel
 478 +	 */
 479 +	if (rotation == 90 || rotation == 270) {
 480 +	    efifb.fb_height = gfx_state.tg_fb.fb_width;
 481 +	    efifb.fb_width = gfx_state.tg_fb.fb_height;
 482 +	} else {
 483 +	    efifb.fb_height = gfx_state.tg_fb.fb_height;
 484 +	    efifb.fb_width = gfx_state.tg_fb.fb_width;
 485 +	}
 486  	efifb.fb_stride = gfx_state.tg_fb.fb_stride;
 487  	efifb.fb_mask_red = gfx_state.tg_fb.fb_mask_red;
 488  	efifb.fb_mask_green = gfx_state.tg_fb.fb_mask_green;
 489 @@ -327,6 +336,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs)
 490  	vm_offset_t size;
 491  	char *rootdevname;
 492  	int howto;
 493 +	char *autorotate, strbuf[4];
 494  	bool is64 = sizeof(long) == 8;
 495  #if defined(LOADER_FDT_SUPPORT)
 496  	vm_offset_t dtbp;
 497 @@ -349,6 +359,17 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs)
 498  #endif
 499  	howto = bi_getboothowto(args);
 500  
 501 +	/*
 502 +	 * If screen.rotate="AUTO", pass the current rotation to the kernel to
 503 +	 * use until the autodetection completes.
 504 +	 */
 505 +	if (rotation != 0 &&
 506 +	    (autorotate = getenv("screen.rotate")) != NULL &&
 507 +	    strncasecmp(autorotate, "auto", 5) == 0) {
 508 +		snprintf(strbuf, sizeof(strbuf), "%d", rotation);
 509 +		setenv("screen.autorotate", strbuf, 1);
 510 +	}
 511 +
 512  	/*
 513  	 * Allow the environment variable 'rootdev' to override the supplied
 514  	 * device. This should perhaps go to MI code and/or have $rootdev
 515 diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c
 516 index 56693187b576..6be3d384e741 100644
 517 --- a/stand/efi/loader/framebuffer.c
 518 +++ b/stand/efi/loader/framebuffer.c
 519 @@ -40,7 +40,9 @@
 520  #include <machine/metadata.h>
 521  
 522  #include "bootstrap.h"
 523 +#include "efichar.h"
 524  #include "framebuffer.h"
 525 +#include "gfx_fb.h"
 526  
 527  static EFI_GUID conout_guid = EFI_CONSOLE_OUT_DEVICE_GUID;
 528  EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
 529 @@ -53,6 +55,9 @@ static EFI_HANDLE gop_handle;
 530  /* Cached EDID. */
 531  struct vesa_edid_info *edid_info = NULL;
 532  
 533 +/* Angle to rotate boot console display. */
 534 +uint32_t rotation = 0;
 535 +
 536  static EFI_GRAPHICS_OUTPUT *gop;
 537  static EFI_UGA_DRAW_PROTOCOL *uga;
 538  
 539 @@ -149,11 +154,42 @@ efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode,
 540      EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info)
 541  {
 542  	int result;
 543 +	size_t len = 0;
 544 +	efi_char *buf;
 545 +	char *angle = NULL;
 546 +	EFI_STATUS rv;
 547 +
 548 +	/*
 549 +	 * Use the UEFI variable freebsd-LoaderRotate to rotate the framebuffer
 550 +	 * to match the panel orientation.  We use a UEFI variable because
 551 +	 * the framebuffer is set up very early in the boot process, before
 552 +	 * loader variables (even the early /boot/efi/EFI/FreeBSD/loader.env
 553 +	 * variables) are set up.
 554 +	 *
 555 +	 * It is intended that an rc.d script shall use the screen.rotate loader
 556 +	 * variable to update freebsd-LoaderRotate for the next boot.
 557 +	 */
 558 +	if (efi_freebsd_getenv("LoaderRotate", NULL, &len) == EFI_BUFFER_TOO_SMALL)
 559 +	    if ((buf = calloc(len + 1, sizeof(efi_char)))) {
 560 +		if (efi_freebsd_getenv("LoaderRotate", buf, &len) == EFI_SUCCESS)
 561 +		    if (ucs2_to_utf8(buf, &angle) == 0) {
 562 +			rotation = strtol(angle, NULL, 0);
 563 +			free(angle);
 564 +		    }
 565 +		free(buf);
 566 +	    }
 567 +	if (rotation != 90 && rotation != 180 && rotation != 270)
 568 +	    rotation = 0;
 569  
 570  	efifb->fb_addr = mode->FrameBufferBase;
 571  	efifb->fb_size = mode->FrameBufferSize;
 572 -	efifb->fb_height = info->VerticalResolution;
 573 -	efifb->fb_width = info->HorizontalResolution;
 574 +	if (rotation == 90 || rotation == 270) {
 575 +	    efifb->fb_width = info->VerticalResolution;
 576 +	    efifb->fb_height = info->HorizontalResolution;
 577 +	} else {
 578 +	    efifb->fb_height = info->VerticalResolution;
 579 +	    efifb->fb_width = info->HorizontalResolution;
 580 +	}
 581  	efifb->fb_stride = info->PixelsPerScanLine;
 582  	result = efifb_mask_from_pixfmt(efifb, info->PixelFormat,
 583  	    &info->PixelInformation);

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2024-04-24T03:39:05+0000, 5.8 KB) [[attachment:files_drm_510_kmod.shar]]
  • [get | view] (2024-04-24T01:23:12+0000, 19.2 KB) [[attachment:loader_rotate-13.3-RELEASE.diff]]
  • [get | view] (2024-04-24T01:23:51+0000, 0.6 KB) [[attachment:lua_commentparse-13.3-RELEASE.diff]]
  • [get | view] (2024-04-24T01:08:17+0000, 41.1 KB) [[attachment:multifix-13.3-RELEASE.diff]]
  • [get | view] (2024-04-24T01:24:12+0000, 0.6 KB) [[attachment:ntp-13.3-RELEASE.diff]]
  • [get | view] (2024-04-24T01:21:52+0000, 10.8 KB) [[attachment:thermal_management-13.3-RELEASE.diff]]
  • [get | view] (2024-04-24T01:23:36+0000, 2.9 KB) [[attachment:usb_hid_setprotocol-13.3-RELEASE.diff]]
  • [get | view] (2024-04-24T01:22:44+0000, 7.2 KB) [[attachment:vt_rotate-13.3-RELEASE.diff]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.