1 /*
2 * Copyright 2011-2014 Intel Corporation - All Rights Reserved
3 */
4
5 #include <syslinux/linux.h>
6 #include "efi.h"
7 #include <string.h>
8
9 extern EFI_GUID GraphicsOutputProtocol;
10
11 static uint32_t console_default_attribute;
12 static bool console_default_cursor;
13
14 /*
15 * We want to restore the console state when we boot a kernel or return
16 * to the firmware.
17 */
efi_console_save(void)18 void efi_console_save(void)
19 {
20 SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
21 SIMPLE_TEXT_OUTPUT_MODE *mode = out->Mode;
22
23 console_default_attribute = mode->Attribute;
24 console_default_cursor = mode->CursorVisible;
25 }
26
efi_console_restore(void)27 void efi_console_restore(void)
28 {
29 SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
30
31 uefi_call_wrapper(out->SetAttribute, 2, out, console_default_attribute);
32 uefi_call_wrapper(out->EnableCursor, 2, out, console_default_cursor);
33 }
34
writechr(char data)35 __export void writechr(char data)
36 {
37 efi_write_char(data, 0);
38 }
39
open_protocol(EFI_HANDLE handle,EFI_GUID * protocol,void ** interface,EFI_HANDLE agent,EFI_HANDLE controller,UINT32 attributes)40 static inline EFI_STATUS open_protocol(EFI_HANDLE handle, EFI_GUID *protocol,
41 void **interface, EFI_HANDLE agent,
42 EFI_HANDLE controller, UINT32 attributes)
43 {
44 return uefi_call_wrapper(BS->OpenProtocol, 6, handle, protocol,
45 interface, agent, controller, attributes);
46 }
47
48 static inline EFI_STATUS
gop_query_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL * gop,UINTN * size,EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** info)49 gop_query_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN *size,
50 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **info)
51 {
52 return uefi_call_wrapper(gop->QueryMode, 4, gop,
53 gop->Mode->Mode, size, info);
54 }
55
bit_mask(uint32_t mask,uint8_t * pos,uint8_t * size)56 static inline void bit_mask(uint32_t mask, uint8_t *pos, uint8_t *size)
57 {
58 *pos = 0;
59 *size = 0;
60
61 if (mask) {
62 while (!(mask & 0x1)) {
63 mask >>= 1;
64 (*pos)++;
65 }
66
67 while (mask & 0x1) {
68 mask >>= 1;
69 (*size)++;
70 }
71 }
72 }
73
setup_gop(struct screen_info * si)74 static int setup_gop(struct screen_info *si)
75 {
76 EFI_HANDLE *handles = NULL;
77 EFI_STATUS status;
78 EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, *found;
79 EFI_GRAPHICS_PIXEL_FORMAT pixel_fmt;
80 EFI_PIXEL_BITMASK pixel_info;
81 uint32_t pixel_scanline;
82 UINTN i, nr_handles;
83 UINTN size;
84 uint16_t lfb_width, lfb_height;
85 uint32_t lfb_base, lfb_size;
86 int err = 0;
87 void **gop_handle = NULL;
88
89 size = 0;
90 status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &GraphicsOutputProtocol,
91 NULL, &size, gop_handle);
92 /* LibLocateHandle handle already returns the number of handles.
93 * There is no need to divide by sizeof(EFI_HANDLE)
94 */
95 status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
96 NULL, &nr_handles, &handles);
97 if (status == EFI_BUFFER_TOO_SMALL) {
98
99 handles = AllocatePool(nr_handles);
100 if (!handles)
101 return 0;
102
103 status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
104 NULL, &nr_handles, &handles);
105 }
106 if (status != EFI_SUCCESS)
107 goto out;
108
109 found = NULL;
110 for (i = 0; i < nr_handles; i++) {
111 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
112 EFI_PCI_IO *pciio = NULL;
113 EFI_HANDLE *h = handles[i];
114
115 status = uefi_call_wrapper(BS->HandleProtocol, 3, h,
116 &GraphicsOutputProtocol, (void **)&gop);
117 if (status != EFI_SUCCESS)
118 continue;
119 uefi_call_wrapper(BS->HandleProtocol, 3, h,
120 &PciIoProtocol, (void **)&pciio);
121 status = gop_query_mode(gop, &size, &info);
122 if (status == EFI_SUCCESS && (!found || pciio)) {
123 lfb_width = info->HorizontalResolution;
124 lfb_height = info->VerticalResolution;
125 lfb_base = gop->Mode->FrameBufferBase;
126 lfb_size = gop->Mode->FrameBufferSize;
127 pixel_fmt = info->PixelFormat;
128 pixel_info = info->PixelInformation;
129 pixel_scanline = info->PixelsPerScanLine;
130 if (pciio)
131 break;
132 found = gop;
133 }
134 }
135
136 if (!found)
137 goto out;
138
139 err = 1;
140
141 dprintf("setup_screen: set up screen parameters for EFI GOP\n");
142 si->orig_video_isVGA = 0x70; /* EFI framebuffer */
143
144 si->lfb_base = lfb_base;
145 si->lfb_size = lfb_size;
146 si->lfb_width = lfb_width;
147 si->lfb_height = lfb_height;
148 si->pages = 1;
149
150 dprintf("setup_screen: lfb_base 0x%x lfb_size %d lfb_width %d lfb_height %d\n", lfb_base, lfb_size, lfb_width, lfb_height);
151 switch (pixel_fmt) {
152 case PixelRedGreenBlueReserved8BitPerColor:
153 si->lfb_depth = 32;
154 si->lfb_linelength = pixel_scanline * 4;
155 si->red_size = 8;
156 si->red_pos = 0;
157 si->green_size = 8;
158 si->green_pos = 8;
159 si->blue_size = 8;
160 si->blue_pos = 16;
161 si->rsvd_size = 8;
162 si->rsvd_pos = 24;
163 break;
164 case PixelBlueGreenRedReserved8BitPerColor:
165 si->lfb_depth = 32;
166 si->lfb_linelength = pixel_scanline * 4;
167 si->red_size = 8;
168 si->red_pos = 16;
169 si->green_size = 8;
170 si->green_pos = 8;
171 si->blue_size = 8;
172 si->blue_pos = 0;
173 si->rsvd_size = 8;
174 si->rsvd_pos = 24;
175 break;
176 case PixelBitMask:
177 bit_mask(pixel_info.RedMask, &si->red_pos,
178 &si->red_size);
179 bit_mask(pixel_info.GreenMask, &si->green_pos,
180 &si->green_size);
181 bit_mask(pixel_info.BlueMask, &si->blue_pos,
182 &si->blue_size);
183 bit_mask(pixel_info.ReservedMask, &si->rsvd_pos,
184 &si->rsvd_size);
185 si->lfb_depth = si->red_size + si->green_size +
186 si->blue_size + si->rsvd_size;
187 si->lfb_linelength = (pixel_scanline * si->lfb_depth) / 8;
188 break;
189 default:
190 si->lfb_depth = 4;;
191 si->lfb_linelength = si->lfb_width / 2;
192 si->red_size = 0;
193 si->red_pos = 0;
194 si->green_size = 0;
195 si->green_pos = 0;
196 si->blue_size = 0;
197 si->blue_pos = 0;
198 si->rsvd_size = 0;
199 si->rsvd_pos = 0;
200 break;
201 }
202 dprintf("setup_screen: depth %d line %d rpos %d rsize %d gpos %d gsize %d bpos %d bsize %d rsvpos %d rsvsize %d\n",
203 si->lfb_depth, si->lfb_linelength,
204 si->red_pos, si->red_size,
205 si->green_pos, si->green_size,
206 si->blue_pos, si->blue_size,
207 si->blue_pos, si->blue_size,
208 si->rsvd_pos, si->rsvd_size);
209
210 out:
211 if (handles) FreePool(handles);
212
213 return err;
214 }
215
216 #define EFI_UGA_PROTOCOL_GUID \
217 { \
218 0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 } \
219 }
220
221 typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL;
222
223 typedef
224 EFI_STATUS
225 (EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) (
226 IN EFI_UGA_DRAW_PROTOCOL *This,
227 OUT UINT32 *Width,
228 OUT UINT32 *Height,
229 OUT UINT32 *Depth,
230 OUT UINT32 *Refresh
231 )
232 ;
233
234 struct _EFI_UGA_DRAW_PROTOCOL {
235 EFI_UGA_DRAW_PROTOCOL_GET_MODE GetMode;
236 void *SetMode;
237 void *Blt;
238 };
239
setup_uga(struct screen_info * si)240 static int setup_uga(struct screen_info *si)
241 {
242 EFI_UGA_DRAW_PROTOCOL *uga, *first;
243 EFI_GUID UgaProtocol = EFI_UGA_PROTOCOL_GUID;
244 UINT32 width, height;
245 EFI_STATUS status;
246 EFI_HANDLE *handles;
247 UINTN i, nr_handles;
248 int rv = 0;
249
250 status = LibLocateHandle(ByProtocol, &UgaProtocol,
251 NULL, &nr_handles, &handles);
252 if (status != EFI_SUCCESS)
253 return rv;
254
255 for (i = 0; i < nr_handles; i++) {
256 EFI_PCI_IO *pciio = NULL;
257 EFI_HANDLE *handle = handles[i];
258 UINT32 w, h, depth, refresh;
259
260 status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
261 &UgaProtocol, (void **)&uga);
262 if (status != EFI_SUCCESS)
263 continue;
264
265 uefi_call_wrapper(BS->HandleProtocol, 3, handle,
266 &PciIoProtocol, (void **)&pciio);
267
268 status = uefi_call_wrapper(uga->GetMode, 5, uga, &w, &h,
269 &depth, &refresh);
270
271 if (status == EFI_SUCCESS && (!first || pciio)) {
272 width = w;
273 height = h;
274
275 if (pciio)
276 break;
277
278 first = uga;
279 }
280 }
281
282 if (!first)
283 goto out;
284 rv = 1;
285
286 si->orig_video_isVGA = 0x70; /* EFI framebuffer */
287
288 si->lfb_depth = 32;
289 si->lfb_width = width;
290 si->lfb_height = height;
291
292 si->red_size = 8;
293 si->red_pos = 16;
294 si->green_size = 8;
295 si->green_pos = 8;
296 si->blue_size = 8;
297 si->blue_pos = 0;
298 si->rsvd_size = 8;
299 si->rsvd_pos = 24;
300
301 out:
302 FreePool(handles);
303 return rv;
304 }
305
setup_screen(struct screen_info * si)306 void setup_screen(struct screen_info *si)
307 {
308 memset(si, 0, sizeof(*si));
309
310 if (!setup_gop(si))
311 setup_uga(si);
312 }
313