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