Generic types; start VGA driver

master
Garrett Mills 3 years ago
parent 4ee62fab50
commit 9e4aaa56ba
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246

@ -9,7 +9,7 @@ DEPS := $(OBJS:.o=.d)
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
CPPFLAGS ?= $(INC_FLAGS) -MMD -MP -g -std=c++11 -Wall
CPPFLAGS ?= $(INC_FLAGS) -MMD -MP -g -std=c++17 -Wall
# Default makefile target
all: os-image

@ -0,0 +1,15 @@
#ifndef KERNEL_CPU_TYPES_H
#define KERNEL_CPU_TYPES_H
// Non-semantic types specific to 32-bit Intel x86
typedef unsigned int u32_t;
typedef int i32_t;
typedef unsigned short u16_t;
typedef short i16_t;
typedef unsigned char u8_t;
typedef char i8_t;
#define LOW16(address) (u16)((address) & 0xffff)
#define HIGH16(address) (u16)(((address) >> 16) & 0xffff)
#endif //KERNEL_CPU_TYPES_H

@ -0,0 +1,149 @@
#include "../kernel/io.h"
#include "vga.h"
int VGA::getOffset(int col, int row) {
return 2 * (row * VGA_MAX_COLS + col);
}
int VGA::getOffsetRow(int offset) {
return offset / (2 * VGA_MAX_COLS);
}
int VGA::getOffsetCol(int offset) {
return (offset - (getOffsetRow(offset) * 2 * VGA_MAX_COLS)) / 2;
}
int VGA::getCursorOffset() {
io_byte_out(REG_VGA_CTL, 14);
int offset = io_byte_in(REG_VGA_DATA) << 8; // High byte
io_byte_out(REG_VGA_CTL, 15);
offset += io_byte_in(REG_VGA_DATA); // Low byte
return offset * 2; // Character cell is 2 bytes, so * position by 2
}
void VGA::setCursorOffset(int offset) {
offset /= 2; // Char cell is 2 bytes, so divide the memory offset by 2 to get position
io_byte_out(REG_VGA_CTL, 14); // write the high-byte
io_byte_out(REG_VGA_DATA, (unsigned char)(offset >> 8)); // get only the high-byte
io_byte_out(REG_VGA_CTL, 15); // write the low-byte
io_byte_out(REG_VGA_DATA, (unsigned char)(offset & 0xff)); // get only the low-byte
}
int VGA::printChar(char character, int col, int row, char attrs) {
// Create a char pointer to the start of video memory
unsigned char* vidmem = (unsigned char*) VGA_ADDRESS;
// If the attributes are nullish, then assume the default
if ( !attrs ) {
attrs = VGA_WHITE_ON_BLACK;
}
// Calculate the video memory offset for the current screen location
int offset;
// If col & row are non-negative, use those
if ( col >= 0 && row >= 0 ) {
offset = getOffset(col, row);
} else {
// Otherwise, use the current location of the cursor.
offset = getCursorOffset();
}
// If we see a newline character, advance offset to the end of the current row,
// so it will be advanced to the first column of the next row.
if ( character == '\n' ) {
int current_row = getOffsetRow(offset);
offset = getOffset(VGA_MAX_COLS - 1, current_row);
} else {
// Otherwise, write the char and its attr byte to the specified vidmem offset
vidmem[offset] = character;
vidmem[offset + 1] = attrs;
}
// Handle scrolling, when we reach the bottom of the screen
offset = adjustScrolling(offset);
// Update the offset to the next cell, 2 bytes ahead of the current one
offset += 2;
// Update the cursor position on the screen device
setCursorOffset(offset);
return offset;
}
void VGA::clearScreen() {
int screen_size = VGA_MAX_COLS * VGA_MAX_ROWS;
unsigned char* vidmem = (unsigned char*) VGA_ADDRESS;
for ( int i = 0; i < screen_size; i += 1 ) {
vidmem[i * 2] = ' ';
vidmem[(i * 2) + 1] = VGA_WHITE_ON_BLACK;
}
setCursorOffset(getOffset(0, 0));
}
int VGA::adjustScrolling(int offset) {
int row = getOffsetRow(offset);
int col = getOffsetCol(offset);
if ( row >= (VGA_MAX_ROWS - 1) && col >= (VGA_MAX_COLS - 2) ) {
advanceScrolling();
return getOffset(col, row - 1);
}
return offset;
}
void VGA::advanceScrolling() {
int screen_size = VGA_MAX_COLS * VGA_MAX_ROWS;
unsigned char* vidmem = (unsigned char*) VGA_ADDRESS;
// Loop over every character cell on the screen
for ( int i = 0; i < screen_size; i += 1 ) {
// Compute the existing offset & row/column
int offset = i * 2;
int col = getOffsetCol(offset);
int row = getOffsetRow(offset);
if ( row > 0 ) {
// If this is not the top (scrolled-off) row, copy the char
// to the same column in the row above it.
int new_offset = getOffset(col, row - 1);
vidmem[new_offset] = vidmem[offset];
vidmem[new_offset + 1] = vidmem[offset + 1];
}
if ( row == (VGA_MAX_ROWS - 1) ) {
// If this is the bottom row, clear the cells.
vidmem[offset] = ' ';
vidmem[offset + 1] = VGA_WHITE_ON_BLACK;
}
}
}
void VGA::printAt(char* string, int col, int row) {
// Update the cursor if col & row nonnegative
if ( col >= 0 && row >= 0 ) {
setCursorOffset(getOffset(col, row));
}
// Loop through each char of the string and print it
int i = 0;
int offset;
while ( string[i] != 0 ) {
offset = printChar(string[i], col, row, VGA_WHITE_ON_BLACK);
// Compute row/col for next iteration
i += 1;
col = getOffsetCol(offset);
row = getOffsetRow(offset);
}
}
void VGA::print(char* string) {
printAt(string, -1, -1);
}

