BL Library now works 100% in paging, protected mode. A picture is worth a thousand...
[reactos.git] / reactos / boot / environ / lib / io / display / efi / gop.c
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