mirror of
https://github.com/cfenollosa/os-tutorial.git
synced 2024-10-27 20:34:19 +00:00
lesson 15, video ports
This commit is contained in:
parent
8f87e4434e
commit
0bd31df1d7
1
15-screen-ports/Makefile
Symbolic link
1
15-screen-ports/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../14-checkpoint/Makefile
|
27
15-screen-ports/README.md
Normal file
27
15-screen-ports/README.md
Normal file
@ -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
15-screen-ports/boot
Symbolic link
1
15-screen-ports/boot
Symbolic link
@ -0,0 +1 @@
|
||||
../14-checkpoint/boot
|
35
15-screen-ports/drivers/ports.c
Normal file
35
15-screen-ports/drivers/ports.c
Normal file
@ -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
15-screen-ports/drivers/ports.h
Normal file
4
15-screen-ports/drivers/ports.h
Normal file
@ -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
15-screen-ports/kernel/kernel.c
Normal file
32
15-screen-ports/kernel/kernel.c
Normal file
@ -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…
Reference in New Issue
Block a user