[FREELDR][XBOXVMP] Check only low 28 bits for framebuffer address (#2249)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / xboxvideo.c
1 /*
2 * FreeLoader
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Note: much of this code was based on knowledge and/or code developed
19 * by the Xbox Linux group: http://www.xbox-linux.org
20 */
21
22 #include <freeldr.h>
23 #include <debug.h>
24
25 DBG_DEFAULT_CHANNEL(UI);
26
27 PVOID FrameBuffer;
28 ULONG FrameBufferSize;
29 static ULONG ScreenWidth;
30 static ULONG ScreenHeight;
31 static ULONG BytesPerPixel;
32 static ULONG Delta;
33 extern multiboot_info_t * MultibootInfoPtr;
34
35 #define CHAR_WIDTH 8
36 #define CHAR_HEIGHT 16
37
38 #define TOP_BOTTOM_LINES 0
39
40 #define FB_SIZE_MB 4
41
42 #define MAKE_COLOR(Red, Green, Blue) (0xff000000 | (((Red) & 0xff) << 16) | (((Green) & 0xff) << 8) | ((Blue) & 0xff))
43
44 static VOID
45 XboxVideoOutputChar(UCHAR Char, unsigned X, unsigned Y, ULONG FgColor, ULONG BgColor)
46 {
47 PUCHAR FontPtr;
48 PULONG Pixel;
49 UCHAR Mask;
50 unsigned Line;
51 unsigned Col;
52
53 FontPtr = XboxFont8x16 + Char * 16;
54 Pixel = (PULONG) ((char *) FrameBuffer + (Y * CHAR_HEIGHT + TOP_BOTTOM_LINES) * Delta
55 + X * CHAR_WIDTH * BytesPerPixel);
56 for (Line = 0; Line < CHAR_HEIGHT; Line++)
57 {
58 Mask = 0x80;
59 for (Col = 0; Col < CHAR_WIDTH; Col++)
60 {
61 Pixel[Col] = (0 != (FontPtr[Line] & Mask) ? FgColor : BgColor);
62 Mask = Mask >> 1;
63 }
64 Pixel = (PULONG) ((char *) Pixel + Delta);
65 }
66 }
67
68 static ULONG
69 XboxVideoAttrToSingleColor(UCHAR Attr)
70 {
71 UCHAR Intensity;
72
73 Intensity = (0 == (Attr & 0x08) ? 127 : 255);
74
75 return 0xff000000 |
76 (0 == (Attr & 0x04) ? 0 : (Intensity << 16)) |
77 (0 == (Attr & 0x02) ? 0 : (Intensity << 8)) |
78 (0 == (Attr & 0x01) ? 0 : Intensity);
79 }
80
81 static VOID
82 XboxVideoAttrToColors(UCHAR Attr, ULONG *FgColor, ULONG *BgColor)
83 {
84 *FgColor = XboxVideoAttrToSingleColor(Attr & 0xf);
85 *BgColor = XboxVideoAttrToSingleColor((Attr >> 4) & 0xf);
86 }
87
88 static VOID
89 XboxVideoClearScreenColor(ULONG Color, BOOLEAN FullScreen)
90 {
91 ULONG Line, Col;
92 PULONG p;
93
94 for (Line = 0; Line < ScreenHeight - (FullScreen ? 0 : 2 * TOP_BOTTOM_LINES); Line++)
95 {
96 p = (PULONG) ((char *) FrameBuffer + (Line + (FullScreen ? 0 : TOP_BOTTOM_LINES)) * Delta);
97 for (Col = 0; Col < ScreenWidth; Col++)
98 {
99 *p++ = Color;
100 }
101 }
102 }
103
104 VOID
105 XboxVideoClearScreen(UCHAR Attr)
106 {
107 ULONG FgColor, BgColor;
108
109 XboxVideoAttrToColors(Attr, &FgColor, &BgColor);
110
111 XboxVideoClearScreenColor(BgColor, FALSE);
112 }
113
114 VOID
115 XboxVideoPutChar(int Ch, UCHAR Attr, unsigned X, unsigned Y)
116 {
117 ULONG FgColor, BgColor;
118
119 XboxVideoAttrToColors(Attr, &FgColor, &BgColor);
120
121 XboxVideoOutputChar(Ch, X, Y, FgColor, BgColor);
122 }
123
124 UCHAR
125 NvGetCrtc(UCHAR Index)
126 {
127 *((PUCHAR) NV2A_CRTC_REGISTER_INDEX) = Index;
128 return *((PUCHAR) NV2A_CRTC_REGISTER_VALUE);
129 }
130
131 ULONG
132 XboxGetFramebufferSize(PVOID Offset)
133 {
134 memory_map_t * MemoryMap;
135 INT Count, i;
136
137 if (!MultibootInfoPtr)
138 {
139 return 0;
140 }
141
142 if (!(MultibootInfoPtr->flags & MB_INFO_FLAG_MEMORY_MAP))
143 {
144 return 0;
145 }
146
147 MemoryMap = (memory_map_t *)MultibootInfoPtr->mmap_addr;
148
149 if (!MemoryMap ||
150 MultibootInfoPtr->mmap_length == 0 ||
151 MultibootInfoPtr->mmap_length % sizeof(memory_map_t) != 0)
152 {
153 return 0;
154 }
155
156 Count = MultibootInfoPtr->mmap_length / sizeof(memory_map_t);
157 for (i = 0; i < Count; i++, MemoryMap++)
158 {
159 TRACE("i = %d, base_addr_low = 0x%p, MemoryMap->length_low = 0x%p\n", i, MemoryMap->base_addr_low, MemoryMap->length_low);
160
161 /* Framebuffer address offset value is coming from the GPU within
162 * memory mapped I/O address space, so we're comparing only low
163 * 28 bits of the address within actual RAM address space */
164 if (MemoryMap->base_addr_low == ((ULONG)Offset & 0x0FFFFFFF) && MemoryMap->base_addr_high == 0)
165 {
166 TRACE("Video memory found\n");
167 return MemoryMap->length_low;
168 }
169 }
170 ERR("Video memory not found!\n");
171 return 0;
172 }
173
174 VOID
175 XboxVideoInit(VOID)
176 {
177 /* Reuse framebuffer that was set up by firmware */
178 FrameBuffer = (PVOID)*((PULONG) NV2A_CRTC_FRAMEBUFFER_START);
179 /* Verify that framebuffer address is page-aligned */
180 ASSERT((ULONG_PTR)FrameBuffer % PAGE_SIZE == 0);
181
182 /* Obtain framebuffer memory size from multiboot memory map */
183 if ((FrameBufferSize = XboxGetFramebufferSize(FrameBuffer)) == 0)
184 {
185 /* Fallback to Cromwell standard which reserves high 4 MB of RAM */
186 FrameBufferSize = 4 * 1024 * 1024;
187 WARN("Could not detect framebuffer memory size, fallback to 4 MB\n");
188 }
189
190 ScreenWidth = *((PULONG) NV2A_RAMDAC_FP_HVALID_END) + 1;
191 ScreenHeight = *((PULONG) NV2A_RAMDAC_FP_VVALID_END) + 1;
192 /* Get BPP directly from NV2A CRTC (magic constants are from Cromwell) */
193 BytesPerPixel = 8 * (((NvGetCrtc(0x19) & 0xE0) << 3) | (NvGetCrtc(0x13) & 0xFF)) / ScreenWidth;
194 if (BytesPerPixel == 4)
195 {
196 ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel - 1);
197 }
198 else
199 {
200 ASSERT((NvGetCrtc(0x28) & 0xF) == BytesPerPixel);
201 }
202 Delta = (ScreenWidth * BytesPerPixel + 3) & ~ 0x3;
203
204 /* Verify screen resolution */
205 ASSERT(ScreenWidth > 1);
206 ASSERT(ScreenHeight > 1);
207 ASSERT(BytesPerPixel >= 1 && BytesPerPixel <= 4);
208 /* Verify that screen fits framebuffer size */
209 ASSERT(ScreenWidth * ScreenHeight * BytesPerPixel <= FrameBufferSize);
210
211 XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
212 }
213
214 VIDEODISPLAYMODE
215 XboxVideoSetDisplayMode(char *DisplayMode, BOOLEAN Init)
216 {
217 /* We only have one mode, semi-text */
218 return VideoTextMode;
219 }
220
221 VOID
222 XboxVideoGetDisplaySize(PULONG Width, PULONG Height, PULONG Depth)
223 {
224 *Width = ScreenWidth / CHAR_WIDTH;
225 *Height = (ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT;
226 *Depth = 0;
227 }
228
229 ULONG
230 XboxVideoGetBufferSize(VOID)
231 {
232 return (ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT * (ScreenWidth / CHAR_WIDTH) * 2;
233 }
234
235 VOID
236 XboxVideoGetFontsFromFirmware(PULONG RomFontPointers)
237 {
238 TRACE("XboxVideoGetFontsFromFirmware(): UNIMPLEMENTED\n");
239 }
240
241 VOID
242 XboxVideoSetTextCursorPosition(UCHAR X, UCHAR Y)
243 {
244 /* We don't have a cursor yet */
245 }
246
247 VOID
248 XboxVideoHideShowTextCursor(BOOLEAN Show)
249 {
250 /* We don't have a cursor yet */
251 }
252
253 VOID
254 XboxVideoCopyOffScreenBufferToVRAM(PVOID Buffer)
255 {
256 PUCHAR OffScreenBuffer = (PUCHAR) Buffer;
257 ULONG Col, Line;
258
259 for (Line = 0; Line < (ScreenHeight - 2 * TOP_BOTTOM_LINES) / CHAR_HEIGHT; Line++)
260 {
261 for (Col = 0; Col < ScreenWidth / CHAR_WIDTH; Col++)
262 {
263 XboxVideoPutChar(OffScreenBuffer[0], OffScreenBuffer[1], Col, Line);
264 OffScreenBuffer += 2;
265 }
266 }
267 }
268
269 BOOLEAN
270 XboxVideoIsPaletteFixed(VOID)
271 {
272 return FALSE;
273 }
274
275 VOID
276 XboxVideoSetPaletteColor(UCHAR Color, UCHAR Red, UCHAR Green, UCHAR Blue)
277 {
278 /* Not supported */
279 }
280
281 VOID
282 XboxVideoGetPaletteColor(UCHAR Color, UCHAR* Red, UCHAR* Green, UCHAR* Blue)
283 {
284 /* Not supported */
285 }
286
287 VOID
288 XboxVideoSync(VOID)
289 {
290 /* Not supported */
291 }
292
293 VOID
294 XboxBeep(VOID)
295 {
296 /* Call PC version */
297 PcBeep();
298 }
299
300 VOID
301 XboxVideoPrepareForReactOS(VOID)
302 {
303 XboxVideoClearScreenColor(MAKE_COLOR(0, 0, 0), TRUE);
304 XboxVideoHideShowTextCursor(FALSE);
305 }
306
307 /* EOF */