vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / debug / frame_buffer_console.cpp
blob7f7ce2fffe3a4ad3286f060d77d664d535d1d34d
1 /*
2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <frame_buffer_console.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <unistd.h>
14 #include <KernelExport.h>
15 #include <kernel.h>
16 #include <lock.h>
17 #include <boot_item.h>
18 #include <vm/vm.h>
19 #include <fs/devfs.h>
20 #include <boot/kernel_args.h>
22 #ifndef _BOOT_MODE
23 #include <vesa_info.h>
25 #include <edid.h>
26 #endif
28 #include "font.h"
31 //#define TRACE_FB_CONSOLE
32 #ifdef TRACE_FB_CONSOLE
33 # define TRACE(x) dprintf x
34 #else
35 # define TRACE(x) ;
36 #endif
39 struct console_info {
40 mutex lock;
41 area_id area;
43 addr_t frame_buffer;
44 int32 width;
45 int32 height;
46 int32 depth;
47 int32 bytes_per_pixel;
48 int32 bytes_per_row;
50 int32 columns;
51 int32 rows;
52 int32 cursor_x;
53 int32 cursor_y;
56 // Palette is (white and black are exchanged):
57 // 0 - white, 1 - blue, 2 - green, 3 - cyan, 4 - red, 5 - magenta, 6 - yellow,
58 // 7 - black
59 // 8-15 - same but bright (we're ignoring those)
61 static uint8 sPalette8[] = {
62 63, 32, 52, 70, 42, 88, 67, 0,
64 static uint16 sPalette15[] = {
65 // 0bbbbbgggggrrrrr (5-5-5)
66 0x7fff, 0x1993, 0x2660, 0x0273, 0x6400, 0x390f, 0x6ea0, 0x0000,
68 static uint16 sPalette16[] = {
69 // bbbbbggggggrrrrr (5-6-5)
70 0xffff, 0x3333, 0x4cc0, 0x04d3, 0xc800, 0x722f, 0xdd40, 0x0000,
72 static uint32 sPalette32[] = {
73 // is also used by 24 bit modes
74 0xffffff, // white
75 0x336698, // blue
76 0x4e9a00, // green
77 0x06989a, // cyan
78 0xcc0000, // red
79 0x73447b, // magenta
80 0xdaa800, // yellow
81 0x000000, // black
84 static struct console_info sConsole;
86 #ifndef _BOOT_MODE
87 static struct frame_buffer_boot_info sBootInfo;
88 static struct vesa_mode* sVesaModes;
89 #endif
92 static inline uint8
93 foreground_color(uint8 attr)
95 return attr & 0x7;
99 static inline uint8
100 background_color(uint8 attr)
102 return (attr >> 4) & 0x7;
106 static uint8*
107 get_palette_entry(uint8 index)
109 switch (sConsole.depth) {
110 case 8:
111 return &sPalette8[index];
112 case 15:
113 return (uint8*)&sPalette15[index];
114 case 16:
115 return (uint8*)&sPalette16[index];
116 default:
117 return (uint8*)&sPalette32[index];
122 static void
123 render_glyph(int32 x, int32 y, uint8 glyph, uint8 attr)
125 // we're ASCII only
126 if (glyph > 127)
127 glyph = 127;
129 if (sConsole.depth >= 8) {
130 uint8* base = (uint8*)(sConsole.frame_buffer
131 + sConsole.bytes_per_row * y * CHAR_HEIGHT
132 + x * CHAR_WIDTH * sConsole.bytes_per_pixel);
133 uint8* color = get_palette_entry(foreground_color(attr));
134 uint8* backgroundColor = get_palette_entry(background_color(attr));
136 for (y = 0; y < CHAR_HEIGHT; y++) {
137 uint8 bits = FONT[CHAR_HEIGHT * glyph + y];
138 for (x = 0; x < CHAR_WIDTH; x++) {
139 for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) {
140 if (bits & 1)
141 base[x * sConsole.bytes_per_pixel + i] = color[i];
142 else {
143 base[x * sConsole.bytes_per_pixel + i]
144 = backgroundColor[i];
147 bits >>= 1;
150 base += sConsole.bytes_per_row;
152 } else {
153 // VGA mode will be treated as monochrome
154 // (ie. only the first plane will be used)
156 uint8* base = (uint8*)(sConsole.frame_buffer
157 + sConsole.bytes_per_row * y * CHAR_HEIGHT + x * CHAR_WIDTH / 8);
158 uint8 baseOffset = (x * CHAR_WIDTH) & 0x7;
160 for (y = 0; y < CHAR_HEIGHT; y++) {
161 uint8 bits = FONT[CHAR_HEIGHT * glyph + y];
162 uint8 offset = baseOffset;
163 uint8 mask = 1 << (7 - baseOffset);
165 for (x = 0; x < CHAR_WIDTH; x++) {
166 if (mask == 0)
167 mask = 128;
169 // black on white
170 if (bits & 1)
171 base[offset / 8] &= ~mask;
172 else
173 base[offset / 8] |= mask;
175 bits >>= 1;
176 mask >>= 1;
177 offset += 1;
180 base += sConsole.bytes_per_row;
186 static void
187 draw_cursor(int32 x, int32 y)
189 if (x < 0 || y < 0)
190 return;
192 x *= CHAR_WIDTH * sConsole.bytes_per_pixel;
193 y *= CHAR_HEIGHT;
194 int32 endX = x + CHAR_WIDTH * sConsole.bytes_per_pixel;
195 int32 endY = y + CHAR_HEIGHT;
196 uint8* base = (uint8*)(sConsole.frame_buffer + y * sConsole.bytes_per_row);
198 if (sConsole.depth < 8) {
199 x /= 8;
200 endY /= 8;
203 for (; y < endY; y++) {
204 for (int32 x2 = x; x2 < endX; x2++)
205 base[x2] = ~base[x2];
207 base += sConsole.bytes_per_row;
212 static status_t
213 console_get_size(int32* _width, int32* _height)
215 *_width = sConsole.columns;
216 *_height = sConsole.rows;
218 return B_OK;
222 static void
223 console_move_cursor(int32 x, int32 y)
225 if (!frame_buffer_console_available())
226 return;
228 draw_cursor(sConsole.cursor_x, sConsole.cursor_y);
229 draw_cursor(x, y);
231 sConsole.cursor_x = x;
232 sConsole.cursor_y = y;
236 static void
237 console_put_glyph(int32 x, int32 y, uint8 glyph, uint8 attr)
239 if (x >= sConsole.columns || y >= sConsole.rows
240 || !frame_buffer_console_available())
241 return;
243 render_glyph(x, y, glyph, attr);
247 static void
248 console_fill_glyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph,
249 uint8 attr)
251 if (x >= sConsole.columns || y >= sConsole.rows
252 || !frame_buffer_console_available())
253 return;
255 int32 left = x + width;
256 if (left > sConsole.columns)
257 left = sConsole.columns;
259 int32 bottom = y + height;
260 if (bottom > sConsole.rows)
261 bottom = sConsole.rows;
263 for (; y < bottom; y++) {
264 for (int32 x2 = x; x2 < left; x2++) {
265 render_glyph(x2, y, glyph, attr);
271 static void
272 console_blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx,
273 int32 desty)
275 if (!frame_buffer_console_available())
276 return;
278 height *= CHAR_HEIGHT;
279 srcy *= CHAR_HEIGHT;
280 desty *= CHAR_HEIGHT;
282 if (sConsole.depth >= 8) {
283 width *= CHAR_WIDTH * sConsole.bytes_per_pixel;
284 srcx *= CHAR_WIDTH * sConsole.bytes_per_pixel;
285 destx *= CHAR_WIDTH * sConsole.bytes_per_pixel;
286 } else {
287 // monochrome mode
288 width = width * CHAR_WIDTH / 8;
289 srcx = srcx * CHAR_WIDTH / 8;
290 destx = destx * CHAR_WIDTH / 8;
293 for (int32 y = 0; y < height; y++) {
294 memmove((void*)(sConsole.frame_buffer + (desty + y)
295 * sConsole.bytes_per_row + destx),
296 (void*)(sConsole.frame_buffer + (srcy + y) * sConsole.bytes_per_row
297 + srcx), width);
302 static void
303 console_clear(uint8 attr)
305 if (!frame_buffer_console_available())
306 return;
308 switch (sConsole.bytes_per_pixel) {
309 case 1:
310 if (sConsole.depth >= 8) {
311 memset((void*)sConsole.frame_buffer,
312 sPalette8[background_color(attr)],
313 sConsole.height * sConsole.bytes_per_row);
314 } else {
315 // special case for VGA mode
316 memset((void*)sConsole.frame_buffer, 0xff,
317 sConsole.height * sConsole.bytes_per_row);
319 break;
320 default:
322 uint8* base = (uint8*)sConsole.frame_buffer;
323 uint8* color = get_palette_entry(background_color(attr));
325 for (int32 y = 0; y < sConsole.height; y++) {
326 for (int32 x = 0; x < sConsole.width; x++) {
327 for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) {
328 base[x * sConsole.bytes_per_pixel + i] = color[i];
331 base += sConsole.bytes_per_row;
333 break;
337 sConsole.cursor_x = -1;
338 sConsole.cursor_y = -1;
342 static status_t
343 console_std_ops(int32 op, ...)
345 switch (op) {
346 case B_MODULE_INIT:
347 return frame_buffer_console_available() ? B_OK : B_ERROR;
348 case B_MODULE_UNINIT:
349 return B_OK;
351 default:
352 return B_ERROR;
357 console_module_info gFrameBufferConsoleModule = {
359 FRAME_BUFFER_CONSOLE_MODULE_NAME,
361 console_std_ops
363 &console_get_size,
364 &console_move_cursor,
365 &console_put_glyph,
366 &console_fill_glyph,
367 &console_blit,
368 &console_clear,
372 // #pragma mark -
375 bool
376 frame_buffer_console_available(void)
378 return sConsole.frame_buffer != 0;
382 status_t
383 frame_buffer_update(addr_t baseAddress, int32 width, int32 height, int32 depth,
384 int32 bytesPerRow)
386 TRACE(("frame_buffer_update(buffer = %p, width = %ld, height = %ld, "
387 "depth = %ld, bytesPerRow = %ld)\n", (void*)baseAddress, width, height,
388 depth, bytesPerRow));
390 mutex_lock(&sConsole.lock);
392 sConsole.frame_buffer = baseAddress;
393 sConsole.width = width;
394 sConsole.height = height;
395 sConsole.depth = depth;
396 sConsole.bytes_per_pixel = (depth + 7) / 8;
397 sConsole.bytes_per_row = bytesPerRow;
398 sConsole.columns = sConsole.width / CHAR_WIDTH;
399 sConsole.rows = sConsole.height / CHAR_HEIGHT;
401 // initially, the cursor is hidden
402 sConsole.cursor_x = -1;
403 sConsole.cursor_y = -1;
405 TRACE(("framebuffer mapped at %p, %ld columns, %ld rows\n",
406 (void*)sConsole.frame_buffer, sConsole.columns, sConsole.rows));
408 mutex_unlock(&sConsole.lock);
409 return B_OK;
413 #ifndef _BOOT_MODE
414 status_t
415 frame_buffer_console_init(kernel_args* args)
417 if (!args->frame_buffer.enabled)
418 return B_OK;
420 mutex_init(&sConsole.lock, "console_lock");
422 void* frameBuffer;
423 sConsole.area = map_physical_memory("vesa frame buffer",
424 args->frame_buffer.physical_buffer.start,
425 args->frame_buffer.physical_buffer.size, B_ANY_KERNEL_ADDRESS,
426 B_READ_AREA | B_WRITE_AREA | B_USER_CLONEABLE_AREA, &frameBuffer);
427 if (sConsole.area < 0)
428 return sConsole.area;
430 frame_buffer_update((addr_t)frameBuffer, args->frame_buffer.width,
431 args->frame_buffer.height, args->frame_buffer.depth,
432 args->frame_buffer.bytes_per_row);
434 sBootInfo.area = sConsole.area;
435 sBootInfo.physical_frame_buffer = args->frame_buffer.physical_buffer.start;
436 sBootInfo.frame_buffer = (addr_t)frameBuffer;
437 sBootInfo.width = args->frame_buffer.width;
438 sBootInfo.height = args->frame_buffer.height;
439 sBootInfo.depth = args->frame_buffer.depth;
440 sBootInfo.bytes_per_row = args->frame_buffer.bytes_per_row;
441 sBootInfo.vesa_capabilities = args->vesa_capabilities;
443 add_boot_item(FRAME_BUFFER_BOOT_INFO, &sBootInfo,
444 sizeof(frame_buffer_boot_info));
446 sVesaModes = (vesa_mode*)malloc(args->vesa_modes_size);
447 if (sVesaModes != NULL && args->vesa_modes_size > 0) {
448 memcpy(sVesaModes, args->vesa_modes, args->vesa_modes_size);
449 add_boot_item(VESA_MODES_BOOT_INFO, sVesaModes, args->vesa_modes_size);
452 if (args->edid_info != NULL) {
453 edid1_info* info = (edid1_info*)malloc(sizeof(edid1_info));
454 if (info != NULL) {
455 memcpy(info, args->edid_info, sizeof(edid1_info));
456 add_boot_item(VESA_EDID_BOOT_INFO, info, sizeof(edid1_info));
460 return B_OK;
464 status_t
465 frame_buffer_console_init_post_modules(kernel_args* args)
467 if (sConsole.frame_buffer == 0)
468 return B_OK;
470 // try to set frame buffer memory to write combined
472 return vm_set_area_memory_type(sConsole.area,
473 args->frame_buffer.physical_buffer.start, B_MTR_WC);
477 // #pragma mark -
480 status_t
481 _user_frame_buffer_update(addr_t baseAddress, int32 width, int32 height,
482 int32 depth, int32 bytesPerRow)
484 debug_stop_screen_debug_output();
486 if (geteuid() != 0)
487 return B_NOT_ALLOWED;
488 if (IS_USER_ADDRESS(baseAddress) && baseAddress != 0)
489 return B_BAD_ADDRESS;
491 return frame_buffer_update(baseAddress, width, height, depth, bytesPerRow);
493 #endif