1 / 25

VGA System Services

Learn how to access video ROM-BIOS functions using Linux's 'vm86()' system call in VGA systems. Understand 'real-mode' addressing, virtual memory, and executing 8086 code. Explore Linux device-drivers for memory mapping and demo-program creation.

mspurlock
Download Presentation

VGA System Services

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. VGA System Services How to use Linux’s ‘vm86()’ system-call to access the video ROM-BIOS functions

  2. The SVGA firmware • VESA-compliant graphics systems provide built-in service-functions (in adapter ROM) • Services normally execute during ‘startup’ before processor enters ‘protected mode’ • But cpu can still ‘emulate’ 8086 behavior after system has entered protected mode (although kernel privileges are required) • Linux provides the system-call: ‘vm86()’

  3. 8086 • At startup, the Pentium operates like 8086: • Physical memory is directly addressable • But memory addresses are only 20-bits • CPU builds address from a pair of values: • Segment-address (16-bits) in special register • Offset-address (16-bits) in register or memory • Formula: address = (segment<<4) + offset • Address-range: 220 = 1,048,576 bytes

  4. 8086 “real-mode” addresses 16-bits 16-bits “logical” address (software) segment-address offset-address + x 16 physical address (hardware) 20-bit bus address

  5. Effect in the Pentium 4 Gigabyte address-range 1 Megabyte address-range

  6. “Protected” Mode • At startup, the Pentium essentially IS an 8086 processor (operates in “real mode”): • It addresses physical memory like an 8086 • It operates without any privilege-restrictions • But after building essential data-structures the Pentium switches to “protected” mode and turns on “virtual” memory-addressing: • To supports the execution of multiple tasks • To impose restrictions on memory access

  7. Pentium can ‘emulate’ 8086 • Even after it enters “protected” mode, the Pentium can still ‘emulate’ 8086 behavior • This works by creating a ‘virtual 8086’ cpu represented by a special data-structure in memory and triggered by a special opcode • But a few 8086 instructions aren’t allowed (if they could perhaps interfere with other tasks): • Device i/o: IN and OUT • Interrupts: CLI / STI, PUSHF / POPF, INT-n / IRET • Execution: HLT

  8. Entering ‘virtual-8086’ mode V M = 1 N T = 0 -- GS -- FS -- DS EFLAGS register-image -- ES -- SS -- SP EFLAGS -- CS SS:ESP -- IP Kernel’s instruction-stream CS:EIP iret Kernel’s stack

  9. Leaving “virtual-8086” mode • Once Pentium enters virtual-8086 mode, it leaves only when an interrupt or exception occurs (interrupts are caused by electrical signals from external devices, such as the keyboard or mouse -- or by the timer, and exceptions are caused by any attempts to execute “privileged” instructions, to violate the system’s protection restrictions, or to perform some kind of “illegal” operation

  10. Handling exceptions • If an exception occurs while the Pentium is executing in ‘virtual-8086’ mode, registers are saved on the kernel stack and a kernel “exception-handler” is executed • The exception-handler might decide to go ahead and perform an operation (such as device i/o) that the ‘virtual-8086’ was not allowed to do on its own, and then resume executing the suspended virtual-8086 task

  11. Linux’s ‘vm86()’ system-call • Linux allows (privileged) user-programs to invoke the Pentium’s capability to execute real-mode 8086 code in virtual-8086 mode • The user-program “submits” the required data-structure to the kernel, and the kernel enters ‘virtual-8086’ mode • If any restricted instruction is encountered, the kernel returns to the user-program the data-structure storing the saved task-state

  12. Recall the LRMI • We used a software package called LRMI to assist us in executing ‘real mode’ code • The ‘mode3’ utility is built on this package • Now we shall see how LRMI really works! • We propose to write a ‘standalone’ demo- program that executes a useful ‘real mode’ video ROM-BIOS routine (using ‘vm86()’)

  13. Linux Device-Drivers • We will need a way to ‘map’ certain special memory-regions into the user address-space • These regions must be mapped to addresses that an 8086 processor could access (i.e., must be in bottom one-megabyte of virtual memory) • Linux normally “maps” nothing else there • We’ll need device-drivers to perform mappings: /dev/zero (This is a standard part of Linux) /dev/dos (This is a ‘custom’ driver we built)

  14. How ‘/dev/zero’ works • This device lets a user map some unused pages of physical memory into user-space • As the name ‘zero’ suggests, the memory that is provided is initialized to ‘all-zeros’ • This region will be used for the real mode code’s stack-area and data-structures; it could also be loaded with executable code

  15. How ‘/dev/dos’ works • This device lets a user map conventional areas of initialized system memory into a user’s virtual address-space (such as the real-mode Interrupt Vector Table and the ROM-BIOS Data Area); and also the VGA system firmware! • There’s a similar device (‘/dev/mem’) that is a standard part of Linux, but it requires ‘root’ privileges for writing; so we substitute our own device-driver to avoid that ‘hassle’.

  16. The 8086 memory-map ROM-BIOS 0xF0000 – 0xFFFFF Standard parts of the PC design that much code does rely upon VGA ROM 0xC0000 – 0xCFFFF VRAM 0xA0000 – 0xBFFFF one megabyte Real Mode Stack Area Data and Text This arena’s location and size can be adjusted to suit our particular purpose BIOS DATA 0x00400 – 0x00502 Standard parts of the PC design that much code does rely upon IVT 0x00000 – 0x003FF

  17. System preparation • Your system needs a device-node for the ‘/dev/dos’ device special file (normally it’s created by a Linux System Administrator) • But you can use ‘sudo’ to do it, like this: $ sudo mknod /dev/dos c 86 0 $ sudo chmod a+rwx /dev/dos

  18. The actual program-code • Use header-file: #include <sys/vm86.h> • Declare object: struct vm86_struct vm; • Map in the necessary memory-regions • Initialize memory-areas as appropriate • Initialize register-images in ‘vm86_struct’ • Call kernel: int result = vm86( &vm ); • Emulate any input and output instructions

  19. Specific SVGA ROM function • We show how to execute VESA function 0 ‘Get VESA BIOS-Extensions Information’) • It fills in the values of a data-structure that gives information about our SVGA system • Name of that data-structure is ‘VbeInfoBlk’ • Structure-size is 512 bytes, documented in VESA white paper: ‘vbe3.pdf’ (on website)

  20. The calling convention • VESA functions are designed to be called from an 8086 assembly-language program that is executing in real mode (i.e., startup) • Register AX is loaded with value 0x0F00 • Registers ES:DI are loaded with address (segment:offset) of the memory-block that is to be filled in (512 bytes), initialized with 4-character string “VBE2” • Then software interrupt 0x10 is executed

  21. Software interrupt instruction • The effect of executing ‘int-0x10’ is to transfer control to a function in ROM • The entry-point to that function was stored in the (real-mode) Interrupt Vector Table by the ROM-BIOS startup code • We can extract that entry-point address and use its pair of values as initial values for registers CS and IP in our virtual 8086

  22. Emulating ‘in’ and ‘out’ • Whenever an ‘in’ or ‘out’ instruction is encountered in ‘virtual-8086’ mode, our application can do an ‘emulation’ • We decode the instruction and execute it on behalf of the virtual-8086 task, and we increment the IP value to “skip” past that ‘in’ or ‘out’ instruction, then we can resume the interrupted virtual-8086 task by calling ‘vm86()’ again, using the adjusted ‘vm’

  23. Stopping the vm86 execution • We need a way to stop our execution-loop • We do it using a special 8086 instruction that cannot execute in virtual-8086 mode • Instead of emulating it, we stop our loop • Various instructions could serve this aim • We choose to use the ‘hlt’ instruction • It’s just 1-byte; its name suggests the idea

  24. Demo-program: ‘vesainfo.cpp’ • We’ve posted source-code for this demo • It implements the ideas we just discussed • It prints out the information in ‘VbeInfoBlk’ • It is based on the VESA documentation • Exercise: You could try modifying our code to perform VESA function 1 (which is quite similar to function 0): it returns information about support for specific display-modes

  25. Another application? • You can add some code to each case in the ‘my_emulate()’ function that prints out a description of a input or output operation • EXAMPLE: case 0xEE: // ‘outb’ opcode int al = vm->regs.eax & 0xFF; int dx = vm->regs.edx & 0xFFFF; printf( “outb( %02X, %04X )\n”, al, dx ); • May help us “reverse engineer” VGA BIOS

More Related