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