Skip to content

Commit 0bd31df

Browse files
committed
lesson 15, video ports
1 parent 8f87e44 commit 0bd31df

File tree

6 files changed

+100
-0
lines changed

6 files changed

+100
-0
lines changed

15-screen-ports/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../14-checkpoint/Makefile

15-screen-ports/README.md

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

15-screen-ports/boot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../14-checkpoint/boot

15-screen-ports/drivers/ports.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Read a byte from the specified port
3+
*/
4+
unsigned char port_byte_in (unsigned short port) {
5+
unsigned char result;
6+
/* Inline assembler syntax
7+
* !! Notice how the source and destination registers are switched from NASM !!
8+
*
9+
* '"=a" (result)'; set '=' the C variable '(result)' to the value of register e'a'x
10+
* '"d" (port)': map the C variable '(port)' into e'd'x register
11+
*
12+
* Inputs and outputs are separated by colons
13+
*/
14+
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
15+
return result;
16+
}
17+
18+
void port_byte_out (unsigned short port, unsigned char data) {
19+
/* Notice how here both registers are mapped to C variables and
20+
* nothing is returned, thus, no equals '=' in the asm syntax
21+
* However we see a comma since there are two variables in the input area
22+
* and none in the 'return' area
23+
*/
24+
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
25+
}
26+
27+
unsigned short port_word_in (unsigned short port) {
28+
unsigned short result;
29+
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
30+
return result;
31+
}
32+
33+
void port_word_out (unsigned short port, unsigned short data) {
34+
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
35+
}

15-screen-ports/drivers/ports.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
unsigned char port_byte_in (unsigned short port);
2+
void port_byte_out (unsigned short port, unsigned char data);
3+
unsigned short port_word_in (unsigned short port);
4+
void port_word_out (unsigned short port, unsigned short data);

15-screen-ports/kernel/kernel.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "../drivers/ports.h"
2+
3+
void main() {
4+
/* Screen cursor position: ask VGA control register (0x3d4) for bytes
5+
* 14 = high byte of cursor and 15 = low byte of cursor. */
6+
port_byte_out(0x3d4, 14); /* Requesting byte 14: high byte of cursor pos */
7+
/* Data is returned in VGA data register (0x3d5) */
8+
int position = port_byte_in(0x3d5);
9+
position = position << 8; /* high byte */
10+
11+
port_byte_out(0x3d4, 15); /* requesting low byte */
12+
position += port_byte_in(0x3d5);
13+
14+
/* VGA 'cells' consist of the character and its control data
15+
* e.g. 'white on black background', 'red text on white bg', etc */
16+
int offset_from_vga = position * 2;
17+
18+
/* Now you can examine both variables using gdb, since we still
19+
* don't know how to print strings on screen. Run 'make debug' and
20+
* on the gdb console:
21+
* breakpoint kernel.c:21
22+
* continue
23+
* print position
24+
* print offset_from_vga
25+
*/
26+
27+
/* Let's write on the current cursor position, we already know how
28+
* to do that */
29+
char *vga = 0xb8000;
30+
vga[offset_from_vga] = 'X';
31+
vga[offset_from_vga+1] = 0x0f; /* White text on black background */
32+
}

0 commit comments

Comments
 (0)