Reworked I/O methodology
Instead of passing function pointers, we're passing structs with context now. The idea is the same, I/O functions require some struct with a function pointer and some generic memory that only the output device cares about. I/O just calls it. VGA has been reworked to accomodate this change, as well as default outputs being created for low-overhead use (such as interrupt handlers).
This commit is contained in:
parent
26dd32345f
commit
d6465ade55
8 changed files with 109 additions and 92 deletions
18
include/io.h
18
include/io.h
|
|
@ -8,11 +8,17 @@
|
|||
#define IO_H
|
||||
#include <stdint.h>
|
||||
|
||||
int putc(int (*)(char), char);
|
||||
int print(int (*)(char), const char*);
|
||||
int println(int (*)(char), const char*);
|
||||
int printhex(int (*)(char), uint32_t);
|
||||
int prindec(int (*)(char), uint32_t out);
|
||||
int printf(int (*)(char), const char* fmt, ...);
|
||||
typedef struct char_writer_s char_writer_t;
|
||||
struct char_writer_s {
|
||||
int (*putChar)(void* ctx, char out);
|
||||
void* ctx;
|
||||
};
|
||||
|
||||
int putc(char_writer_t*, char);
|
||||
int print(char_writer_t*, const char*);
|
||||
int println(char_writer_t*, const char*);
|
||||
int printhex(char_writer_t*, uint32_t);
|
||||
int prindec(char_writer_t*, uint32_t out);
|
||||
int printf(char_writer_t*, const char* fmt, ...);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@
|
|||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
#include "asm.h"
|
||||
#include "io.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct SerialState_s {
|
||||
uint16_t port;
|
||||
} SerialState_t;
|
||||
|
||||
extern char_writer_t* default_COM;
|
||||
|
||||
/**
|
||||
* @brief Initialize a serial port for communication
|
||||
* @param port The serial port number to initialize
|
||||
|
|
|
|||
|
|
@ -7,34 +7,37 @@
|
|||
#define VGA_H
|
||||
#define VGA_GRID_COLS 80
|
||||
#define VGA_GRID_ROWS 25
|
||||
#define DEFAULT_ATTRIBUTES 0x0F00
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "io.h"
|
||||
/*
|
||||
* CONSTANTS AND VARIABLES
|
||||
*/
|
||||
|
||||
//Information on the VGA buffer
|
||||
|
||||
extern volatile uint16_t* const vga_buffer;
|
||||
|
||||
//grid is top left origin. This is our cursor!
|
||||
extern int cursor_col;
|
||||
extern int cursor_row;
|
||||
extern uint16_t vga_attributes; // Black background, White foreground
|
||||
typedef struct vga_ctx_s {
|
||||
int cursor_col;
|
||||
int cursor_row;
|
||||
uint16_t attributes;
|
||||
} vga_ctx_t;
|
||||
|
||||
//grid is top left origin. This is our cursor!
|
||||
extern uint16_t vga_attributes; // Black background, White foreground
|
||||
extern char_writer_t* default_vga;
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
||||
//Clear the VGA buffer
|
||||
//Clear the VGA buffer, context optional
|
||||
void vga_clear_ctx(vga_ctx_t* ctx);
|
||||
void vga_clear();
|
||||
//Put a character in the VGA buffer and move the cursor to the right by one
|
||||
void vga_set_attributes(uint8_t attributes);
|
||||
//Write character c to cursor
|
||||
//Implements IO generic ASCII output
|
||||
int vga_out(char c);
|
||||
int vga_out(void* ctx, char c);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,26 +1,34 @@
|
|||
#include "interrupt_handlers.h"
|
||||
#include "vga.h"
|
||||
#include "io.h"
|
||||
#include "serial.h"
|
||||
void generic_isr_handler(StateSnapshot_t* cpu_state) {
|
||||
//We made it to C for our interrupt! For now, let's just print our interrupt to the screen.
|
||||
//What's cookin for outputs?
|
||||
char_writer_t* out = 0;
|
||||
if(default_COM) {
|
||||
out = default_COM;
|
||||
} else if(default_vga) {
|
||||
out = default_vga;
|
||||
vga_clear_ctx(default_vga->ctx);
|
||||
}
|
||||
switch(cpu_state->interrupt_id) {
|
||||
|
||||
|
||||
default:
|
||||
vga_clear();
|
||||
printf(vga_out, "INTERRUPT TRIGGERED! Info below.\n");
|
||||
printf(vga_out, "Int_ID|ERR: %X|%X\n", cpu_state->interrupt_id, cpu_state->error_code);
|
||||
printf(vga_out, "EFLAGS|CS|EIP: %X|%X|%X\n", cpu_state->eflags, cpu_state->cs,cpu_state->eip);
|
||||
printf(vga_out, "GP Registers:\neax:%X\nebx:%X\necx:%X\nedx:%X\nesp:%X\nebp:%X\nesi:%X\nedi:%X\n",
|
||||
cpu_state->eax,
|
||||
cpu_state->ebx,
|
||||
cpu_state->ecx,
|
||||
cpu_state->edx,
|
||||
cpu_state->esp,
|
||||
cpu_state->ebp,
|
||||
cpu_state->esi,
|
||||
cpu_state->edi);
|
||||
printf(vga_out, "HALT!");
|
||||
while(1);
|
||||
if(out){
|
||||
printf(out, "INTERRUPT TRIGGERED! Info below.\n");
|
||||
printf(out, "Int_ID|ERR: %X|%X\n", cpu_state->interrupt_id, cpu_state->error_code);
|
||||
printf(out, "EFLAGS|CS|EIP: %X|%X|%X\n", cpu_state->eflags, cpu_state->cs,cpu_state->eip);
|
||||
printf(out, "GP Registers:\neax:%X\nebx:%X\necx:%X\nedx:%X\nesp:%X\nebp:%X\nesi:%X\nedi:%X\n",
|
||||
cpu_state->eax,
|
||||
cpu_state->ebx,
|
||||
cpu_state->ecx,
|
||||
cpu_state->edx,
|
||||
cpu_state->esp,
|
||||
cpu_state->ebp,
|
||||
cpu_state->esi,
|
||||
cpu_state->edi);
|
||||
printf(out, "HALT!");
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
src/io.c
34
src/io.c
|
|
@ -2,39 +2,39 @@
|
|||
#include "kttools.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
int printhex(int (*sendDataFnc)(char), uint32_t out) {
|
||||
int printhex(char_writer_t* writer, uint32_t out) {
|
||||
char buff[9];
|
||||
i_to_str(out, buff, 9, 0x10);
|
||||
return print(sendDataFnc, buff);
|
||||
return print(writer, buff);
|
||||
}
|
||||
|
||||
int printdec(int (*sendDataFnc)(char), uint32_t out) {
|
||||
int printdec(char_writer_t* writer, uint32_t out) {
|
||||
char buff[11];
|
||||
i_to_str(out, buff, 11, 10);
|
||||
return print(sendDataFnc, buff);
|
||||
return print(writer, buff);
|
||||
}
|
||||
|
||||
int putc(int (*sendDataFnc)(char), char out) {
|
||||
return sendDataFnc(out);
|
||||
int putc(char_writer_t* writer, char out) {
|
||||
return writer->putChar(writer->ctx, out);
|
||||
}
|
||||
|
||||
int print(int (*sendDataFnc)(char), const char* out) {
|
||||
int print(char_writer_t* writer, const char* out) {
|
||||
int ret = 0;
|
||||
for (int i = 0; out[i] != '\0' && !ret; i++)
|
||||
ret = putc(sendDataFnc, out[i]);
|
||||
ret = putc(writer, out[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int println(int (*sendDataFnc)(char), const char* out) {
|
||||
int ret = print(sendDataFnc, out);
|
||||
int println(char_writer_t* writer, const char* out) {
|
||||
int ret = print(writer, out);
|
||||
if(ret)
|
||||
return ret;
|
||||
ret = print(sendDataFnc, "\n");
|
||||
ret = print(writer, "\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print a format string to the outstream function.
|
||||
* @brief Print a format string to the outwriter function.
|
||||
*
|
||||
* Print some format string to the output given in sendDataFnc. Supports a few format strings in C format.
|
||||
*
|
||||
|
|
@ -45,7 +45,7 @@ int println(int (*sendDataFnc)(char), const char* out) {
|
|||
*
|
||||
*/
|
||||
|
||||
int printf(int (*sendDataFnc)(char), const char* fmt, ...) {
|
||||
int printf(char_writer_t* writer, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int ret = 0;
|
||||
|
|
@ -54,17 +54,17 @@ int printf(int (*sendDataFnc)(char), const char* fmt, ...) {
|
|||
fmt++;
|
||||
switch(*fmt) {
|
||||
case 'X':
|
||||
ret = print(sendDataFnc, "0x");
|
||||
ret = print(writer, "0x");
|
||||
case 'x':
|
||||
ret = printhex(sendDataFnc, va_arg(args,uint32_t));
|
||||
ret = printhex(writer, va_arg(args,uint32_t));
|
||||
break;
|
||||
case 'd':
|
||||
ret = printdec(sendDataFnc, va_arg(args,uint32_t));
|
||||
ret = printdec(writer, va_arg(args,uint32_t));
|
||||
break;
|
||||
|
||||
}
|
||||
} else {
|
||||
sendDataFnc(*fmt);
|
||||
ret = putc(writer,*fmt);
|
||||
}
|
||||
fmt++;
|
||||
if(ret)
|
||||
|
|
|
|||
45
src/main.c
45
src/main.c
|
|
@ -1,8 +1,4 @@
|
|||
//Our own code, at this point...
|
||||
//Output table:
|
||||
//0: VGA
|
||||
//1: COM1
|
||||
#define OUTPUT_TYPE 1
|
||||
#include <stdint.h>
|
||||
#include "vga.h"
|
||||
#include "io.h"
|
||||
|
|
@ -16,35 +12,30 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
|||
//First interrupts.
|
||||
setup_idt();
|
||||
|
||||
//Let's pick an output schema.
|
||||
int (*outWriter)(char) = 0;
|
||||
int comstatus = 1234;
|
||||
switch(OUTPUT_TYPE) {
|
||||
case 1:
|
||||
comstatus = serial_init(COM1);
|
||||
if(comstatus) {
|
||||
//Fail...
|
||||
break;
|
||||
}
|
||||
outWriter = serial_send8;
|
||||
break;
|
||||
}
|
||||
//VGA is selected or the selected option failed, falling back
|
||||
if(outWriter == 0){
|
||||
outWriter = vga_out;
|
||||
vga_clear();
|
||||
}
|
||||
//Let's get some output schemas ready.
|
||||
|
||||
printf(outWriter, "Entry eax:%X\n", multiboot_magic);
|
||||
//VGA prep
|
||||
vga_ctx_t vga_ctx;
|
||||
vga_ctx.attributes = DEFAULT_ATTRIBUTES;
|
||||
vga_ctx.cursor_row = 0;
|
||||
vga_ctx.cursor_col = 0;
|
||||
char_writer_t vga_writer;
|
||||
vga_writer.ctx = &vga_ctx;
|
||||
vga_writer.putChar = vga_out;
|
||||
default_vga = &vga_writer;
|
||||
vga_clear_ctx(&vga_ctx);
|
||||
|
||||
|
||||
printf(&vga_writer, "Entry eax:%X\n", multiboot_magic);
|
||||
|
||||
if(multiboot_magic != 0x2BADB002) {
|
||||
println(outWriter, writerState, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
||||
println(&vga_writer, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
||||
return;
|
||||
} else {
|
||||
println(outWriter, writerState, "Multiboot detected! Continuing...");
|
||||
println(&vga_writer, "Multiboot detected! Continuing...");
|
||||
}
|
||||
|
||||
printf(outWriter, writerState, "MEM_LOWER:%X\n", multiboot_info->mem_lower);
|
||||
printf(outWriter, writerState"MEM_UPPER:%X\n", multiboot_info->mem_upper);
|
||||
printf(&vga_writer, "MEM_LOWER:%X\n", multiboot_info->mem_lower);
|
||||
printf(&vga_writer, "MEM_UPPER:%X\n", multiboot_info->mem_upper);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "serial.h"
|
||||
#include <stdint.h>
|
||||
|
||||
char_writer_t* default_COM = 0;
|
||||
|
||||
int serial_init(uint16_t port) {
|
||||
//disable interrupts when messing with it
|
||||
|
|
|
|||
35
src/vga.c
35
src/vga.c
|
|
@ -1,22 +1,29 @@
|
|||
#include "vga.h"
|
||||
#include "kttools.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* VARS
|
||||
*/
|
||||
|
||||
int cursor_col = 0;
|
||||
int cursor_row = 0;
|
||||
volatile uint16_t* const vga_buffer = (uint16_t*)0xB8000;
|
||||
uint16_t vga_attributes = 0x0F00;
|
||||
char_writer_t* default_vga = 0;
|
||||
|
||||
/*
|
||||
* FUNCTIONS
|
||||
*/
|
||||
|
||||
void vga_clear() {
|
||||
for (int col = 0; col < VGA_GRID_COLS; col ++) {
|
||||
void cga_clear() {
|
||||
vga_clear_ctx(0);
|
||||
}
|
||||
|
||||
void vga_clear_ctx(vga_ctx_t* ctx) {
|
||||
uint16_t vga_attributes = DEFAULT_ATTRIBUTES;
|
||||
if(ctx) {
|
||||
ctx->cursor_col = 0;
|
||||
ctx->cursor_row = 0;
|
||||
vga_attributes = ctx->attributes;
|
||||
}
|
||||
for (int col = 0; col < VGA_GRID_COLS; col ++) {
|
||||
for (int row = 0; row < VGA_GRID_ROWS; row ++) {
|
||||
//works out to iterating every cell
|
||||
const size_t index = (VGA_GRID_COLS * row) + col;
|
||||
|
|
@ -30,26 +37,24 @@ void vga_clear() {
|
|||
}
|
||||
}
|
||||
|
||||
int vga_out(char c)
|
||||
int vga_out(void* ctx, char c)
|
||||
{
|
||||
vga_ctx_t* vga_ctx = (vga_ctx_t*) ctx;
|
||||
//Check for some freaky escape character first
|
||||
if(c == '\n') {
|
||||
cursor_col = 0;
|
||||
vga_ctx->cursor_col = 0;
|
||||
//mod implements wraparound
|
||||
cursor_row = (cursor_row + 1) % (VGA_GRID_ROWS-1);
|
||||
vga_ctx->cursor_row = (vga_ctx->cursor_row + 1) % (VGA_GRID_ROWS-1);
|
||||
return 0;
|
||||
}
|
||||
//Calculate where in the vga buffer to put the character
|
||||
const size_t index = (VGA_GRID_COLS * cursor_row) + cursor_col;
|
||||
const size_t index = (VGA_GRID_COLS * vga_ctx->cursor_row) + vga_ctx->cursor_col;
|
||||
//VGA buffer cell consists of the first half attributes, second half character
|
||||
vga_buffer[index] = vga_attributes | c;
|
||||
cursor_col++;
|
||||
vga_buffer[index] = vga_ctx->attributes | c;
|
||||
vga_ctx->cursor_col++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vga_set_attributes(uint8_t attributes) {
|
||||
vga_attributes = ((uint16_t)attributes) << 8;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue