Przeglądaj źródła

lesson 15, video ports

Carlos Fenollosa 10 lat temu
rodzic
commit
0bd31df1d7

+ 1 - 0
15-screen-ports/Makefile

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

+ 27 - 0
15-screen-ports/README.md

@@ -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.

+ 1 - 0
15-screen-ports/boot

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

+ 35 - 0
15-screen-ports/drivers/ports.c

@@ -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));
+}

+ 4 - 0
15-screen-ports/drivers/ports.h

@@ -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);

+ 32 - 0
15-screen-ports/kernel/kernel.c

@@ -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 */
+}