xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/apps/lfbgrid.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /*	$NetBSD: lfbgrid.c,v 1.1.1.2 2021/09/30 18:50:09 jmcneill Exp $	*/
2 
3 #include <efi.h>
4 #include <efilib.h>
5 
6 extern EFI_GUID GraphicsOutputProtocol;
7 
8 #define be32_to_cpu(x) __builtin_bswap32(x)
9 
10 static void
11 fill_boxes(UINT32 *PixelBuffer, UINT32 Width, UINT32 Height, UINT32 Pitch,
12 	   EFI_GRAPHICS_PIXEL_FORMAT Format, EFI_PIXEL_BITMASK Info )
13 {
14 	UINT32 Red, Green;
15 	UINT32 y, x, color;
16 
17 	switch(Format) {
18 	case PixelRedGreenBlueReserved8BitPerColor:
19 		Red = be32_to_cpu(0xff000000);
20 		Green = be32_to_cpu(0x00ff0000);
21 		break;
22 	case PixelBlueGreenRedReserved8BitPerColor:
23 		Red = be32_to_cpu(0x0000ff00);
24 		Green = be32_to_cpu(0x00ff0000);
25 		break;
26 	case PixelBitMask:
27 		Red = Info.RedMask;
28 		Green = Info.GreenMask;
29 		break;
30 	case PixelBltOnly:
31 		return;
32 	default:
33 		Print(L"Invalid pixel format\n");
34 		return;
35 	}
36 
37 	for (y = 0; y < Height; y++) {
38 		color = ((y / 32) % 2 == 0) ? Red : Green;
39 		for (x = 0; x < Width; x++) {
40 			if (x % 32 == 0 && x != 0)
41 				color = (color == Red) ? Green : Red;
42 			PixelBuffer[y * Pitch + x] = color;
43 		}
44 	}
45 }
46 
47 static void
48 draw_boxes(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
49 {
50 	int i, imax;
51 	EFI_STATUS rc;
52 	EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
53 	UINTN NumPixels;
54 	UINT32 *PixelBuffer;
55 	UINT32 CopySize, BufferSize;
56 #if defined(__x86_64__) || defined(__aarch64__) || \
57     (defined (__riscv) && __riscv_xlen == 64)
58 	UINT64 FrameBufferAddr;
59 #elif defined(__i386__) || defined(__arm__)
60 	UINT32 FrameBufferAddr;
61 #else
62 #error YOUR ARCH HERE
63 #endif
64 
65 	if (gop->Mode) {
66 		imax = gop->Mode->MaxMode;
67 	} else {
68 		Print(L"gop->Mode is NULL\n");
69 		return;
70 	}
71 
72 	for (i = 0; i < imax; i++) {
73 		UINTN SizeOfInfo;
74 		rc = uefi_call_wrapper(gop->QueryMode, 4, gop, i, &SizeOfInfo,
75 					&info);
76 		if (rc == EFI_NOT_STARTED) {
77 			Print(L"gop->QueryMode() returned %r\n", rc);
78 			Print(L"Trying to start GOP with SetMode().\n");
79 			rc = uefi_call_wrapper(gop->SetMode, 2, gop,
80 				gop->Mode ? gop->Mode->Mode : 0);
81 			rc = uefi_call_wrapper(gop->QueryMode, 4, gop, i,
82 				&SizeOfInfo, &info);
83 		}
84 
85 		if (EFI_ERROR(rc)) {
86 			Print(L"%d: Bad response from QueryMode: %r (%d)\n",
87 			      i, rc, rc);
88 			continue;
89 		}
90 
91 		if (CompareMem(info, gop->Mode->Info, sizeof (*info)))
92 			continue;
93 
94 		NumPixels = info->VerticalResolution * info->PixelsPerScanLine;
95 		BufferSize = NumPixels * sizeof(UINT32);
96 		if (BufferSize == gop->Mode->FrameBufferSize) {
97 			CopySize = BufferSize;
98 		} else {
99 			CopySize = BufferSize < gop->Mode->FrameBufferSize ?
100 				BufferSize : gop->Mode->FrameBufferSize;
101 			Print(L"height * pitch * pixelsize = %lu buf fb size is %lu; using %lu\n",
102 			      BufferSize, gop->Mode->FrameBufferSize, CopySize);
103 		}
104 
105 		PixelBuffer = AllocatePool(BufferSize);
106 		if (!PixelBuffer) {
107 			Print(L"Allocation of 0x%08lx bytes failed.\n",
108 			      sizeof(UINT32) * NumPixels);
109 			return;
110 		}
111 
112 		fill_boxes(PixelBuffer, info->HorizontalResolution,
113 			   info->VerticalResolution, info->PixelsPerScanLine,
114 			   info->PixelFormat, info->PixelInformation);
115 
116 		if (info->PixelFormat == PixelBltOnly) {
117 			Print(L"No linear framebuffer on this device.\n");
118 			return;
119 		}
120 #if defined(__x86_64__) || defined(__aarch64__) || \
121     (defined (__riscv) && __riscv_xlen == 64)
122 		FrameBufferAddr = (UINT64)gop->Mode->FrameBufferBase;
123 #elif defined(__i386__) || defined(__arm__)
124 		FrameBufferAddr = (UINT32)(UINT64)gop->Mode->FrameBufferBase;
125 #else
126 #error YOUR ARCH HERE
127 #endif
128 
129 		CopyMem((VOID *)FrameBufferAddr, PixelBuffer, CopySize);
130 		return;
131 	}
132 	Print(L"Never found the active video mode?\n");
133 }
134 
135 static EFI_STATUS
136 SetWatchdog(UINTN seconds)
137 {
138 	EFI_STATUS rc;
139 	rc = uefi_call_wrapper(BS->SetWatchdogTimer, 4, seconds, 0x1ffff,
140 				0, NULL);
141 	if (EFI_ERROR(rc)) {
142 		CHAR16 Buffer[64];
143 		StatusToString(Buffer, rc);
144 		Print(L"Bad response from QueryMode: %s (%d)\n", Buffer, rc);
145 	}
146 	return rc;
147 }
148 
149 EFI_STATUS
150 efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
151 {
152 	EFI_STATUS rc;
153 	EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
154 
155 	InitializeLib(image_handle, systab);
156 
157 	SetWatchdog(10);
158 
159 	rc = LibLocateProtocol(&GraphicsOutputProtocol, (void **)&gop);
160 	if (EFI_ERROR(rc)) {
161 		Print(L"Could not locate GOP: %r\n", rc);
162 		return rc;
163 	}
164 
165 	if (!gop) {
166 		Print(L"LocateProtocol(GOP, &gop) returned %r but GOP is NULL\n", rc);
167 		return EFI_UNSUPPORTED;
168 	}
169 
170 	draw_boxes(gop);
171 
172 	SetWatchdog(0);
173 	return EFI_SUCCESS;
174 }
175