• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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