From ad43ca56b12b911fc6d70698bff8d742003d0e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Ortega=20Froysa?= Date: Mon, 26 Feb 2018 15:02:25 +0100 Subject: [PATCH] Buggy screen driver. --- Makefile | 2 +- drivers/screen.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/screen.h | 5 +-- kernel/kernel.c | 12 +++---- kernel/ports.c | 4 +-- kernel/ports.h | 4 +-- kernel/util.c | 7 ++++ kernel/util.h | 2 ++ 8 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 kernel/util.c create mode 100644 kernel/util.h diff --git a/Makefile b/Makefile index 26ff8db..e6b17d3 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CC=gcc LD=ld LDFLAGS=-melf_i386 -Ttext 0x1000 --oformat binary -OBJ=kernel/kernel_entry.o kernel/kernel.o kernel/ports.o +OBJ=kernel/kernel_entry.o kernel/kernel.o kernel/ports.o kernel/util.o drivers/screen.o all: os-image diff --git a/drivers/screen.c b/drivers/screen.c index bbd07ef..ad85a4c 100644 --- a/drivers/screen.c +++ b/drivers/screen.c @@ -1,6 +1,67 @@ #include "screen.h" #include "../kernel/ports.h" +#include "../kernel/util.h" + +int get_screen_offset(int col, int row) { + return (row * MAX_COLS + col) * 2; +} + +int get_cursor() { + /* + * screens use their control register as an index to + * select their internal registers of which: + * - 14: high byte of the cursor's offset + * - 15: low byte of the cursor's offset + */ + port_byte_out(REG_SCREEN_CTRL, 14); + /* get the high byte and shift it a byte */ + int offset = port_byte_in(REG_SCREEN_DATA) << 8; + port_byte_out(REG_SCREEN_CTRL, 15); + /* now add the low byte with the free space from before */ + offset += port_byte_in(REG_SCREEN_DATA); + + /* remember: each cell is two bytes, not one */ + return offset * 2; +} + +void set_cursor(int offset) { + /* convert from cell offset to char offset */ + offset /= 2; + + port_byte_out(REG_SCREEN_CTRL, 14); + port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8)); + port_byte_out(REG_SCREEN_CTRL, 15); +} + +int handle_scrolling(int cursor_offset) { + /* if within the screen then don't modify */ + if(cursor_offset < MAX_ROWS * MAX_COLS * 2) + return cursor_offset; + + /* translate rows back by one */ + unsigned int i; + for(i = 1; i < MAX_ROWS; ++i) + { + memory_copy((char*)get_screen_offset(0, i) + VIDEO_ADDRESS, + (char*)get_screen_offset(0, i - 1) + VIDEO_ADDRESS, + MAX_COLS * 2); + } + + /* set last line to blank */ + char *last_line = (char*)get_screen_offset(0, MAX_ROWS - 1) + VIDEO_ADDRESS; + for(i = 0; i < MAX_COLS * 2; ++i) + last_line[i] = 0; + + /* + * move the cursor offset to the last row instead of + * off the screen + */ + cursor_offset -= MAX_COLS * 2; + + /* updated cursor position */ + return cursor_offset; +} void print_char(char c, int col, int row, char attr_byte) { unsigned char *vidmem = (unsigned char*) VIDEO_ADDRESS; @@ -44,3 +105,30 @@ void print_char(char c, int col, int row, char attr_byte) { /* update the cursor position */ set_cursor(offset); } + +void print_at(const char *msg, int col, int row) { + if(col >= 0 && row >= 0) + set_cursor(get_screen_offset(col, row)); + + int i; + for(i = 0; msg[i] != 0; ++i) + print_char(msg[i], col, row, WHITE_ON_BLACK); +} + +void print(const char *msg) { + print_at(msg, -1, -1); +} + +void clear_screen() { + int row, col; + + for(row = 0; row < MAX_ROWS; ++row) + { + for(col = 0; col < MAX_COLS; ++col) + { + print_char(' ', col, row, WHITE_ON_BLACK); + } + } + + set_cursor(get_screen_offset(0, 0)); +} diff --git a/drivers/screen.h b/drivers/screen.h index d07f2cb..704b79c 100644 --- a/drivers/screen.h +++ b/drivers/screen.h @@ -9,5 +9,6 @@ #define REG_SCREEN_CTRL 0x3d4 #define REG_SCREEN_DATA 0x3d5 -void print_char(char c, int col, int row, char attr_byte); -int get_screen_offset(int col, int row); +void print_at(const char *msg, int col, int row); +void print(const char *msg); +void clear_screen(); diff --git a/kernel/kernel.c b/kernel/kernel.c index 0592e41..cc9028c 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,10 +1,6 @@ +#include "../drivers/screen.h" + void main() { - /* - * point to first text cell of the video memory - */ - char *video_memory = (char*) 0xb8000; - /* - * store the character 'X' there - */ - *video_memory = 'X'; + /*clear_screen(); + print_at("This is a test.", 0, 0);*/ } diff --git a/kernel/ports.c b/kernel/ports.c index a795775..bffb3b6 100644 --- a/kernel/ports.c +++ b/kernel/ports.c @@ -1,4 +1,4 @@ -unsigned char port_byte_in(unsigned char port) { +unsigned char port_byte_in(unsigned short port) { unsigned char res; /* * `"=a" (res)' means: put result of `al' into `res' variable @@ -8,7 +8,7 @@ unsigned char port_byte_in(unsigned char port) { return res; } -void port_byte_out(unsigned char port, unsigned char data) { +void port_byte_out(unsigned short port, unsigned char data) { __asm__("out %%al, %%dx" : : "a" (data), "d" (port)); } diff --git a/kernel/ports.h b/kernel/ports.h index ab47a3b..a50b4ce 100644 --- a/kernel/ports.h +++ b/kernel/ports.h @@ -3,11 +3,11 @@ /* * return a byte from a port. */ -unsigned char port_byte_in(unsigned char port); +unsigned char port_byte_in(unsigned short port); /* * write a byte of data to a port. */ -void port_byte_out(unsigned char port, unsigned char data); +void port_byte_out(unsigned short port, unsigned char data); /* * return a word of data from a port. */ diff --git a/kernel/util.c b/kernel/util.c new file mode 100644 index 0000000..4f2e7dd --- /dev/null +++ b/kernel/util.c @@ -0,0 +1,7 @@ +void memory_copy(char *src, char *dest, unsigned int n) { + unsigned int i; + for(i = 0; i < n; ++i) + { + dest[i] = src[i]; + } +} diff --git a/kernel/util.h b/kernel/util.h new file mode 100644 index 0000000..8dd80d7 --- /dev/null +++ b/kernel/util.h @@ -0,0 +1,2 @@ +#pragma once +void memory_copy(char *src, char *dest, unsigned int n);