lfbgrid.c revision 1.1.1.2 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