Serenity Operating System
at master 231 lines 15 kB view raw view rendered
1# Introduction to the Kernel Graphics Subsystem 2 3## What is the Kernel Graphics Subsystem? 4 5The Kernel Graphics Subsystem is the kernel subsystem that is responsible to 6manage all graphics devices, framebuffers, hardware 3D acceleration, memory mappings, etc. 7 8## Responsibilities 9 10* Provide a convenient interface to all supported video hardware in the Kernel. 11* Manage 3D rendering on supported hardware. 12 13## Current Limitations and Future features? 14 15* No locking on who can do `mmap` on DisplayConnector devices currently, which can 16lead to malicious applications "fighting" with WindowServer on what is shown to the user 17from the framebuffer. 18 19# DisplayConnector Devices 20 21The Display Connector devices are an abstraction layer to what is essentially the 22management layer of hardware display (commonly known as scanouts too) output connectors. 23The idea of using such type of device was inspired by Linux, which has a struct called 24`drm_connector` as a base structure for other derived structures in the various Linux DRM drivers. 25 26A Display connector device is typically connected to a group of other connectors as well, 27as it's generally common to have video hardware that utilizes multiple hardware connectors 28to VGA, DisplayPort, HDMI, DVI, etc. However, it can be a stand-alone device too, which 29is the case for the `GenericDisplayConnector` class, that can be initialized without being 30attached to a parent PCI device object at all. 31 32Each display connector is programmatically accessible via a device file, in the 33`/dev/gpu/` directory with a name `connectorX` (X is replaced with the minor number). 34 35Each display connector could be `mmap`-ed to gain control to video RAM directly. 36This works nicely with the kernel TTY subsystem thanks to the role of virtual memory 37in the subsystem. 38 39# Hardware framebuffers 40 41## History lesson on ISA, PCI, VGA (and SVGA) 42 43Since the beginning of video hardware with old-school ISA VGA display adapters, 44there was a window being mapped in the physical address space, being translated 45by the motherboard chipset as read/write to video RAM. When SuperVGA came along 46in the 90s, it expanded the usage of that small VGA window (where it was in very low memory) 47to high resolution framebuffers in very high memory regions. This tradition continues today 48to some extent (excluding hardware which requires DMA from main memory to video memory), 49because it's relatively cheap and easy way to let operating systems to access video RAM 50directly without too much trouble. 51 52Since the main PC x86 computer bus was the IBM ISA bus, there was no easy way to tell where 53the resources of each card were actually located at the IO space nor in the physical memory space. 54There were a couple of attempts to fix this - the most notable was the Plug-and-Play standard. 55 56The real change came from a new computer bus in the mid 90s - the PCI bus. This new bus 57was PnP friendly - no more hardcoded resource allocations which means also that OS drivers 58can find where the firmware (BIOS) mapped the BAR (Base address registers) for the actual resources. 59This was also the era where SuperVGA video adapters started to appear, taking advantage of this 60new bus. 61 62Since VGA was introduced, countless amount of vendors brought their own implementations 63and video adapters for usage in the PC market. By now, most of them are gone, leaving the major 64vendors (Intel, AMD and Nvidia) to still be able to manufacture video adapters which are today 65commonly known as Graphics Processing Unit (abbreviated as GPU) - due to the fact that today 66video adapters are not only outputting pixels to the computer screen, but have a whole set of processors 67to take care of heavy computational tasks of graphics assets, and even general processing tasks nowadays. 68 69SuperVGA was only the first step into this direction, yet SuperVGA is not a standard, but 70a marketing name for is essentially each video adapters' vendor tried to do in the 90s - 71building an extension upon VGA. All of these vendors did that without creating a unified standard, 72like with VGA, which ensured everyone are conforming to well-known and expected video hardware behavior. 73To try to cope with the dire situation, the VBE (Video BIOS extensions) standard was created to 74help BIOS and operating system vendors to be able to get high resolution framebuffer from 75any hardware that complied to the standard. When UEFI came along, the vendors agreed 76to create the Graphics output protocol (known as UEFI GOP), to provide the same set of features 77that VBE had, but now is usable from 64-bit kernel code as long as the kernel didn't shutdown 78the UEFI services (which it really should do) after completing the boot process. 79 80## Then how does it all apply to the subsystem? 81 82Glad you asked! Since hardware framebuffers are still relevant today, we use them 83to put pixels so the video encoder of a GPU can convert these bits into light, so 84you could actually see a picture from a computer screen. Each GPU implements its own 85internal functionality so it might vary from very simple devices (like the QEMU bochs-display 86device, which is nothing more than framebuffer region and a couple of registers to manage it) 87to very complex devices, such as bare metal devices (like Intel integrated GPUs, etc). 88 89The Kernel graphics subsystem strives to manage all of these devices in a unified fashion 90as much as possible. Of course, actual implementations should vary internally in the 91amount of code to handle the actual device, but all basic API being exposed to userspace is the same. 92 93## The role of MMUs and virtual memory 94 95One of the primary goals of the subsystem to is to allow userspace applications, 96like the WindowServer, to utilize the hardware framebuffers, so we can see the SerenityOS 97desktop, and to ensure the internal TTY subsystem in the Kernel can use the same framebuffers 98to put output from kernel virtual consoles when desired to (i.e. the user switched to the 99Virtual console from another console that is in graphics mode). 100 101The SerenityOS kernel utilizes the MMU and virtual memory in a very neat trick to 102give the "feel of control" to whoever did the `mmap` syscall on a DisplayConnector 103device, while keeping the control to the Kernel to decide who accesses the actual VRAM 104at a given time. This works by working with the following assumptions: 105 1061. Current usage of `mmap` is only for direct framebuffer manipulation. This means 107that if we add support for batch buffers or other objects that should reside in VRAM, this trick 108can lead to catastrophic incidents with the underlying hardware. This happens to be this way, due to 109the fact that we essentially can take VRAM access from the WindowServer at anytime we want, 110without the WindowServer being aware of this so it can still function in the background. 1112. We need to know the maximum dimensions of the framebuffers when initializing the device 112and creating the DisplayConnector device at runtime. This happens because we map all the possible 113pages of VRAM framebuffer at that time, and also reserve the same amount of pages in usable 114physical memory space, so we could reserve the contents of VRAM between the switch 115from graphics mode to console mode and vice-versa. 116 117The actual implementation is quite simple, yet powerful enough to let everyone 118live comfortably - each DisplayConnector device is backed by a special VMObject (VMObject is 119the base class for managing virtual memory scenarios easily) that is created when the 120DisplayConnector device is initialized - we need to find the physical address of the 121start of the framebuffer and the maximum resource size (this is where PCI BARs play their role, 122as we can determine with them the physical address by reading their values and also 123the maximum resource size, by doing a very simple write 1s-and-read trick that was introduced 124with the PCI bus when it was created). Then when the object is created, the code ensures 125we reserve for later usage the same amount of pages somewhere else to ensure we preserve 126the contents of VRAM between the switch from console and graphics mode and vice-versa. 127The special VMObject is tied to each `Memory::Region` object, so it can instruct each 128virtual-to-physical memory mapping to be actually re-mapped to wherever we want in physical 129address space, therefore, we do not interrupt any userspace application from drawing its pixels 130to the framebuffer in the background. 131 132## Do you plan supporting old VGA adapters? 133 134Given the nature of the user experience SerenityOS strives to deliver to the users, 135a core requirement from the first day of this project was to only support 32 bit-per-pixel 136(also known as True-color framebuffer) hardware framebuffers. We do support hardware 137framebuffers that neglect the alpha-channel (essentially it's a 24 bit-per-pixel), 138as long as each pixel is aligned to 4 bytes. The QEMU std-vga (bochs-display with 139VGA capabilities) device was chosen as the first device to be supported in the project, 140and that was an excellent choice for that time to put up with the said requirement. 141 142This hard requirement is due to the fact that supporting anything besides True-color 143framebuffers is a *waste of time* for a new modern kernel. Not only that, but relying 144on VGA with modern monitors is essentially settling for blurry, badly-shaped graphics 145on a computer monitor, due to unoptimized resolution scaling with modern screen ratios. 146 147Old VGA adapters are certainly not capable of using high resolution framebuffers 148when operating in pure native VGA mode (i.e. not operating in an extension mode 149of the video adapter), therefore, if the Kernel cannot find a suitable framebuffer 150to work with or a video adapter it has a driver for, then the last resort is to use the old VGA text mode 151console. Therefore, the SerenityOS kernel will probably never support pure VGA functionality. 152That technology was good for operating systems in the 90s, but is not usable anymore. 153 154By doing so, we ensure that legacy cruft is not introduced in the Kernel space. This indeed 155helps keeping the Graphics subsystem lean and flexible to future changes. 156 157## What about the Video BIOS Extensions? It can gives high resolution framebuffers without writing native drivers! 158 159As for using Video BIOS extensions - this requires us to be able to call to BIOS 16-bit real mode 160code. The solutions for these are: 1611. Drop to real mode, invoke the BIOS interrupt and return to our kernel. 1622. Writing a Real-Mode 16-bit emulator, either in Kernel space or userspace. 1633. Use Intel VT-x extensions to simulate a processor running in Real mode. 1644. Use the old v8086 mode in x86 processors to get an hardware monitor of 16-bit tasks. 165 166Neither of these options is suitable for us. Dropping to real mode is quite dangerous task, and breaks 167the concept of memory protection entirely. Writing a real mode emulator is the safest solution, yet can 168take a not negligible amount of effort to get something usable and correct. Using the hardware options 169such as Intel VT-x or the v8086 mode are almost equally equivalent to writing an emulator. 170 171We will probably never support using the Video BIOS extensions because of these reasons: 1721. Major part of this project is to maximize usability and fun on what we do, and turning into legacy-cruft to 173temporarily solve a solution is not the right thing to do. 1742. VBE is not usable on machines that lack support of BIOS. As of 2022, this increasingly becomes a problem 175because many PC vendors dropped support for BIOS (known as CSM [Compatibility Support Module] in UEFI terms). 1763. VBE is limited to whatever the vendor decided to hardcode in the OptionROM of the video adapter, which means 177it can limit us to a small set of resolutions and bits-per-pixel settings, 178some of these settings are not convenient for us, nor suitable for our needs. 1794. VBE lacks the support of detecting if the screen actually supports the resolution settings, 180which means that the operating system has to use other methods to determine if screen output is 181working properly (e.g. waiting for a couple of seconds for user confirmation on the selected settings). 182This is because VBE lacks support of getting the screen EDID because most of the time, 183the EDID resides in a ROM in the computer screen, which is inaccessible without using specific 184methods to extract it (via the Display Data Channel), which are not encoded or implemented in 185the PCI OptionROM of the device. 186This is in contrast to native drivers which are able to do this, and VGA, that never relied on 187such methods and instead relied on all video adapters and computer screen to use an well-known 188specification-defined display modes. 189 190## What are the native drivers that are included in the kernel? what type of configurations are supported? 191 192The kernel can be configured to operate in the following conditions: 1931. Fully-enable the graphics subsystem, initialize every device being supported. 1942. Only use the pre-initialized framebuffer from the bootloader, don't initialize anything else. 1953. Don't use any framebuffer, don't initialize any device. 196 197By default, we try to fully-initialize the graphics subsystem, which means we iterate 198over all PCI devices, searching for VGA compatible devices or Display Controller devices. 199 200We currently natively support QEMU std-vga (and bochs-display) device, VirtIO GPU, VMWare SVGA II adapter, 201and Intel Graphics (Gen 4 only). We try our best to avoid using a pre-initialized framebuffer, so 202if we detect any of the said devices, we simply ignore the pre-initialized framebuffer from the bootloader. 203 204The user can choose to use a different condition of the Graphics subsystem, but hardware limitations 205such as lack of supported hardware can either lead the Kernel to use a pre-initialized framebuffer 206or completely "abandon" graphics usage (as was mentioned in third condition), making the system usable 207only through a VGA 80x25 text mode console. 208 209# Userspace APIs 210 211## Unified Graphics IOCTLs 212 213All graphics ioctls are currently unified and being implemented in one final method 214of the `DisplayDevice` class, to keep implementation consistent as much as possible. 215 216## Syscalls 217 218The `read` and `write` syscalls are not supported and probably will never be. In the transition 219period from the old framebuffer code in the Kernel to the current design, the `mmap` syscall was 220quite dangerous and did not handle multiple userspace programs trying to use it on one device. 221Since that was resolved and `mmap` can be used safely, `read` and `write` syscalls are no longer 222needed and are considered obsolete for this device because no userspace program in Serenity will 223ever need to use them, or test them at the very least. 224 225The `ioctl` syscall is used to control the DisplayConnector device - to invoke 226changing of the current mode-set of a framebuffer, flush the framebuffer, etc. 227 228## Major and minor numbering 229 230The major number is fixed at 226. Minor number is allocated incrementally as instances 231are initialized.