I'm a teenager who has become very interested in assembly language. I'm trying to write a small operating system in Intel x86 assembler, and I was wondering how to write directly to the screen, as in without relying on the BIOS or any other operating sytems. I was looking through the sources of coreboot, Linux, and Kolibri, among others, in the hopes of finding and understanding some piece of code that does this. I have not yet succeeded in this regard, though I believe I'll take another look at the Linux source code, it being the most understandable to me of the sources I've searched through.
If anybody knows this, or knows where in some piece of source code that I could look at, I would appreciate it if they told me.
Or better yet, if someone knows how to identify what I/O port on an Intel x86 CPU connects to what piece of hardware, that would be appreciated too. The reason I need to ask this, is that in neither the chapter for input/output in the Intel 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture, nor in the sections for the IN or OUT instruction in Volume 3, could I find any of this information. And because it has been too arduous to search for the relevant instructions in the sources that I have.
PART 1
For old VGA modes, there's a fixed address to write to the (legacy) display memory area. For text modes this area starts at 0x000B8000. For graphics modes it starts at 0x000A0000.
For high-resolution video modes (e.g. those set by the VESA/VBE interface) this doesn't work because the size of legacy display memory area is limited to 64 KiB and most high-resolution video modes need a lot more space (e.g. 1024 * 768 * 32-bpp = 2.25 MiB). To get around that there's 2 different methods supported by VBE.
The first method is called "bank switching", where only part of the video card's display memory is mapped into the legacy area at any time (and you can change which part is mapped). This can be quite messy - for example, to draw one pixel you might need to calculate which bank the pixel is in, then switch to that bank, then calculate which offset in the bank. To make this worse, for some video modes (e.g. 24-bpp video modes where there's 3 bytes per pixel) only the first part of a pixel's data might be in one bank and the second part of the same pixel's data is in a different bank. The main benefit of this is that it works with real mode addressing, as the legacy display memory area is below 0x00100000.
The second method is called "Linear Framebuffer" (or just "LFB"), where the video card's entire display memory area can be accessed without any messy bank switching. You have to ask the VESA/VBE interface where this area is (and it's typically in the "PCI hole" somewhere between 0xC0000000 and 0xFFF00000). This means you can't access it in real mode, and need to use protected mode or long mode or "unreal mode".
To find the address of a pixel when you're using an LFB mode, you'd do something like "pixel_address = display_memory_address + y * bytes_per_line + x * bytes_per_pixel". The "bytes_per_line" comes from the VESA/VBE interface (and may not be the same as "horizontal_resolution * bytes_per_pixel" because there can be padding between horizontal lines).
For "bank switched" VBE/VESA modes, it becomes something more like:
pixel_offset = y * bytes_per_line + x * bytes_per_pixel; bank_number = pixel_offset / bank_size; pixel_starting_address_within_bank = pixel_offset % bank_size;
For some old VGA modes (e.g. the 256-colour "mode 0x13") it's very similar to LFB, except there is no padding between lines and you can do "pixel_address = display_memory_address + (y * horizontal_resolution + x) * bytes_per_pixel". For text modes it's basically the same thing, except 2 bytes determine each character and its attribute - e.g. "char_address = display_memory_address + (y * horizontal_resolution + x) * 2". For other old VGA modes (monochrome/2-colour, 4-colour and 16-colour modes) the video card's memory is arranged completely differently. It's split into "planes" where each plane contains one bit of the pixel, and (for e.g.) to update one pixel in a 16-colour mode you need to write to 4 separate planes. For performance reasons the VGA hardware supports different write modes and different read modes, and it can get complicated (too complicated to describe adequately here).
PART 2
For I/O ports (on 80x86, "PC compatibles"), there's 3 general categories. The first is "de facto standard" legacy devices which use fixed I/O ports. This includes things like the PIC chips, ISA DMA controller, PS/2 controller, PIT chip, serial/parallel ports, etc. Almost anything that describes how to program each of these devices will tell you which I/O ports the device uses.
The next category is legacy/ISA devices, where the I/O ports the devices use is determined by jumpers on the card itself, and there's no sane way to determine which I/O ports they use from software. To get around this the end-user has to tell the OS which I/O ports each device uses. Thankfully this crusty stuff has all become obsolete (although that doesn't necessarily mean that nobody is using it).
The third category is "plug & play", where there's some method of asking the device which I/O ports it uses (and in most cases, changing the I/O ports the device uses). An example of this is PCI, where there's a "PCI configuration space" that tells you lots of information about each PCI device. For this categories, there is no way anyone can determine which devices will be using which I/O ports without doing it at run-time, and changing some BIOS settings can cause any/all of these devices to change I/O ports.
Also note that an Intel CPU is only a CPU. Nothing prevents those CPUs from being used in something that is radically different to a "PC compatible" computer. Intel's CPU manuals will never tell you anything about hardware that exists outside of the CPU itself (including the chipset or devices).
Part 3
Probably the best place to go for more information (that's intended for OS developers/hobbyists) is http://osdev.org/ (their wiki and their forums).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With