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 "vesa_private.h" 8 #include "vesa.h" 9 10 #include <boot_item.h> 11 #include <frame_buffer_console.h> 12 #include <util/kernel_cpp.h> 13 #include <vm/vm.h> 14 15 #include "driver.h" 16 #include "utility.h" 17 #include "vesa_info.h" 18 19 20 #define LINEAR_ADDRESS(segment, offset) \ 21 (((addr_t)(segment) << 4) + (addr_t)(offset)) 22 #define SEGMENTED_TO_LINEAR(segmented) \ 23 LINEAR_ADDRESS((addr_t)(segmented) >> 16, (addr_t)(segmented) & 0xffff) 24 25 26 bios_module_info* sBIOSModule; 27 28 29 /*! Loads the BIOS module and sets up a state for it. The BIOS module is only 30 loaded when we need it, as it is quite a large module. 31 */ 32 status_t 33 vbe_call_prepare(bios_state** state) 34 { 35 status_t status; 36 37 status = get_module(B_BIOS_MODULE_NAME, (module_info**)&sBIOSModule); 38 if (status != B_OK) { 39 dprintf(DEVICE_NAME ": failed to get BIOS module: %s\n", 40 strerror(status)); 41 return status; 42 } 43 44 status = sBIOSModule->prepare(state); 45 if (status != B_OK) { 46 dprintf(DEVICE_NAME ": failed to prepare BIOS state: %s\n", 47 strerror(status)); 48 put_module(B_BIOS_MODULE_NAME); 49 } 50 51 return status; 52 } 53 54 55 void 56 vbe_call_finish(bios_state* state) 57 { 58 sBIOSModule->finish(state); 59 put_module(B_BIOS_MODULE_NAME); 60 } 61 62 63 static status_t 64 find_graphics_card(addr_t frameBuffer, addr_t& base, size_t& size) 65 { 66 // TODO: when we port this over to the new driver API, this mechanism can be 67 // used to find the right device_node 68 pci_module_info* pci; 69 if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) != B_OK) 70 return B_ERROR; 71 72 pci_info info; 73 for (int32 index = 0; pci->get_nth_pci_info(index, &info) == B_OK; index++) { 74 if (info.class_base != PCI_display) 75 continue; 76 77 // check PCI BARs 78 for (uint32 i = 0; i < 6; i++) { 79 if (info.u.h0.base_registers[i] <= frameBuffer 80 && info.u.h0.base_registers[i] + info.u.h0.base_register_sizes[i] 81 > frameBuffer) { 82 // found it! 83 base = info.u.h0.base_registers[i]; 84 size = info.u.h0.base_register_sizes[i]; 85 86 put_module(B_PCI_MODULE_NAME); 87 return B_OK; 88 } 89 } 90 } 91 92 put_module(B_PCI_MODULE_NAME); 93 return B_ENTRY_NOT_FOUND; 94 } 95 96 97 uint32 98 get_color_space_for_depth(uint32 depth) 99 { 100 switch (depth) { 101 case 1: 102 return B_GRAY1; 103 case 4: 104 return B_GRAY8; 105 // the app_server is smart enough to translate this to VGA mode 106 case 8: 107 return B_CMAP8; 108 case 15: 109 return B_RGB15; 110 case 16: 111 return B_RGB16; 112 case 24: 113 return B_RGB24; 114 case 32: 115 return B_RGB32; 116 } 117 118 return 0; 119 } 120 121 122 status_t 123 vbe_get_mode_info(bios_state* state, uint16 mode, struct vbe_mode_info* modeInfo) 124 { 125 void* vbeModeInfo = sBIOSModule->allocate_mem(state, 126 sizeof(struct vbe_mode_info)); 127 if (vbeModeInfo == NULL) 128 return B_NO_MEMORY; 129 memset(vbeModeInfo, 0, sizeof(vbe_mode_info)); 130 131 uint32 physicalAddress = sBIOSModule->physical_address(state, vbeModeInfo); 132 bios_regs regs = {}; 133 regs.eax = 0x4f01; 134 regs.ecx = mode; 135 regs.es = physicalAddress >> 4; 136 regs.edi = physicalAddress - (regs.es << 4); 137 138 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 139 if (status != B_OK) { 140 dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): BIOS failed: %s\n", mode, 141 strerror(status)); 142 return status; 143 } 144 145 if ((regs.eax & 0xffff) != 0x4f) { 146 dprintf(DEVICE_NAME ": vbe_get_mode_info(%u): BIOS returned " 147 "0x%04" B_PRIx32 "\n", mode, regs.eax & 0xffff); 148 return B_ENTRY_NOT_FOUND; 149 } 150 151 memcpy(modeInfo, vbeModeInfo, sizeof(struct vbe_mode_info)); 152 return B_OK; 153 } 154 155 156 status_t 157 vbe_set_mode(bios_state* state, uint16 mode) 158 { 159 bios_regs regs = {}; 160 regs.eax = 0x4f02; 161 regs.ebx = (mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER; 162 163 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 164 if (status != B_OK) { 165 dprintf(DEVICE_NAME ": vbe_set_mode(%u): BIOS failed: %s\n", mode, 166 strerror(status)); 167 return status; 168 } 169 170 if ((regs.eax & 0xffff) != 0x4f) { 171 dprintf(DEVICE_NAME ": vbe_set_mode(%u): BIOS returned 0x%04" B_PRIx32 172 "\n", mode, regs.eax & 0xffff); 173 return B_ERROR; 174 } 175 176 return B_OK; 177 } 178 179 180 static uint32 181 vbe_to_system_dpms(uint8 vbeMode) 182 { 183 uint32 mode = 0; 184 if ((vbeMode & (DPMS_OFF | DPMS_REDUCED_ON)) != 0) 185 mode |= B_DPMS_OFF; 186 if ((vbeMode & DPMS_STANDBY) != 0) 187 mode |= B_DPMS_STAND_BY; 188 if ((vbeMode & DPMS_SUSPEND) != 0) 189 mode |= B_DPMS_SUSPEND; 190 191 return mode; 192 } 193 194 195 static status_t 196 vbe_get_dpms_capabilities(bios_state* state, uint32& vbeMode, uint32& mode) 197 { 198 // we always return a valid mode 199 vbeMode = 0; 200 mode = B_DPMS_ON; 201 202 bios_regs regs = {}; 203 regs.eax = 0x4f10; 204 regs.ebx = 0; 205 regs.esi = 0; 206 regs.edi = 0; 207 208 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 209 if (status != B_OK) { 210 dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS failed: %s\n", 211 strerror(status)); 212 return status; 213 } 214 215 if ((regs.eax & 0xffff) != 0x4f) { 216 dprintf(DEVICE_NAME ": vbe_get_dpms_capabilities(): BIOS returned " 217 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 218 return B_ERROR; 219 } 220 221 vbeMode = regs.ebx >> 8; 222 mode = vbe_to_system_dpms(vbeMode); 223 return status; 224 } 225 226 227 status_t 228 vbe_set_bits_per_gun(bios_state* state, vesa_info& info, uint8 bits) 229 { 230 info.bits_per_gun = 6; 231 232 bios_regs regs = {}; 233 regs.eax = 0x4f08; 234 regs.ebx = (bits << 8) | 1; 235 236 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 237 if (status != B_OK) { 238 dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS failed: %s\n", 239 strerror(status)); 240 return status; 241 } 242 243 if ((regs.eax & 0xffff) != 0x4f) { 244 dprintf(DEVICE_NAME ": vbe_set_bits_per_gun(): BIOS returned " 245 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 246 return B_ERROR; 247 } 248 249 info.bits_per_gun = regs.ebx >> 8; 250 return B_OK; 251 } 252 253 254 static status_t 255 vbe_get_vesa_info(bios_state* state, vesa_info& info) 256 { 257 vbe_info_block* infoHeader = (vbe_info_block*)sBIOSModule->allocate_mem(state, 256); 258 phys_addr_t physicalAddress = sBIOSModule->physical_address(state, infoHeader); 259 260 bios_regs regs = {}; 261 regs.eax = 0x4f00; 262 regs.es = physicalAddress >> 4; 263 regs.edi = physicalAddress - (regs.es << 4); 264 265 status_t status = sBIOSModule->interrupt(state, 0x10, ®s); 266 if (status != B_OK) { 267 dprintf(DEVICE_NAME ": vbe_get_vesa_info(): BIOS failed: %s\n", 268 strerror(status)); 269 return status; 270 } 271 272 if ((regs.eax & 0xffff) != 0x4f) { 273 dprintf(DEVICE_NAME ": vbe_get_vesa_info(): BIOS returned " 274 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 275 return B_ERROR; 276 } 277 278 info.shared_info->vram_size = infoHeader->total_memory * 65536; 279 strlcpy(info.shared_info->name, (char*)sBIOSModule->virtual_address(state, 280 SEGMENTED_TO_LINEAR(infoHeader->oem_string)), 32); 281 282 return status; 283 } 284 285 286 /*! Remaps the frame buffer if necessary; if we've already mapped the complete 287 frame buffer, there is no need to map it again. 288 */ 289 status_t 290 remap_frame_buffer(vesa_info& info, addr_t physicalBase, uint32 width, 291 uint32 height, int8 depth, uint32 bytesPerRow, bool initializing) 292 { 293 vesa_shared_info& sharedInfo = *info.shared_info; 294 addr_t frameBuffer = info.frame_buffer; 295 296 if (!info.complete_frame_buffer_mapped) { 297 addr_t base = physicalBase; 298 size_t size = bytesPerRow * height; 299 bool remap = !initializing; 300 301 if (info.physical_frame_buffer_size != 0) { 302 // we can map the complete frame buffer 303 base = info.physical_frame_buffer; 304 size = info.physical_frame_buffer_size; 305 remap = true; 306 } 307 308 if (remap) { 309 area_id area = map_physical_memory("vesa frame buffer", base, 310 size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, 311 (void**)&frameBuffer); 312 if (area < 0) 313 return area; 314 315 if (initializing) { 316 // We need to manually update the kernel's frame buffer address, 317 // since this frame buffer remapping has not been issued by the 318 // app_server (which would otherwise take care of this) 319 frame_buffer_update(frameBuffer, width, height, depth, 320 bytesPerRow); 321 } 322 323 delete_area(info.shared_info->frame_buffer_area); 324 325 info.frame_buffer = frameBuffer; 326 sharedInfo.frame_buffer_area = area; 327 328 // Turn on write combining for the area 329 vm_set_area_memory_type(area, base, B_MTR_WC); 330 331 if (info.physical_frame_buffer_size != 0) 332 info.complete_frame_buffer_mapped = true; 333 } 334 } 335 336 if (info.complete_frame_buffer_mapped) 337 frameBuffer += physicalBase - info.physical_frame_buffer; 338 339 // Update shared frame buffer information 340 sharedInfo.frame_buffer = (uint8*)frameBuffer; 341 sharedInfo.physical_frame_buffer = (uint8*)physicalBase; 342 sharedInfo.bytes_per_row = bytesPerRow; 343 344 return B_OK; 345 } 346 347 348 // #pragma mark - 349 350 351 status_t 352 vesa_init(vesa_info& info) 353 { 354 frame_buffer_boot_info* bufferInfo 355 = (frame_buffer_boot_info*)get_boot_item(FRAME_BUFFER_BOOT_INFO, NULL); 356 if (bufferInfo == NULL) 357 return B_ERROR; 358 359 info.vbe_capabilities = bufferInfo->vesa_capabilities; 360 info.complete_frame_buffer_mapped = false; 361 362 // Find out which PCI device we belong to, so that we know its frame buffer 363 // size 364 find_graphics_card(bufferInfo->physical_frame_buffer, 365 info.physical_frame_buffer, info.physical_frame_buffer_size); 366 367 size_t modesSize = 0; 368 vesa_mode* modes = (vesa_mode*)get_boot_item(VESA_MODES_BOOT_INFO, 369 &modesSize); 370 info.modes = modes; 371 372 size_t sharedSize = (sizeof(vesa_shared_info) + 7) & ~7; 373 374 info.shared_area = create_area("vesa shared info", 375 (void**)&info.shared_info, B_ANY_KERNEL_ADDRESS, 376 ROUND_TO_PAGE_SIZE(sharedSize + modesSize), B_FULL_LOCK, 377 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA); 378 if (info.shared_area < 0) 379 return info.shared_area; 380 381 vesa_shared_info& sharedInfo = *info.shared_info; 382 383 memset(&sharedInfo, 0, sizeof(vesa_shared_info)); 384 385 if (modes != NULL) { 386 sharedInfo.vesa_mode_offset = sharedSize; 387 sharedInfo.vesa_mode_count = modesSize / sizeof(vesa_mode); 388 389 memcpy((uint8*)&sharedInfo + sharedSize, modes, modesSize); 390 } 391 392 sharedInfo.frame_buffer_area = bufferInfo->area; 393 394 remap_frame_buffer(info, bufferInfo->physical_frame_buffer, 395 bufferInfo->width, bufferInfo->height, bufferInfo->depth, 396 bufferInfo->bytes_per_row, true); 397 // Does not matter if this fails - the frame buffer was already mapped 398 // before. 399 400 sharedInfo.current_mode.virtual_width = bufferInfo->width; 401 sharedInfo.current_mode.virtual_height = bufferInfo->height; 402 sharedInfo.current_mode.space = get_color_space_for_depth( 403 bufferInfo->depth); 404 405 edid1_info* edidInfo = (edid1_info*)get_boot_item(VESA_EDID_BOOT_INFO, 406 NULL); 407 if (edidInfo != NULL) { 408 sharedInfo.has_edid = true; 409 memcpy(&sharedInfo.edid_info, edidInfo, sizeof(edid1_info)); 410 } 411 412 bios_state* state; 413 status_t status = vbe_call_prepare(&state); 414 if (status != B_OK) 415 return status; 416 417 vesa_identify_bios(state, &sharedInfo); 418 419 vbe_get_dpms_capabilities(state, info.vbe_dpms_capabilities, 420 sharedInfo.dpms_capabilities); 421 if (bufferInfo->depth <= 8) 422 vbe_set_bits_per_gun(state, info, 8); 423 424 vbe_call_finish(state); 425 426 dprintf(DEVICE_NAME ": vesa_init() completed successfully!\n"); 427 return B_OK; 428 } 429 430 431 void 432 vesa_uninit(vesa_info& info) 433 { 434 dprintf(DEVICE_NAME": vesa_uninit()\n"); 435 436 delete_area(info.shared_info->frame_buffer_area); 437 delete_area(info.shared_area); 438 } 439 440 441 status_t 442 vesa_set_display_mode(vesa_info& info, uint32 mode) 443 { 444 if (mode >= info.shared_info->vesa_mode_count) 445 return B_ENTRY_NOT_FOUND; 446 447 // Prepare BIOS environment 448 bios_state* state; 449 status_t status = vbe_call_prepare(&state); 450 if (status != B_OK) 451 return status; 452 453 // Get mode information 454 struct vbe_mode_info modeInfo; 455 status = vbe_get_mode_info(state, info.modes[mode].mode, &modeInfo); 456 if (status != B_OK) { 457 dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot get mode info\n"); 458 goto out; 459 } 460 461 // Set mode 462 status = vbe_set_mode(state, info.modes[mode].mode); 463 if (status != B_OK) { 464 dprintf(DEVICE_NAME": vesa_set_display_mode(): cannot set mode\n"); 465 goto out; 466 } 467 468 if (info.modes[mode].bits_per_pixel <= 8) 469 vbe_set_bits_per_gun(state, info, 8); 470 471 // Map new frame buffer if necessary 472 473 status = remap_frame_buffer(info, modeInfo.physical_base, modeInfo.width, 474 modeInfo.height, modeInfo.bits_per_pixel, modeInfo.bytes_per_row, 475 false); 476 if (status == B_OK) { 477 // Update shared frame buffer information 478 info.shared_info->current_mode.virtual_width = modeInfo.width; 479 info.shared_info->current_mode.virtual_height = modeInfo.height; 480 info.shared_info->current_mode.space = get_color_space_for_depth( 481 modeInfo.bits_per_pixel); 482 } 483 484 out: 485 vbe_call_finish(state); 486 return status; 487 } 488 489 490 status_t 491 vesa_get_dpms_mode(vesa_info& info, uint32& mode) 492 { 493 mode = B_DPMS_ON; 494 // we always return a valid mode 495 496 // Prepare BIOS environment 497 bios_state* state; 498 status_t status = vbe_call_prepare(&state); 499 if (status != B_OK) 500 return status; 501 502 bios_regs regs = {}; 503 regs.eax = 0x4f10; 504 regs.ebx = 2; 505 regs.esi = 0; 506 regs.edi = 0; 507 508 status = sBIOSModule->interrupt(state, 0x10, ®s); 509 if (status != B_OK) { 510 dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS failed: %s\n", 511 strerror(status)); 512 goto out; 513 } 514 515 if ((regs.eax & 0xffff) != 0x4f) { 516 dprintf(DEVICE_NAME ": vesa_get_dpms_mode(): BIOS returned " 517 "0x%" B_PRIx32 "\n", regs.eax & 0xffff); 518 status = B_ERROR; 519 goto out; 520 } 521 522 mode = vbe_to_system_dpms(regs.ebx >> 8); 523 524 out: 525 vbe_call_finish(state); 526 return status; 527 } 528 529 530 status_t 531 vesa_set_dpms_mode(vesa_info& info, uint32 mode) 532 { 533 // Only let supported modes through 534 mode &= info.shared_info->dpms_capabilities; 535 536 uint8 vbeMode = 0; 537 if ((mode & B_DPMS_OFF) != 0) 538 vbeMode |= DPMS_OFF | DPMS_REDUCED_ON; 539 if ((mode & B_DPMS_STAND_BY) != 0) 540 vbeMode |= DPMS_STANDBY; 541 if ((mode & B_DPMS_SUSPEND) != 0) 542 vbeMode |= DPMS_SUSPEND; 543 544 vbeMode &= info.vbe_dpms_capabilities; 545 546 // Prepare BIOS environment 547 bios_state* state; 548 status_t status = vbe_call_prepare(&state); 549 if (status != B_OK) 550 return status; 551 552 bios_regs regs = {}; 553 regs.eax = 0x4f10; 554 regs.ebx = (vbeMode << 8) | 1; 555 regs.esi = 0; 556 regs.edi = 0; 557 558 status = sBIOSModule->interrupt(state, 0x10, ®s); 559 if (status != B_OK) { 560 dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS failed: %s\n", 561 strerror(status)); 562 goto out; 563 } 564 565 if ((regs.eax & 0xffff) != 0x4f) { 566 dprintf(DEVICE_NAME ": vesa_set_dpms_mode(): BIOS returned " 567 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 568 status = B_ERROR; 569 goto out; 570 } 571 572 out: 573 vbe_call_finish(state); 574 return status; 575 } 576 577 578 status_t 579 vesa_set_indexed_colors(vesa_info& info, uint8 first, uint8* colors, 580 uint16 count) 581 { 582 bios_regs regs = {}; 583 uint32 shift, physicalAddress; 584 585 if (first + count > 256) 586 count = 256 - first; 587 588 // Prepare BIOS environment 589 bios_state* state; 590 status_t status = vbe_call_prepare(&state); 591 if (status != B_OK) 592 return status; 593 594 uint8* palette = (uint8*)sBIOSModule->allocate_mem(state, 256 * 4); 595 if (palette == NULL) { 596 status = B_NO_MEMORY; 597 goto out; 598 } 599 600 shift = 8 - info.bits_per_gun; 601 602 // convert colors to VESA palette 603 for (int32 i = first; i < count; i++) { 604 uint8 color[3]; 605 if (user_memcpy(color, &colors[i * 3], 3) < B_OK) { 606 status = B_BAD_ADDRESS; 607 goto out; 608 } 609 610 // order is BGR- 611 palette[i * 4 + 0] = color[2] >> shift; 612 palette[i * 4 + 1] = color[1] >> shift; 613 palette[i * 4 + 2] = color[0] >> shift; 614 palette[i * 4 + 3] = 0; 615 } 616 617 // set palette 618 physicalAddress = sBIOSModule->physical_address(state, palette); 619 regs.eax = 0x4f09; 620 regs.ebx = 0; 621 regs.ecx = count; 622 regs.edx = first; 623 regs.es = physicalAddress >> 4; 624 regs.edi = physicalAddress - (regs.es << 4); 625 626 status = sBIOSModule->interrupt(state, 0x10, ®s); 627 if (status != B_OK) { 628 dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS failed: %s\n", 629 strerror(status)); 630 goto out; 631 } 632 633 if ((regs.eax & 0xffff) != 0x4f) { 634 dprintf(DEVICE_NAME ": vesa_set_indexed_colors(): BIOS returned " 635 "0x%04" B_PRIx32 "\n", regs.eax & 0xffff); 636 status = B_ERROR; 637 } 638 639 out: 640 vbe_call_finish(state); 641 return status; 642 } 643