@ -0,0 +1,83 @@
#ifndef KERNEL_VGA_H
#define KERNEL_VGA_H
// Base memory address for MM VGA
#define VGA_ADDRESS 0xb8000
// Max character cell dimensions
#define VGA_MAX_ROWS 25
#define VGA_MAX_COLS 80
// Default color scheme
#define VGA_WHITE_ON_BLACK 0x0f
// Screen device I/O ports
#define REG_VGA_CTL 0x3d4
#define REG_VGA_DATA 0x3d5
class VGA {
protected:
/**
* Given a column and row of a VGA character cell, compute the memory
* offset from the beginning of the VGA video memory of its char and
* attr bytes.
* @param col
* @param row
* @return the computed offset
*/
int getOffset(int col, int row);
int getOffsetRow(int offset);
int getOffsetCol(int offset);
/**
* Get the memory offset of the character cell where the cursor is.
*
* 1. Ask for the high-byte of the offset (data 14)
* 2. Ask for the low-byte (data 15)
*
* @return
*/
int getCursorOffset();
/**
* Given a VGA memory offset, set the cursor to that offset's character cell.
* @param offset
*/
void setCursorOffset(int offset);
/**
* Print a character to the specified position.
*
* If col/row are negative, print to the current cursor position.
* If attribute_byte is 0, default white on black.
*
* @param character
* @param col
* @param row
* @param attribute_byte
*/
int printChar(char character, int col, int row, char attrs);
int adjustScrolling(int offset);
/**
* Scrolls all the character cells up one row, replacing the top
* row and creating a new empty row on the bottom.
*/
void advanceScrolling();
public:
/**
* Resets all video memory characters to empty space and all formatting
* to the default white on black. Then, reset the cursor to the first cell.
*/
void clearScreen();
void printAt(char* string, int col, int row);
void print(char* string);
};
#endif //KERNEL_VGA_H

@ -1,8 +0,0 @@
// Called by boot.asm
void main() {
// Create pointer to a char and point to the first text cell of VGA
char* video_memory = (char*) 0xb8000;
// Write the char X to the video memory to display it on the top-left of screen
*video_memory = 'X';
}

@ -0,0 +1,57 @@
#include "util.h"
/**
* Wrapper function that reads a byte from the specified I/O port.
*
* "=a" (result) - put al register in the `result` var when finished
* "d" (port) - load edx with the specified `port`
*
* @param port
* @return the read byte
*/
u8_t io_byte_in(u16_t port) {
u8_t result;
__asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
return result;
}
/**
* Wrapper function that writes a byte to the specified I/O port.
*
* "a" (data) - load eal with `data`
* "d" (port) - load edx with `port`
*
* @param port
* @param data
*/
void io_byte_out(u16_t port, u8_t data) {
__asm__("out %%al, %%dx" : : "a" (data), "d" (port));
}
/**
* Wrapper function that reads a word from the specified I/O port.
*
* "=a" (result) - put eax register in the `result` var when finished
* "d" (port) - load edx with the specified `port`
*
* @param port
* @return the read word
*/
u16_t io_word_in(u16_t port) {
u16_t result;
__asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
return result;
}
/**
* Wrapper function that writes a word to the specified I/O port.
*
* "a" (data) - load eax with `data`
* "d" (port) - load edx with `port`
*
* @param port
* @param data
*/
void io_word_out(u16_t port, u16_t data) {
__asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
}

@ -0,0 +1,48 @@
#ifndef KERNEL_IO_H
#define KERNEL_IO_H
/**
* Wrapper function that reads a byte from the specified I/O port.
*
* "=a" (result) - put al register in the `result` var when finished
* "d" (port) - load edx with the specified `port`
*
* @param port
* @return the read byte
*/
u8_t io_byte_in(u16_t port);
/**
* Wrapper function that writes a byte to the specified I/O port.
*
* "a" (data) - load eal with `data`
* "d" (port) - load edx with `port`
*
* @param port
* @param data
*/
void io_byte_out(u16_t port, u8_t data);
/**
* Wrapper function that reads a word from the specified I/O port.
*
* "=a" (result) - put eax register in the `result` var when finished
* "d" (port) - load edx with the specified `port`
*
* @param port
* @return the read word
*/
u16_t io_word_in(u16_t port);
/**
* Wrapper function that writes a word to the specified I/O port.
*
* "a" (data) - load eax with `data`
* "d" (port) - load edx with `port`
*
* @param port
* @param data
*/
void io_word_out(u16_t port, u16_t data);
#endif //KERNEL_IO_H

@ -0,0 +1,9 @@
#include "../drivers/vga.h"
// Called by boot.asm
void main() {
VGA vga;
vga.clearScreen();
vga.print("Kernel booted.");
}

@ -0,0 +1,14 @@
/**
* Copy `num_bytes` many bytes from the `source` memory to the
* `destination` memory.
*
* @param source
* @param destination
* @param num_bytes
*/
void mem_copy(char* source, char* destination, int num_bytes) {
for ( int i = 0; i < num_bytes; i += 1 ) {
*(destination + i) = *(source + i);
}
}

@ -0,0 +1,6 @@
#ifndef KERNEL_MEM_H
#define KERNEL_MEM_H
void mem_copy(char* source, char* destination, int num_bytes);
#endif //KERNEL_MEM_H

@ -0,0 +1,6 @@
#ifndef KERNEL_UTIL_H
#define KERNEL_UTIL_H
#include "../cpu/types.h"
#endif //KERNEL_UTIL_H
Loading…
Cancel
Save