xref: /reactos/boot/environ/lib/io/display/efi/gop.c (revision 1734f297)
1 /*
2  * COPYRIGHT:       See COPYING.ARM in the top level directory
3  * PROJECT:         ReactOS UEFI Boot Library
4  * FILE:            boot/environ/lib/io/display/efi/gop.c
5  * PURPOSE:         Boot Library EFI GOP Routines
6  * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include "bl.h"
12 
13 /* DATA VARIABLES ************************************************************/
14 
15 /* FUNCTIONS *****************************************************************/
16 
17 NTSTATUS
18 ConsoleEfiGopGetGraphicalFormat (
19     _In_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo,
20     _Out_ PULONG PixelDepth
21     )
22 {
23     /* Convert the format to depth */
24     if (ModeInfo->PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
25     {
26         *PixelDepth = 32;
27         return STATUS_SUCCESS;
28     }
29     if (ModeInfo->PixelFormat == PixelBitMask)
30     {
31         *PixelDepth = 24;
32         return STATUS_SUCCESS;
33     }
34     return STATUS_UNSUCCESSFUL;
35 }
36 
37 BOOLEAN
38 ConsoleEfiGopIsPixelFormatSupported (
39     _In_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode
40     )
41 {
42     BOOLEAN Supported;
43     EFI_PIXEL_BITMASK PixelMask;
44 
45     Supported = FALSE;
46 
47     /* Check if it's simple BGR8 */
48     if (Mode->PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
49     {
50         Supported = TRUE;
51     }
52     else
53     {
54         /* Otherwise, we can check if it's a masked format */
55         if (Mode->PixelFormat == PixelBitMask)
56         {
57             /* Check if the masked format is BGR8 */
58             PixelMask.BlueMask = 0xFF;
59             PixelMask.GreenMask = 0xFF00;
60             PixelMask.RedMask = 0xFF0000;
61             PixelMask.ReservedMask = 0;
62             if (RtlEqualMemory(&Mode->PixelInformation,
63                 &PixelMask,
64                 sizeof(PixelMask)))
65             {
66                 Supported = TRUE;
67             }
68         }
69     }
70 
71     /* Return if the format was supported */
72     return Supported;
73 }
74 
75 
76 NTSTATUS
77 ConsoleEfiGopFindModeFromAllowed (
78     _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopProtocol,
79     _In_ PBL_DISPLAY_MODE SupportedModes,
80     _In_ ULONG MaximumIndex,
81     _Out_ PULONG SupportedMode
82     )
83 {
84     return STATUS_NOT_IMPLEMENTED;
85 }
86 
87 NTSTATUS
88 ConsoleEfiGopEnable (
89     _In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
90     )
91 {
92     PVOID FrameBuffer;
93     UINTN CurrentMode, Dummy;
94     ULONG Mode, PixelDepth;
95     UINTN FrameBufferSize;
96     EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInformation;
97     EFI_GRAPHICS_OUTPUT_PROTOCOL* Protocol;
98     NTSTATUS Status;
99     PHYSICAL_ADDRESS FrameBufferPhysical;
100 
101     /* Capture the current mode and protocol */
102     Mode = GraphicsConsole->Mode;
103     Protocol = GraphicsConsole->Protocol;
104 
105     /* Get the current mode and its information */
106     Status = EfiGopGetCurrentMode(Protocol, &CurrentMode, &ModeInformation);
107     if (!NT_SUCCESS(Status))
108     {
109         return Status;
110     }
111 
112     /* Check if we're not in the mode we should be */
113     if (CurrentMode != Mode)
114     {
115         /* Switch modes */
116         Status = EfiGopSetMode(Protocol, Mode);
117         if (!NT_SUCCESS(Status))
118         {
119             return Status;
120         }
121 
122         /* Reset the OEM bitmap and get the new more information */
123         BlDisplayInvalidateOemBitmap();
124         EfiGopGetCurrentMode(Protocol, &Dummy, &ModeInformation);
125     }
126 
127     /* Get the pixel depth for this mode */
128     Status = ConsoleEfiGopGetGraphicalFormat(&ModeInformation, &PixelDepth);
129     if (NT_SUCCESS(Status))
130     {
131         /* Get the framebuffer for this mode */
132         EfiGopGetFrameBuffer(Protocol, &FrameBufferPhysical, &FrameBufferSize);
133 
134         /* Map the framebuffer, try as writeback first */
135         FrameBuffer = NULL;
136         Status = BlMmMapPhysicalAddressEx(&FrameBuffer,
137                                           BlMemoryWriteBack,
138                                           FrameBufferSize,
139                                           FrameBufferPhysical);
140         if (!NT_SUCCESS(Status))
141         {
142             /* That didn't work, so try uncached next */
143             Status = BlMmMapPhysicalAddressEx(&FrameBuffer,
144                                               BlMemoryUncached,
145                                               FrameBufferSize,
146                                               FrameBufferPhysical);
147         }
148     }
149 
150     /* Check if getting all the required information worked out */
151     if (NT_SUCCESS(Status))
152     {
153         /* Capture the resolution, depth, and framebuffer information */
154         GraphicsConsole->DisplayMode.HRes = ModeInformation.HorizontalResolution;
155         GraphicsConsole->DisplayMode.VRes = ModeInformation.VerticalResolution;
156         GraphicsConsole->DisplayMode.HRes2 = ModeInformation.PixelsPerScanLine;
157         GraphicsConsole->PixelDepth = PixelDepth;
158         GraphicsConsole->FrameBuffer = FrameBuffer;
159         GraphicsConsole->FrameBufferSize = FrameBufferSize;
160         GraphicsConsole->PixelsPerScanLine = ModeInformation.PixelsPerScanLine;
161 
162         /* All good */
163         Status = STATUS_SUCCESS;
164     }
165     else if (CurrentMode != GraphicsConsole->Mode)
166     {
167         /* We failed somewhere, reset the mode and the OEM bitmap back */
168         EfiGopSetMode(Protocol, CurrentMode);
169         BlDisplayInvalidateOemBitmap();
170     }
171 
172     /* Return back to caller */
173     return Status;
174 }
175 
176 VOID
177 ConsoleEfiGopClose (
178     _In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
179     )
180 {
181     ULONG OldMode;
182 
183     /* Did we switch modes when we turned on the console? */
184     OldMode = GraphicsConsole->OldMode;
185     if (GraphicsConsole->Mode != OldMode)
186     {
187         /* Restore the old mode and reset the OEM bitmap in ACPI */
188         EfiGopSetMode(GraphicsConsole->Protocol, OldMode);
189         BlDisplayInvalidateOemBitmap();
190     }
191 
192     /* Close the GOP protocol */
193     EfiCloseProtocol(GraphicsConsole->Handle,
194                      &EfiGraphicsOutputProtocol);
195 }
196 
197 NTSTATUS
198 ConsoleEfiGopOpen (
199     _In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
200     )
201 {
202     NTSTATUS Status;
203     EFI_GRAPHICS_OUTPUT_PROTOCOL *GopProtocol;
204     ULONG Mode, PixelDepth;
205     UINTN CurrentMode;
206     EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInformation;
207     BOOLEAN CurrentModeOk;
208 
209     /* Open a handle to GOP */
210     Status = EfiOpenProtocol(GraphicsConsole->Handle,
211                              &EfiGraphicsOutputProtocol,
212                              (PVOID*)&GopProtocol);
213     if (!NT_SUCCESS(Status))
214     {
215         EfiPrintf(L"GOP OPEN failed: %lx\r\n", Status);
216         return STATUS_NOT_SUPPORTED;
217     }
218 
219     /* Get the current mode */
220     Status = EfiGopGetCurrentMode(GopProtocol, &CurrentMode, &ModeInformation);
221     if (!NT_SUCCESS(Status))
222     {
223         EfiPrintf(L"GOP mode failed: %lx\r\n", Status);
224         goto Quickie;
225     }
226 
227     Mode = CurrentMode;
228 
229     /* Check if any custom BCD options were provided */
230     if (ConsoleGraphicalResolutionListFlags &
231         (BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG |
232          BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG))
233     {
234         /* We'll have to find a mode */
235         CurrentModeOk = FALSE;
236     }
237     else
238     {
239         /* Then we should be in the default mode, check if the pixel format is OK */
240         CurrentModeOk = ConsoleEfiGopIsPixelFormatSupported(&ModeInformation);
241     }
242 
243     /* Is the mode/format OK? */
244     if (!CurrentModeOk)
245     {
246         /* Nope -- we'll have to go find one */
247         Status = ConsoleEfiGopFindModeFromAllowed(GopProtocol,
248                                                   ConsoleGraphicalResolutionList,
249                                                   ConsoleGraphicalResolutionListSize,
250                                                   &Mode);
251         if (!NT_SUCCESS(Status))
252         {
253             goto Quickie;
254         }
255     }
256 
257     /* Store mode information */
258     GraphicsConsole->Protocol = GopProtocol;
259     GraphicsConsole->Mode = Mode;
260     GraphicsConsole->OldMode = CurrentMode;
261 
262     /* Get format information */
263     Status = ConsoleEfiGopGetGraphicalFormat(&ModeInformation, &PixelDepth);
264     if (NT_SUCCESS(Status))
265     {
266         /* Store it */
267         GraphicsConsole->OldDisplayMode.HRes = ModeInformation.HorizontalResolution;
268         GraphicsConsole->OldDisplayMode.VRes = ModeInformation.VerticalResolution;
269         GraphicsConsole->OldDisplayMode.HRes2 = ModeInformation.PixelsPerScanLine;
270         GraphicsConsole->PixelDepth = PixelDepth;
271         return STATUS_SUCCESS;
272     }
273 
274 Quickie:
275     /* We failed, close the protocol and return the failure code */
276     EfiPrintf(L"Get format failed: %lx\r\n", Status);
277     EfiCloseProtocol(GraphicsConsole->Handle, &EfiGraphicsOutputProtocol);
278     return Status;
279 }
280 
281