The Pedigree Project 0.1
modules/drivers/x86/uefi-gfx/main.cc
1/* Copyright (c) 2026, Pedigree Developers. SPDX-License-Identifier: ISC */
2
3#include "pedigree/kernel/BootstrapInfo.h"
4#include "pedigree/kernel/Service.h"
5#include "pedigree/kernel/ServiceFeatures.h"
6#include "pedigree/kernel/ServiceManager.h"
7#include "pedigree/kernel/graphics/Graphics.h"
8#include "pedigree/kernel/graphics/GraphicsService.h"
9#include "pedigree/kernel/machine/Display.h"
10#include "pedigree/kernel/machine/Framebuffer.h"
11#include "pedigree/kernel/processor/MemoryRegion.h"
12#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
13#include "pedigree/kernel/processor/VirtualAddressSpace.h"
14#include "pedigree/kernel/utilities/List.h"
15#include "pedigree/kernel/utilities/String.h"
16
17#include "modules/Module.h"
18
19namespace {
20
21class UefiFramebuffer final : public Framebuffer {
22 public:
23 UefiFramebuffer() : Framebuffer(), m_Region("UEFI GOP framebuffer"), m_Offset(0) {}
24
26 if (!info.address || !info.width || !info.height ||
27 info.pitch < static_cast<uint64_t>(info.width) * 4 || info.format > 1) {
28 return false;
29 }
30
31 const uint64_t bytes = static_cast<uint64_t>(info.pitch) * info.height;
32 if (!bytes || bytes > SIZE_MAX) {
33 return false;
34 }
35
36 const size_t pageSize = PhysicalMemoryManager::getPageSize();
37 m_Offset = info.address & (pageSize - 1);
38 const size_t pages = (static_cast<size_t>(bytes) + m_Offset + pageSize - 1) / pageSize;
40 m_Region, pages,
45 info.address - m_Offset)) {
46 return false;
47 }
48
49 setWidth(info.width);
50 setHeight(info.height);
51 setBytesPerPixel(4);
52 setBytesPerLine(info.pitch);
53 setFormat(info.format == 0 ? Graphics::Bits32_Bgr : Graphics::Bits32_Rgb);
54 setXPos(0);
55 setYPos(0);
56 setParent(0);
57 setFramebuffer(reinterpret_cast<uintptr_t>(m_Region.virtualAddress()) + m_Offset);
58 return true;
59 }
60
61 physical_uintptr_t getPhysicalPage(size_t offset) const override {
62 const size_t bytes = getHeight() * getBytesPerLine();
63 if (offset >= bytes) {
64 return ~physical_uintptr_t(0);
65 }
66
67 offset &= ~(PhysicalMemoryManager::getPageSize() - 1);
68 return m_Region.physicalAddress() + m_Offset + offset;
69 }
70
71 protected:
72 void hwRedraw(size_t, size_t, size_t, size_t) override {}
73
74 private:
75 MemoryRegion m_Region;
76 size_t m_Offset;
77};
78
79class UefiDisplay final : public Display {
80 public:
81 UefiDisplay(UefiFramebuffer* framebuffer, const BootstrapStruct_t::FramebufferInfo& info)
82 : Display(), m_pFramebuffer(framebuffer), m_Mode() {
83 m_Mode.id = 1;
84 m_Mode.width = info.width;
85 m_Mode.height = info.height;
86 m_Mode.refresh = 0;
87 m_Mode.framebuffer = info.address;
88 m_Mode.pf.mRed = 8;
89 m_Mode.pf.pRed = info.format == 0 ? 0 : 16;
90 m_Mode.pf.mGreen = 8;
91 m_Mode.pf.pGreen = 8;
92 m_Mode.pf.mBlue = 8;
93 m_Mode.pf.pBlue = info.format == 0 ? 16 : 0;
94 m_Mode.pf.mAlpha = 0;
95 m_Mode.pf.pAlpha = 24;
96 m_Mode.pf.nBpp = 32;
97 m_Mode.pf.nPitch = info.pitch;
98 m_Mode.pf2 = framebuffer->getFormat();
99 m_Mode.bytesPerLine = info.pitch;
100 m_Mode.bytesPerPixel = 4;
101 m_Mode.textMode = false;
102 setSpecificType(String("UEFI GOP display"));
103 }
104
105 void* getFramebuffer() override {
106 return m_pFramebuffer->getRawBuffer();
107 }
108
109 bool getPixelFormat(PixelFormat& format) override {
110 format = m_Mode.pf;
111 return true;
112 }
113
114 bool getCurrentScreenMode(ScreenMode& mode) override {
115 mode = m_Mode;
116 return true;
117 }
118
119 bool getScreenModes(List<ScreenMode*>& modes) override {
120 ScreenMode* mode = new ScreenMode(m_Mode);
121 if (!mode) {
122 return false;
123 }
124 modes.pushBack(mode);
125 return true;
126 }
127
128 bool setScreenMode(ScreenMode mode) override {
129 return mode.id == m_Mode.id && mode.width == m_Mode.width && mode.height == m_Mode.height &&
130 mode.pf.nBpp == m_Mode.pf.nBpp;
131 }
132
133 bool setScreenMode(size_t modeId) override {
134 // There is no VGA text mode to switch to after ExitBootServices(). Keep
135 // the firmware-selected GOP mode when clients request text mode.
136 return modeId == 0 || modeId == m_Mode.id;
137 }
138
139 bool setScreenMode(size_t width, size_t height, size_t bpp) override {
140 return width == m_Mode.width && height == m_Mode.height && bpp == m_Mode.pf.nBpp;
141 }
142
143 private:
144 UefiFramebuffer* m_pFramebuffer;
145 ScreenMode m_Mode;
146};
147
148UefiDisplay* g_pDisplay = nullptr;
149UefiFramebuffer* g_pFramebuffer = nullptr;
150GraphicsService::GraphicsProvider* g_pProvider = nullptr;
151
152bool entry() {
153 EMIT_IF(NOGFX) {
154 return false;
155 }
156
157 if (!g_pBootstrapInfo || !g_pBootstrapInfo->isUefi()) {
158 return false;
159 }
160
162 if (!g_pBootstrapInfo->getFramebuffer(info)) {
163 return false;
164 }
165
166 g_pFramebuffer = new UefiFramebuffer;
167 if (!g_pFramebuffer || !g_pFramebuffer->initialise(info)) {
168 delete g_pFramebuffer;
169 g_pFramebuffer = nullptr;
170 return false;
171 }
172
173 g_pDisplay = new UefiDisplay(g_pFramebuffer, info);
174 g_pProvider = new GraphicsService::GraphicsProvider;
175 if (!g_pDisplay || !g_pProvider) {
176 delete g_pProvider;
177 delete g_pDisplay;
178 delete g_pFramebuffer;
179 g_pProvider = nullptr;
180 g_pDisplay = nullptr;
181 g_pFramebuffer = nullptr;
182 return false;
183 }
184
185 g_pProvider->pDisplay = g_pDisplay;
186 g_pProvider->pFramebuffer = g_pFramebuffer;
187 g_pProvider->maxWidth = info.width;
188 g_pProvider->maxHeight = info.height;
189 g_pProvider->maxDepth = 32;
190 g_pProvider->maxTextWidth = 0;
191 g_pProvider->maxTextHeight = 0;
192 g_pProvider->bHardwareAccel = false;
193 g_pProvider->bTextModes = false;
194 g_pProvider->bFirmwareFallback = true;
195
196 ServiceFeatures* features = ServiceManager::instance().enumerateOperations(String("graphics"));
197 Service* service = ServiceManager::instance().getService(String("graphics"));
198 if (!features || !service || !features->provides(ServiceFeatures::touch) ||
199 !service->serve(ServiceFeatures::touch, g_pProvider, sizeof(*g_pProvider))) {
200 delete g_pProvider;
201 delete g_pDisplay;
202 delete g_pFramebuffer;
203 g_pProvider = nullptr;
204 g_pDisplay = nullptr;
205 g_pFramebuffer = nullptr;
206 return false;
207 }
208
209 NOTICE("UEFI GOP: registered fixed " << Dec << info.width << "x" << info.height << "x32 display");
210 return true;
211}
212
213void exit() {}
214
215} // namespace
216
217MODULE_INFO("uefi-gfx", &entry, &exit);
virtual void setSpecificType(String str)
Definition Device.h:187
virtual bool getPixelFormat(PixelFormat &pf)
Definition Display.cc:78
virtual void * getFramebuffer()
Definition Display.cc:58
virtual bool getCurrentScreenMode(ScreenMode &sm)
Definition Display.cc:82
virtual bool getScreenModes(List< ScreenMode * > &sms)
Definition Display.cc:86
virtual bool setScreenMode(ScreenMode sm)
Definition Display.cc:90
bool initialise()
Definition fb.cc:211
virtual void hwRedraw(size_t x=~0UL, size_t y=~0UL, size_t w=~0UL, size_t h=~0UL)
Inherited by drivers that provide a hardware redraw function.
virtual physical_uintptr_t getPhysicalPage(size_t offset) const
Definition List.h:61
Special memory entity in the kernel's virtual address space.
static PhysicalMemoryManager & instance()
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
virtual bool provides(Type service)
Service * getService(const String &serviceName)
ServiceFeatures * enumerateOperations(const String &serviceName)
virtual bool serve(ServiceFeatures::Type type, void *pData, size_t dataLen)=0
@ Dec
Definition Log.h:126
void pushBack(const T &value)
Definition List.h:216
bool bFirmwareFallback
Firmware scanout is a fallback once a native driver owns the display.