1 /* 2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <frame_buffer_console.h> 8 9 #include <stdlib.h> 10 #include <string.h> 11 #include <stdio.h> 12 #include <unistd.h> 13 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> 21 22 #ifndef _BOOT_MODE 23 #include <vesa_info.h> 24 25 #include <edid.h> 26 #endif 27 28 #include "font.h" 29 30 31 //#define TRACE_FB_CONSOLE 32 #ifdef TRACE_FB_CONSOLE 33 # define TRACE(x) dprintf x 34 #else 35 # define TRACE(x) ; 36 #endif 37 38 39 struct console_info { 40 mutex lock; 41 area_id area; 42 43 addr_t frame_buffer; 44 int32 width; 45 int32 height; 46 int32 depth; 47 int32 bytes_per_pixel; 48 int32 bytes_per_row; 49 50 int32 columns; 51 int32 rows; 52 int32 cursor_x; 53 int32 cursor_y; 54 }; 55 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) 60 61 static uint8 sPalette8[] = { 62 63, 32, 52, 70, 42, 88, 67, 0, 63 }; 64 static uint16 sPalette15[] = { 65 // 0bbbbbgggggrrrrr (5-5-5) 66 0x7fff, 0x1993, 0x2660, 0x0273, 0x6400, 0x390f, 0x6ea0, 0x0000, 67 }; 68 static uint16 sPalette16[] = { 69 // bbbbbggggggrrrrr (5-6-5) 70 0xffff, 0x3333, 0x4cc0, 0x04d3, 0xc800, 0x722f, 0xdd40, 0x0000, 71 }; 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 82 }; 83 84 static struct console_info sConsole; 85 86 #ifndef _BOOT_MODE 87 static struct frame_buffer_boot_info sBootInfo; 88 static struct vesa_mode* sVesaModes; 89 #endif 90 91 92 static inline uint8 93 foreground_color(uint8 attr) 94 { 95 return attr & 0x7; 96 } 97 98 99 static inline uint8 100 background_color(uint8 attr) 101 { 102 return (attr >> 4) & 0x7; 103 } 104 105 106 static uint8* 107 get_palette_entry(uint8 index) 108 { 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]; 118 } 119 } 120 121 122 static void 123 render_glyph(int32 x, int32 y, uint8 glyph, uint8 attr) 124 { 125 // we're ASCII only 126 if (glyph > 127) 127 glyph = 127; 128 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)); 135 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]; 145 } 146 } 147 bits >>= 1; 148 } 149 150 base += sConsole.bytes_per_row; 151 } 152 } else { 153 // VGA mode will be treated as monochrome 154 // (ie. only the first plane will be used) 155 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; 159 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); 164 165 for (x = 0; x < CHAR_WIDTH; x++) { 166 if (mask == 0) 167 mask = 128; 168 169 // black on white 170 if (bits & 1) 171 base[offset / 8] &= ~mask; 172 else 173 base[offset / 8] |= mask; 174 175 bits >>= 1; 176 mask >>= 1; 177 offset += 1; 178 } 179 180 base += sConsole.bytes_per_row; 181 } 182 } 183 } 184 185 186 static void 187 draw_cursor(int32 x, int32 y) 188 { 189 if (x < 0 || y < 0) 190 return; 191 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); 197 198 if (sConsole.depth < 8) { 199 x /= 8; 200 endY /= 8; 201 } 202 203 for (; y < endY; y++) { 204 for (int32 x2 = x; x2 < endX; x2++) 205 base[x2] = ~base[x2]; 206 207 base += sConsole.bytes_per_row; 208 } 209 } 210 211 212 static status_t 213 console_get_size(int32* _width, int32* _height) 214 { 215 *_width = sConsole.columns; 216 *_height = sConsole.rows; 217 218 return B_OK; 219 } 220 221 222 static void 223 console_move_cursor(int32 x, int32 y) 224 { 225 if (!frame_buffer_console_available()) 226 return; 227 228 draw_cursor(sConsole.cursor_x, sConsole.cursor_y); 229 draw_cursor(x, y); 230 231 sConsole.cursor_x = x; 232 sConsole.cursor_y = y; 233 } 234 235 236 static void 237 console_put_glyph(int32 x, int32 y, uint8 glyph, uint8 attr) 238 { 239 if (x >= sConsole.columns || y >= sConsole.rows 240 || !frame_buffer_console_available()) 241 return; 242 243 render_glyph(x, y, glyph, attr); 244 } 245 246 247 static void 248 console_fill_glyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, 249 uint8 attr) 250 { 251 if (x >= sConsole.columns || y >= sConsole.rows 252 || !frame_buffer_console_available()) 253 return; 254 255 int32 left = x + width; 256 if (left > sConsole.columns) 257 left = sConsole.columns; 258 259 int32 bottom = y + height; 260 if (bottom > sConsole.rows) 261 bottom = sConsole.rows; 262 263 for (; y < bottom; y++) { 264 for (int32 x2 = x; x2 < left; x2++) { 265 render_glyph(x2, y, glyph, attr); 266 } 267 } 268 } 269 270 271 static void 272 console_blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, 273 int32 desty) 274 { 275 if (!frame_buffer_console_available()) 276 return; 277 278 height *= CHAR_HEIGHT; 279 srcy *= CHAR_HEIGHT; 280 desty *= CHAR_HEIGHT; 281 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; 291 } 292 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); 298 } 299 } 300 301 302 static void 303 console_clear(uint8 attr) 304 { 305 if (!frame_buffer_console_available()) 306 return; 307 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); 318 } 319 break; 320 default: 321 { 322 uint8* base = (uint8*)sConsole.frame_buffer; 323 uint8* color = get_palette_entry(background_color(attr)); 324 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]; 329 } 330 } 331 base += sConsole.bytes_per_row; 332 } 333 break; 334 } 335 } 336 337 sConsole.cursor_x = -1; 338 sConsole.cursor_y = -1; 339 } 340 341 342 static status_t 343 console_std_ops(int32 op, ...) 344 { 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; 350 351 default: 352 return B_ERROR; 353 } 354 } 355 356 357 console_module_info gFrameBufferConsoleModule = { 358 { 359 FRAME_BUFFER_CONSOLE_MODULE_NAME, 360 0, 361 console_std_ops 362 }, 363 &console_get_size, 364 &console_move_cursor, 365 &console_put_glyph, 366 &console_fill_glyph, 367 &console_blit, 368 &console_clear, 369 }; 370 371 372 // #pragma mark - 373 374 375 bool 376 frame_buffer_console_available(void) 377 { 378 return sConsole.frame_buffer != 0; 379 } 380 381 382 status_t 383 frame_buffer_update(addr_t baseAddress, int32 width, int32 height, int32 depth, 384 int32 bytesPerRow) 385 { 386 TRACE(("frame_buffer_update(buffer = %p, width = %ld, height = %ld, " 387 "depth = %ld, bytesPerRow = %ld)\n", (void*)baseAddress, width, height, 388 depth, bytesPerRow)); 389 390 mutex_lock(&sConsole.lock); 391 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; 400 401 // initially, the cursor is hidden 402 sConsole.cursor_x = -1; 403 sConsole.cursor_y = -1; 404 405 TRACE(("framebuffer mapped at %p, %ld columns, %ld rows\n", 406 (void*)sConsole.frame_buffer, sConsole.columns, sConsole.rows)); 407 408 mutex_unlock(&sConsole.lock); 409 return B_OK; 410 } 411 412 413 #ifndef _BOOT_MODE 414 status_t 415 frame_buffer_console_init(kernel_args* args) 416 { 417 if (!args->frame_buffer.enabled) 418 return B_OK; 419 420 mutex_init(&sConsole.lock, "console_lock"); 421 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; 429 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); 433 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; 442 443 add_boot_item(FRAME_BUFFER_BOOT_INFO, &sBootInfo, 444 sizeof(frame_buffer_boot_info)); 445 446 sVesaModes = (vesa_mode*)malloc(args->vesa_modes_size); 447 if (sVesaModes != NULL) { 448 memcpy(sVesaModes, args->vesa_modes, args->vesa_modes_size); 449 add_boot_item(VESA_MODES_BOOT_INFO, sVesaModes, args->vesa_modes_size); 450 } 451 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)); 457 } 458 } 459 460 return B_OK; 461 } 462 463 464 status_t 465 frame_buffer_console_init_post_modules(kernel_args* args) 466 { 467 if (sConsole.frame_buffer == 0) 468 return B_OK; 469 470 // try to set frame buffer memory to write combined 471 472 return vm_set_area_memory_type(sConsole.area, 473 args->frame_buffer.physical_buffer.start, B_MTR_WC); 474 } 475 476 477 // #pragma mark - 478 479 480 status_t 481 _user_frame_buffer_update(addr_t baseAddress, int32 width, int32 height, 482 int32 depth, int32 bytesPerRow) 483 { 484 debug_stop_screen_debug_output(); 485 486 if (geteuid() != 0) 487 return B_NOT_ALLOWED; 488 if (IS_USER_ADDRESS(baseAddress) && baseAddress != 0) 489 return B_BAD_ADDRESS; 490 491 return frame_buffer_update(baseAddress, width, height, depth, bytesPerRow); 492 } 493 #endif 494 495