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.h> 19 #include <fs/devfs.h> 20 #include <boot/kernel_args.h> 21 #include <vesa_info.h> 22 23 #include <edid.h> 24 25 #include "font.h" 26 27 28 //#define TRACE_FB_CONSOLE 29 #ifdef TRACE_FB_CONSOLE 30 # define TRACE(x) dprintf x 31 #else 32 # define TRACE(x) ; 33 #endif 34 35 36 struct console_info { 37 mutex lock; 38 area_id area; 39 40 addr_t frame_buffer; 41 int32 width; 42 int32 height; 43 int32 depth; 44 int32 bytes_per_pixel; 45 int32 bytes_per_row; 46 47 int32 columns; 48 int32 rows; 49 int32 cursor_x; 50 int32 cursor_y; 51 }; 52 53 // Palette is (white and black are exchanged): 54 // 0 - white, 1 - blue, 2 - green, 3 - cyan, 4 - red, 5 - magenta, 6 - yellow, 55 // 7 - black 56 // 8-15 - same but bright (we're ignoring those) 57 58 static uint8 sPalette8[] = { 59 63, 32, 52, 70, 42, 88, 67, 0, 60 }; 61 static uint16 sPalette15[] = { 62 // 0bbbbbgggggrrrrr (5-5-5) 63 0x7fff, 0x1993, 0x2660, 0x0273, 0x6400, 0x390f, 0x6ea0, 0x0000, 64 }; 65 static uint16 sPalette16[] = { 66 // bbbbbggggggrrrrr (5-6-5) 67 0xffff, 0x3333, 0x4cc0, 0x04d3, 0xc800, 0x722f, 0xdd40, 0x0000, 68 }; 69 static uint32 sPalette32[] = { 70 // is also used by 24 bit modes 71 0xffffff, // white 72 0x336698, // blue 73 0x4e9a00, // green 74 0x06989a, // cyan 75 0xcc0000, // red 76 0x73447b, // magenta 77 0xdaa800, // yellow 78 0x000000, // black 79 }; 80 81 static struct console_info sConsole; 82 static struct frame_buffer_boot_info sBootInfo; 83 static struct vesa_mode* sVesaModes; 84 85 86 static inline uint8 87 foreground_color(uint8 attr) 88 { 89 return attr & 0x7; 90 } 91 92 93 static inline uint8 94 background_color(uint8 attr) 95 { 96 return (attr >> 4) & 0x7; 97 } 98 99 100 static uint8* 101 get_palette_entry(uint8 index) 102 { 103 switch (sConsole.depth) { 104 case 8: 105 return &sPalette8[index]; 106 case 15: 107 return (uint8*)&sPalette15[index]; 108 case 16: 109 return (uint8*)&sPalette16[index]; 110 default: 111 return (uint8*)&sPalette32[index]; 112 } 113 } 114 115 116 static void 117 render_glyph(int32 x, int32 y, uint8 glyph, uint8 attr) 118 { 119 // we're ASCII only 120 if (glyph > 127) 121 glyph = 127; 122 123 if (sConsole.depth >= 8) { 124 uint8* base = (uint8*)(sConsole.frame_buffer 125 + sConsole.bytes_per_row * y * CHAR_HEIGHT 126 + x * CHAR_WIDTH * sConsole.bytes_per_pixel); 127 uint8* color = get_palette_entry(foreground_color(attr)); 128 uint8* backgroundColor = get_palette_entry(background_color(attr)); 129 130 for (y = 0; y < CHAR_HEIGHT; y++) { 131 uint8 bits = FONT[CHAR_HEIGHT * glyph + y]; 132 for (x = 0; x < CHAR_WIDTH; x++) { 133 for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) { 134 if (bits & 1) 135 base[x * sConsole.bytes_per_pixel + i] = color[i]; 136 else { 137 base[x * sConsole.bytes_per_pixel + i] 138 = backgroundColor[i]; 139 } 140 } 141 bits >>= 1; 142 } 143 144 base += sConsole.bytes_per_row; 145 } 146 } else { 147 // VGA mode will be treated as monochrome 148 // (ie. only the first plane will be used) 149 150 uint8* base = (uint8*)(sConsole.frame_buffer 151 + sConsole.bytes_per_row * y * CHAR_HEIGHT + x * CHAR_WIDTH / 8); 152 uint8 baseOffset = (x * CHAR_WIDTH) & 0x7; 153 154 for (y = 0; y < CHAR_HEIGHT; y++) { 155 uint8 bits = FONT[CHAR_HEIGHT * glyph + y]; 156 uint8 offset = baseOffset; 157 uint8 mask = 1 << (7 - baseOffset); 158 159 for (x = 0; x < CHAR_WIDTH; x++) { 160 if (mask == 0) 161 mask = 128; 162 163 // black on white 164 if (bits & 1) 165 base[offset / 8] &= ~mask; 166 else 167 base[offset / 8] |= mask; 168 169 bits >>= 1; 170 mask >>= 1; 171 offset += 1; 172 } 173 174 base += sConsole.bytes_per_row; 175 } 176 } 177 } 178 179 180 static void 181 draw_cursor(int32 x, int32 y) 182 { 183 if (x < 0 || y < 0) 184 return; 185 186 x *= CHAR_WIDTH * sConsole.bytes_per_pixel; 187 y *= CHAR_HEIGHT; 188 int32 endX = x + CHAR_WIDTH * sConsole.bytes_per_pixel; 189 int32 endY = y + CHAR_HEIGHT; 190 uint8* base = (uint8*)(sConsole.frame_buffer + y * sConsole.bytes_per_row); 191 192 if (sConsole.depth < 8) { 193 x /= 8; 194 endY /= 8; 195 } 196 197 for (; y < endY; y++) { 198 for (int32 x2 = x; x2 < endX; x2++) 199 base[x2] = ~base[x2]; 200 201 base += sConsole.bytes_per_row; 202 } 203 } 204 205 206 static status_t 207 console_get_size(int32* _width, int32* _height) 208 { 209 *_width = sConsole.columns; 210 *_height = sConsole.rows; 211 212 return B_OK; 213 } 214 215 216 static void 217 console_move_cursor(int32 x, int32 y) 218 { 219 if (!frame_buffer_console_available()) 220 return; 221 222 draw_cursor(sConsole.cursor_x, sConsole.cursor_y); 223 draw_cursor(x, y); 224 225 sConsole.cursor_x = x; 226 sConsole.cursor_y = y; 227 } 228 229 230 static void 231 console_put_glyph(int32 x, int32 y, uint8 glyph, uint8 attr) 232 { 233 if (x >= sConsole.columns || y >= sConsole.rows 234 || !frame_buffer_console_available()) 235 return; 236 237 render_glyph(x, y, glyph, attr); 238 } 239 240 241 static void 242 console_fill_glyph(int32 x, int32 y, int32 width, int32 height, uint8 glyph, 243 uint8 attr) 244 { 245 if (x >= sConsole.columns || y >= sConsole.rows 246 || !frame_buffer_console_available()) 247 return; 248 249 int32 left = x + width; 250 if (left > sConsole.columns) 251 left = sConsole.columns; 252 253 int32 bottom = y + height; 254 if (bottom > sConsole.rows) 255 bottom = sConsole.rows; 256 257 for (; y < bottom; y++) { 258 for (int32 x2 = x; x2 < left; x2++) { 259 render_glyph(x2, y, glyph, attr); 260 } 261 } 262 } 263 264 265 static void 266 console_blit(int32 srcx, int32 srcy, int32 width, int32 height, int32 destx, 267 int32 desty) 268 { 269 if (!frame_buffer_console_available()) 270 return; 271 272 height *= CHAR_HEIGHT; 273 srcy *= CHAR_HEIGHT; 274 desty *= CHAR_HEIGHT; 275 276 if (sConsole.depth >= 8) { 277 width *= CHAR_WIDTH * sConsole.bytes_per_pixel; 278 srcx *= CHAR_WIDTH * sConsole.bytes_per_pixel; 279 destx *= CHAR_WIDTH * sConsole.bytes_per_pixel; 280 } else { 281 // monochrome mode 282 width = width * CHAR_WIDTH / 8; 283 srcx = srcx * CHAR_WIDTH / 8; 284 destx = destx * CHAR_WIDTH / 8; 285 } 286 287 for (int32 y = 0; y < height; y++) { 288 memmove((void*)(sConsole.frame_buffer + (desty + y) 289 * sConsole.bytes_per_row + destx), 290 (void*)(sConsole.frame_buffer + (srcy + y) * sConsole.bytes_per_row 291 + srcx), width); 292 } 293 } 294 295 296 static void 297 console_clear(uint8 attr) 298 { 299 if (!frame_buffer_console_available()) 300 return; 301 302 switch (sConsole.bytes_per_pixel) { 303 case 1: 304 if (sConsole.depth >= 8) { 305 memset((void*)sConsole.frame_buffer, 306 sPalette8[background_color(attr)], 307 sConsole.height * sConsole.bytes_per_row); 308 } else { 309 // special case for VGA mode 310 memset((void*)sConsole.frame_buffer, 0xff, 311 sConsole.height * sConsole.bytes_per_row); 312 } 313 break; 314 default: 315 { 316 uint8* base = (uint8*)sConsole.frame_buffer; 317 uint8* color = get_palette_entry(background_color(attr)); 318 319 for (int32 y = 0; y < sConsole.height; y++) { 320 for (int32 x = 0; x < sConsole.width; x++) { 321 for (int32 i = 0; i < sConsole.bytes_per_pixel; i++) { 322 base[x * sConsole.bytes_per_pixel + i] = color[i]; 323 } 324 } 325 base += sConsole.bytes_per_row; 326 } 327 break; 328 } 329 } 330 331 sConsole.cursor_x = -1; 332 sConsole.cursor_y = -1; 333 } 334 335 336 static status_t 337 console_std_ops(int32 op, ...) 338 { 339 switch (op) { 340 case B_MODULE_INIT: 341 return frame_buffer_console_available() ? B_OK : B_ERROR; 342 case B_MODULE_UNINIT: 343 return B_OK; 344 345 default: 346 return B_ERROR; 347 } 348 } 349 350 351 console_module_info gFrameBufferConsoleModule = { 352 { 353 FRAME_BUFFER_CONSOLE_MODULE_NAME, 354 0, 355 console_std_ops 356 }, 357 &console_get_size, 358 &console_move_cursor, 359 &console_put_glyph, 360 &console_fill_glyph, 361 &console_blit, 362 &console_clear, 363 }; 364 365 366 static status_t 367 frame_buffer_update(addr_t baseAddress, int32 width, int32 height, int32 depth, 368 int32 bytesPerRow) 369 { 370 TRACE(("frame_buffer_update(buffer = %p, width = %ld, height = %ld, " 371 "depth = %ld, bytesPerRow = %ld)\n", (void*)baseAddress, width, height, 372 depth, bytesPerRow)); 373 374 mutex_lock(&sConsole.lock); 375 376 sConsole.frame_buffer = baseAddress; 377 sConsole.width = width; 378 sConsole.height = height; 379 sConsole.depth = depth; 380 sConsole.bytes_per_pixel = (depth + 7) / 8; 381 sConsole.bytes_per_row = bytesPerRow; 382 sConsole.columns = sConsole.width / CHAR_WIDTH; 383 sConsole.rows = sConsole.height / CHAR_HEIGHT; 384 385 // initially, the cursor is hidden 386 sConsole.cursor_x = -1; 387 sConsole.cursor_y = -1; 388 389 TRACE(("framebuffer mapped at %p, %ld columns, %ld rows\n", 390 (void*)sConsole.frame_buffer, sConsole.columns, sConsole.rows)); 391 392 mutex_unlock(&sConsole.lock); 393 return B_OK; 394 } 395 396 397 // #pragma mark - 398 399 400 bool 401 frame_buffer_console_available(void) 402 { 403 return sConsole.frame_buffer != 0; 404 } 405 406 407 status_t 408 frame_buffer_console_init(kernel_args* args) 409 { 410 if (!args->frame_buffer.enabled) 411 return B_OK; 412 413 mutex_init(&sConsole.lock, "console_lock"); 414 415 void* frameBuffer; 416 sConsole.area = map_physical_memory("vesa_fb", 417 (void*)args->frame_buffer.physical_buffer.start, 418 args->frame_buffer.physical_buffer.size, B_ANY_KERNEL_ADDRESS, 419 B_READ_AREA | B_WRITE_AREA | B_USER_CLONEABLE_AREA, &frameBuffer); 420 if (sConsole.area < 0) 421 return sConsole.area; 422 423 frame_buffer_update((addr_t)frameBuffer, args->frame_buffer.width, 424 args->frame_buffer.height, args->frame_buffer.depth, 425 args->frame_buffer.bytes_per_row); 426 427 sBootInfo.area = sConsole.area; 428 sBootInfo.frame_buffer = (addr_t)frameBuffer; 429 sBootInfo.width = args->frame_buffer.width; 430 sBootInfo.height = args->frame_buffer.height; 431 sBootInfo.depth = args->frame_buffer.depth; 432 sBootInfo.bytes_per_row = args->frame_buffer.bytes_per_row; 433 sBootInfo.vesa_capabilities = args->vesa_capabilities; 434 435 add_boot_item(FRAME_BUFFER_BOOT_INFO, &sBootInfo, 436 sizeof(frame_buffer_boot_info)); 437 438 sVesaModes = (vesa_mode*)malloc(args->vesa_modes_size); 439 if (sVesaModes != NULL) { 440 memcpy(sVesaModes, args->vesa_modes, args->vesa_modes_size); 441 add_boot_item(VESA_MODES_BOOT_INFO, sVesaModes, args->vesa_modes_size); 442 } 443 444 if (args->edid_info != NULL) { 445 edid1_info* info = (edid1_info*)malloc(sizeof(edid1_info)); 446 if (info != NULL) { 447 memcpy(info, args->edid_info, sizeof(edid1_info)); 448 add_boot_item(VESA_EDID_BOOT_INFO, info, sizeof(edid1_info)); 449 } 450 } 451 452 return B_OK; 453 } 454 455 456 status_t 457 frame_buffer_console_init_post_modules(kernel_args* args) 458 { 459 if (sConsole.frame_buffer == 0) 460 return B_OK; 461 462 // try to set frame buffer memory to write combined 463 464 return vm_set_area_memory_type(sConsole.area, 465 args->frame_buffer.physical_buffer.start, B_MTR_WC); 466 } 467 468 469 // #pragma mark - 470 471 472 status_t 473 _user_frame_buffer_update(addr_t baseAddress, int32 width, int32 height, 474 int32 depth, int32 bytesPerRow) 475 { 476 debug_stop_screen_debug_output(); 477 478 if (geteuid() != 0) 479 return B_NOT_ALLOWED; 480 if (IS_USER_ADDRESS(baseAddress) && baseAddress != 0) 481 return B_BAD_ADDRESS; 482 483 return frame_buffer_update(baseAddress, width, height, depth, bytesPerRow); 484 } 485 486