vesa & framebuffer: Clone the framebuffer instead of having it be user-accessible.

This begins paving the way for removal of user access to kernel
address space.

After the previous commits, BDirectWindow and BWindowScreen
still function properly.

Part of #19990.

Change-Id: I8477e43cd517ba67383755a4cb60b00bc117f5d7
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10559
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Augustin Cavalier
2026-03-24 14:01:11 +00:00
committed by waddlesplash
parent 95ace7f374
commit 9be0e148a2
15 changed files with 105 additions and 46 deletions
+1 -5
View File
@@ -37,11 +37,6 @@ struct vesa_shared_info {
display_mode current_mode; display_mode current_mode;
uint32 bytes_per_row; uint32 bytes_per_row;
area_id frame_buffer_area; // area of frame buffer
uint8* frame_buffer;
// pointer to frame buffer (visible by all apps!)
uint8* physical_frame_buffer;
uint32 vesa_mode_offset; uint32 vesa_mode_offset;
uint32 vesa_mode_count; uint32 vesa_mode_count;
@@ -62,6 +57,7 @@ struct vesa_shared_info {
// list ioctls // list ioctls
enum { enum {
VESA_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1, VESA_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1,
VESA_CLONE_FRAME_BUFFER,
VESA_GET_DEVICE_NAME, VESA_GET_DEVICE_NAME,
VESA_SET_DISPLAY_MODE, VESA_SET_DISPLAY_MODE,
VESA_GET_DPMS_MODE, VESA_GET_DPMS_MODE,
@@ -50,6 +50,7 @@ init_common(int device, bool isClone)
gInfo->is_clone = isClone; gInfo->is_clone = isClone;
gInfo->device = device; gInfo->device = device;
gInfo->current_mode = UINT16_MAX; gInfo->current_mode = UINT16_MAX;
gInfo->frame_buffer_area = -1;
// get basic info from driver // get basic info from driver
@@ -74,6 +75,7 @@ init_common(int device, bool isClone)
static void static void
uninit_common(void) uninit_common(void)
{ {
delete_area(gInfo->frame_buffer_area);
delete_area(gInfo->shared_info_area); delete_area(gInfo->shared_info_area);
gInfo->shared_info_area = -1; gInfo->shared_info_area = -1;
gInfo->shared_info = NULL; gInfo->shared_info = NULL;
@@ -106,6 +108,16 @@ framebuffer_init_accelerant(int device)
return status; return status;
} }
area_info info;
status = ioctl(gInfo->device, VESA_CLONE_FRAME_BUFFER, &info, sizeof(info));
if (status != B_OK) {
uninit_common();
return status;
}
gInfo->frame_buffer_area = info.area;
gInfo->frame_buffer = info.address;
return B_OK; return B_OK;
} }
@@ -21,6 +21,10 @@ typedef struct accelerant_info {
// cloned list of standard display modes // cloned list of standard display modes
display_mode *mode_list; display_mode *mode_list;
uint16 current_mode; uint16 current_mode;
area_id frame_buffer_area;
// cloned framebuffer
void* frame_buffer;
} accelerant_info; } accelerant_info;
extern accelerant_info *gInfo; extern accelerant_info *gInfo;
+2 -2
View File
@@ -134,8 +134,8 @@ framebuffer_get_frame_buffer_config(frame_buffer_config* config)
{ {
TRACE(("framebuffer_get_frame_buffer_config()\n")); TRACE(("framebuffer_get_frame_buffer_config()\n"));
config->frame_buffer = gInfo->shared_info->frame_buffer; config->frame_buffer = gInfo->frame_buffer;
config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; config->frame_buffer_dma = NULL;
config->bytes_per_row = gInfo->shared_info->bytes_per_row; config->bytes_per_row = gInfo->shared_info->bytes_per_row;
return B_OK; return B_OK;
@@ -49,6 +49,7 @@ init_common(int device, bool isClone)
gInfo->is_clone = isClone; gInfo->is_clone = isClone;
gInfo->device = device; gInfo->device = device;
gInfo->current_mode = UINT16_MAX; gInfo->current_mode = UINT16_MAX;
gInfo->frame_buffer_area = -1;
// get basic info from driver // get basic info from driver
@@ -110,6 +111,7 @@ vesa_init_accelerant(int device)
// Initialize current mode completely from the mode list // Initialize current mode completely from the mode list
vesa_propose_display_mode(&gInfo->shared_info->current_mode, NULL, NULL); vesa_propose_display_mode(&gInfo->shared_info->current_mode, NULL, NULL);
return B_OK; return B_OK;
} }
@@ -22,6 +22,10 @@ typedef struct accelerant_info {
int16 current_mode; // index in the mode_list, or -1 if using a custom mode int16 current_mode; // index in the mode_list, or -1 if using a custom mode
vesa_mode *vesa_modes; vesa_mode *vesa_modes;
area_id frame_buffer_area;
// cloned framebuffer
void* frame_buffer;
} accelerant_info; } accelerant_info;
extern accelerant_info *gInfo; extern accelerant_info *gInfo;
+24 -3
View File
@@ -231,8 +231,13 @@ vesa_set_display_mode(display_mode* _mode)
if (gInfo->current_mode == i) if (gInfo->current_mode == i)
return B_OK; return B_OK;
status_t result = ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i)); status_t result = ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i));
if (result == B_OK) if (result == B_OK) {
delete_area(gInfo->frame_buffer_area);
gInfo->frame_buffer_area = -1;
gInfo->frame_buffer = NULL;
gInfo->current_mode = i; gInfo->current_mode = i;
}
return result; return result;
} }
} }
@@ -241,6 +246,10 @@ vesa_set_display_mode(display_mode* _mode)
status_t result = ioctl(gInfo->device, VESA_SET_CUSTOM_DISPLAY_MODE, status_t result = ioctl(gInfo->device, VESA_SET_CUSTOM_DISPLAY_MODE,
&mode, sizeof(display_mode)); &mode, sizeof(display_mode));
if (result == B_OK) { if (result == B_OK) {
delete_area(gInfo->frame_buffer_area);
gInfo->frame_buffer_area = -1;
gInfo->frame_buffer = NULL;
gInfo->current_mode = -1; gInfo->current_mode = -1;
} }
@@ -278,8 +287,20 @@ vesa_get_frame_buffer_config(frame_buffer_config* config)
{ {
TRACE(("vesa_get_frame_buffer_config()\n")); TRACE(("vesa_get_frame_buffer_config()\n"));
config->frame_buffer = gInfo->shared_info->frame_buffer; if (gInfo->frame_buffer == NULL) {
config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer; // Clone the current framebuffer.
area_info info;
status_t status = ioctl(gInfo->device, VESA_CLONE_FRAME_BUFFER,
&info, sizeof(info));
if (status != B_OK)
return status;
gInfo->frame_buffer_area = info.area;
gInfo->frame_buffer = info.address;
}
config->frame_buffer = gInfo->frame_buffer;
config->frame_buffer_dma = NULL;
config->bytes_per_row = gInfo->shared_info->bytes_per_row; config->bytes_per_row = gInfo->shared_info->bytes_per_row;
return B_OK; return B_OK;
@@ -17,6 +17,7 @@
#include <OS.h> #include <OS.h>
#include <PCI.h> #include <PCI.h>
#include <SupportDefs.h> #include <SupportDefs.h>
#include <vm/vm.h>
#include <vesa.h> #include <vesa.h>
@@ -113,6 +114,18 @@ device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength)
return B_OK; return B_OK;
case VESA_CLONE_FRAME_BUFFER:
{
void* dummy;
area_id area = vm_clone_area(B_CURRENT_TEAM, "cloned framebuffer",
&dummy, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 0,
info->frame_buffer_area, true);
if (area < 0)
return area;
return _user_get_area_info(area, (area_info*)buffer);
}
// needed to share data between kernel and accelerant // needed to share data between kernel and accelerant
case VESA_GET_PRIVATE_DATA: case VESA_GET_PRIVATE_DATA:
return user_memcpy(buffer, &info->shared_area, sizeof(area_id)); return user_memcpy(buffer, &info->shared_area, sizeof(area_id));
@@ -49,7 +49,7 @@ get_color_space_for_depth(uint32 depth)
static status_t static status_t
remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width, remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width,
uint32 height, int8 depth, uint32 bytesPerRow, bool initializing) uint32 height, int8 depth, uint32 bytesPerRow)
{ {
vesa_shared_info& sharedInfo = *info.shared_info; vesa_shared_info& sharedInfo = *info.shared_info;
addr_t frameBuffer = info.frame_buffer; addr_t frameBuffer = info.frame_buffer;
@@ -63,25 +63,19 @@ remap_frame_buffer(framebuffer_info& info, addr_t physicalBase, uint32 width,
if (area < 0) if (area < 0)
return area; return area;
if (initializing) { frame_buffer_update(frameBuffer, width, height, depth,
// We need to manually update the kernel's frame buffer address, bytesPerRow);
// since this frame buffer remapping has not been issued by the
// app_server (which would otherwise take care of this)
frame_buffer_update(frameBuffer, width, height, depth,
bytesPerRow);
}
delete_area(info.shared_info->frame_buffer_area); vm_change_clones_to_null_areas(info.frame_buffer_area);
delete_area(info.frame_buffer_area);
info.frame_buffer = frameBuffer; info.frame_buffer = frameBuffer;
sharedInfo.frame_buffer_area = area; info.frame_buffer_area = area;
// Turn on write combining for the area // Turn on write combining for the area
vm_set_area_memory_type(area, base, B_WRITE_COMBINING_MEMORY); vm_set_area_memory_type(area, base, B_WRITE_COMBINING_MEMORY);
// Update shared frame buffer information // Update shared frame buffer information
sharedInfo.frame_buffer = (uint8*)frameBuffer;
sharedInfo.physical_frame_buffer = (uint8*)physicalBase;
sharedInfo.bytes_per_row = bytesPerRow; sharedInfo.bytes_per_row = bytesPerRow;
return B_OK; return B_OK;
@@ -112,11 +106,11 @@ framebuffer_init(framebuffer_info& info)
memset(&sharedInfo, 0, sizeof(vesa_shared_info)); memset(&sharedInfo, 0, sizeof(vesa_shared_info));
sharedInfo.frame_buffer_area = bufferInfo->area; info.frame_buffer_area = bufferInfo->area;
remap_frame_buffer(info, bufferInfo->physical_frame_buffer, remap_frame_buffer(info, bufferInfo->physical_frame_buffer,
bufferInfo->width, bufferInfo->height, bufferInfo->depth, bufferInfo->width, bufferInfo->height, bufferInfo->depth,
bufferInfo->bytes_per_row, true); bufferInfo->bytes_per_row);
// Does not matter if this fails - the frame buffer was already mapped // Does not matter if this fails - the frame buffer was already mapped
// before. // before.
@@ -142,6 +136,7 @@ framebuffer_uninit(framebuffer_info& info)
{ {
dprintf(DEVICE_NAME": framebuffer_uninit()\n"); dprintf(DEVICE_NAME": framebuffer_uninit()\n");
delete_area(info.shared_info->frame_buffer_area); vm_change_clones_to_null_areas(info.frame_buffer_area);
delete_area(info.frame_buffer_area);
delete_area(info.shared_area); delete_area(info.shared_area);
} }
@@ -23,6 +23,7 @@ struct framebuffer_info {
struct vesa_shared_info* shared_info; struct vesa_shared_info* shared_info;
area_id shared_area; area_id shared_area;
area_id frame_buffer_area;
addr_t frame_buffer; addr_t frame_buffer;
}; };
@@ -16,6 +16,7 @@
#include <OS.h> #include <OS.h>
#include <PCI.h> #include <PCI.h>
#include <SupportDefs.h> #include <SupportDefs.h>
#include <vm/vm.h>
#include <vesa.h> #include <vesa.h>
@@ -113,6 +114,18 @@ device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength)
return B_OK; return B_OK;
case VESA_CLONE_FRAME_BUFFER:
{
void* dummy;
area_id area = vm_clone_area(B_CURRENT_TEAM, "cloned framebuffer",
&dummy, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 0,
info->frame_buffer_area, true);
if (area < 0)
return area;
return _user_get_area_info(area, (area_info*)buffer);
}
// needed to share data between kernel and accelerant // needed to share data between kernel and accelerant
case VESA_GET_PRIVATE_DATA: case VESA_GET_PRIVATE_DATA:
return user_memcpy(buffer, &info->shared_area, sizeof(area_id)); return user_memcpy(buffer, &info->shared_area, sizeof(area_id));
@@ -215,7 +228,7 @@ device_ioctl(void* cookie, uint32 msg, void* buffer, size_t bufferLength)
if (user_memcpy(&args, buffer, sizeof(args)) != B_OK) if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
return vga_planar_blit(info->shared_info, args.source, return vga_planar_blit(info, args.source,
args.source_bytes_per_row, args.left, args.top, args.source_bytes_per_row, args.left, args.top,
args.right, args.bottom); args.right, args.bottom);
} }
@@ -316,23 +316,19 @@ remap_frame_buffer(vesa_info& info, addr_t physicalBase, uint32 width,
if (remap) { if (remap) {
area_id area = map_physical_memory("vesa frame buffer", base, area_id area = map_physical_memory("vesa frame buffer", base,
size, B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, size, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
(void**)&frameBuffer); (void**)&frameBuffer);
if (area < 0) if (area < 0)
return area; return area;
if (initializing) { frame_buffer_update(frameBuffer, width, height, depth,
// We need to manually update the kernel's frame buffer address, bytesPerRow);
// since this frame buffer remapping has not been issued by the
// app_server (which would otherwise take care of this)
frame_buffer_update(frameBuffer, width, height, depth,
bytesPerRow);
}
delete_area(info.shared_info->frame_buffer_area); vm_change_clones_to_null_areas(info.frame_buffer_area);
delete_area(info.frame_buffer_area);
info.frame_buffer = frameBuffer; info.frame_buffer = frameBuffer;
sharedInfo.frame_buffer_area = area; info.frame_buffer_area = area;
// Turn on write combining for the area // Turn on write combining for the area
vm_set_area_memory_type(area, base, B_WRITE_COMBINING_MEMORY); vm_set_area_memory_type(area, base, B_WRITE_COMBINING_MEMORY);
@@ -346,8 +342,6 @@ remap_frame_buffer(vesa_info& info, addr_t physicalBase, uint32 width,
frameBuffer += physicalBase - info.physical_frame_buffer; frameBuffer += physicalBase - info.physical_frame_buffer;
// Update shared frame buffer information // Update shared frame buffer information
sharedInfo.frame_buffer = (uint8*)frameBuffer;
sharedInfo.physical_frame_buffer = (uint8*)physicalBase;
sharedInfo.bytes_per_row = bytesPerRow; sharedInfo.bytes_per_row = bytesPerRow;
return B_OK; return B_OK;
@@ -400,7 +394,7 @@ vesa_init(vesa_info& info)
memcpy((uint8*)&sharedInfo + sharedSize, modes, modesSize); memcpy((uint8*)&sharedInfo + sharedSize, modes, modesSize);
} }
sharedInfo.frame_buffer_area = bufferInfo->area; info.frame_buffer_area = bufferInfo->area;
remap_frame_buffer(info, bufferInfo->physical_frame_buffer, remap_frame_buffer(info, bufferInfo->physical_frame_buffer,
bufferInfo->width, bufferInfo->height, bufferInfo->depth, bufferInfo->width, bufferInfo->height, bufferInfo->depth,
@@ -476,7 +470,8 @@ vesa_uninit(vesa_info& info)
{ {
dprintf(DEVICE_NAME": vesa_uninit()\n"); dprintf(DEVICE_NAME": vesa_uninit()\n");
delete_area(info.shared_info->frame_buffer_area); vm_change_clones_to_null_areas(info.frame_buffer_area);
delete_area(info.frame_buffer_area);
delete_area(info.shared_area); delete_area(info.shared_area);
} }
@@ -33,6 +33,7 @@ struct vesa_info {
uint8 vbe_capabilities; uint8 vbe_capabilities;
uint8 bits_per_gun; uint8 bits_per_gun;
area_id frame_buffer_area;
addr_t frame_buffer; addr_t frame_buffer;
addr_t physical_frame_buffer; addr_t physical_frame_buffer;
size_t physical_frame_buffer_size; size_t physical_frame_buffer_size;
@@ -7,6 +7,7 @@
#include "vga.h" #include "vga.h"
#include "driver.h" #include "driver.h"
#include <vesa_info.h>
#include <vga.h> #include <vga.h>
#include <KernelExport.h> #include <KernelExport.h>
@@ -40,7 +41,7 @@ vga_set_indexed_colors(uint8 first, uint8 *colors, uint16 count)
status_t status_t
vga_planar_blit(vesa_shared_info *info, uint8 *src, int32 srcBPR, vga_planar_blit(vesa_info *info, uint8 *src, int32 srcBPR,
int32 left, int32 top, int32 right, int32 bottom) int32 left, int32 top, int32 right, int32 bottom)
{ {
// If we don't actually have an ISA bus, bail. // If we don't actually have an ISA bus, bail.
@@ -48,11 +49,11 @@ vga_planar_blit(vesa_shared_info *info, uint8 *src, int32 srcBPR,
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
// If we don't actually have a frame_buffer, bail. // If we don't actually have a frame_buffer, bail.
if (info->frame_buffer == NULL) if (info->frame_buffer == 0)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
int32 dstBPR = info->bytes_per_row; int32 dstBPR = info->shared_info->bytes_per_row;
uint8 *dst = info->frame_buffer + top * dstBPR + left / 8; uint8 *dst = (uint8*)(info->frame_buffer + top * dstBPR + left / 8);
// TODO: this is awfully slow... // TODO: this is awfully slow...
// TODO: assumes BGR order // TODO: assumes BGR order
@@ -6,11 +6,12 @@
#define _VGA_H #define _VGA_H
#include <vesa_info.h> #include "vesa_private.h"
status_t vga_set_indexed_colors(uint8 first, uint8 *colors, uint16 count); status_t vga_set_indexed_colors(uint8 first, uint8 *colors, uint16 count);
status_t vga_planar_blit(vesa_shared_info *info, uint8 *src, int32 srcBPR, status_t vga_planar_blit(vesa_info *info, uint8 *src, int32 srcBPR,
int32 left, int32 top, int32 right, int32 bottom); int32 left, int32 top, int32 right, int32 bottom);
#endif /* _VGA_H */ #endif /* _VGA_H */