lesson 15, video ports

pull/6/head
Carlos Fenollosa 10 years ago
parent 8f87e4434e
commit 0bd31df1d7

@ -0,0 +1 @@
../14-checkpoint/Makefile

@ -0,0 +1,27 @@
*Concepts you may want to Google beforehand: I/O ports*
**Goal: Learn how to use the VGA card data ports**
We will use C to communicate with devices via I/O registers and ports.
Open `drivers/ports.c` and examine the inline C assembler syntax. It has
some differences, like the order of the source and destination operands,
and the funny syntax to assign variables to operands.
When you understand the concepts, open `kernel/kernel.c` for an example
of use.
In this example we will examine the I/O ports which map the screen cursor
position. Specifically, we will query port `0x3d4` with value `14` to request
the cursor position high byte, and the same port with `15` for the low byte.
When this port is queried, it saves the result in port `0x3d5`
Don't miss the opportunity to use `gdb` to inspect the value of C variables,
since we still can't print them on the screen. To do so, set a breakpoint
for a specific line, `breakpoint kernel.c:21` and use the `print` command
to examine variables. Aren't you glad now that we invested some time in
compiling the cross-compiled gdb? ;)
Finally, we will use the queried cursor position to write a character
at that location.

@ -0,0 +1 @@
../14-checkpoint/boot

@ -0,0 +1,35 @@
/**
* Read a byte from the specified port
*/
unsigned char port_byte_in (unsigned short port) {
unsigned char result;
/* Inline assembler syntax
* !! Notice how the source and destination registers are switched from NASM !!
*
* '"=a" (result)'; set '=' the C variable '(result)' to the value of register e'a'x
* '"d" (port)': map the C variable '(port)' into e'd'x register
*
* Inputs and outputs are separated by colons
*/
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
return result;
}
void port_byte_out (unsigned short port, unsigned char data) {
/* Notice how here both registers are mapped to C variables and
* nothing is returned, thus, no equals '=' in the asm syntax
* However we see a comma since there are two variables in the input area
* and none in the 'return' area
*/
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
}
unsigned short port_word_in (unsigned short port) {
unsigned short result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}
void port_word_out (unsigned short port, unsigned short data) {
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
}

@ -0,0 +1,4 @@
unsigned char port_byte_in (unsigned short port);
void port_byte_out (unsigned short port, unsigned char data);
unsigned short port_word_in (unsigned short port);
void port_word_out (unsigned short port, unsigned short data);

@ -0,0 +1,32 @@
#include "../drivers/ports.h"
void main() {
/* Screen cursor position: ask VGA control register (0x3d4) for bytes
* 14 = high byte of cursor and 15 = low byte of cursor. */
port_byte_out(0x3d4, 14); /* Requesting byte 14: high byte of cursor pos */
/* Data is returned in VGA data register (0x3d5) */
int position = port_byte_in(0x3d5);
position = position << 8; /* high byte */
port_byte_out(0x3d4, 15); /* requesting low byte */
position += port_byte_in(0x3d5);
/* VGA 'cells' consist of the character and its control data
* e.g. 'white on black background', 'red text on white bg', etc */
int offset_from_vga = position * 2;
/* Now you can examine both variables using gdb, since we still
* don't know how to print strings on screen. Run 'make debug' and
* on the gdb console:
* breakpoint kernel.c:21
* continue
* print position
* print offset_from_vga
*/
/* Let's write on the current cursor position, we already know how
* to do that */
char *vga = 0xb8000;
vga[offset_from_vga] = 'X';
vga[offset_from_vga+1] = 0x0f; /* White text on black background */
}
Loading…
Cancel
Save