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.You are not allowed to attach a file to this page.