Changed I/O to be more generic.
instead of stuffing all of the i/o stuff into the "kio" library, i've decided to rework i/o to be a generic handler that takes in a function pointer for putc, and does the rest of the logic onto that pointer. That way, you can pass any function that can take in characters and move them to buffers. I'll do a writeup on this at some point to document it.
This commit is contained in:
parent
55d5823bde
commit
4899877cec
6 changed files with 135 additions and 90 deletions
18
include/io.h
Normal file
18
include/io.h
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
/* io.h
|
||||||
|
* In/Out
|
||||||
|
*
|
||||||
|
* Common library for handling user i/o. Aims to be mechanic agnostic, and instead
|
||||||
|
* focus on implementing generic functions to format and manipulate data.
|
||||||
|
*/
|
||||||
|
#ifndef IO_H
|
||||||
|
#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, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
/* kio.h
|
/* vga.h
|
||||||
* Kernel I/O
|
* VGA
|
||||||
*
|
*
|
||||||
* Responsible for kernel related in/output, such as VGA and serial
|
* Responsible for VGA buffer control.
|
||||||
*/
|
*/
|
||||||
#ifndef KIO_H
|
#ifndef VGA_H
|
||||||
#define KIO_H
|
#define VGA_H
|
||||||
#define VGA_GRID_COLS 80
|
#define VGA_GRID_COLS 80
|
||||||
#define VGA_GRID_ROWS 25
|
#define VGA_GRID_ROWS 25
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -31,12 +31,10 @@ extern uint16_t vga_attributes; // Black background, White foreground
|
||||||
//Clear the VGA buffer
|
//Clear the VGA buffer
|
||||||
void vga_clear();
|
void vga_clear();
|
||||||
//Put a character in the VGA buffer and move the cursor to the right by one
|
//Put a character in the VGA buffer and move the cursor to the right by one
|
||||||
void vga_putc(char c);
|
|
||||||
void vga_set_attributes(uint8_t attributes);
|
void vga_set_attributes(uint8_t attributes);
|
||||||
void vga_print(const char* out);
|
//Write character c to cursor
|
||||||
void vga_println(const char* out);
|
//Implements IO generic ASCII output
|
||||||
void vga_printhex(uint32_t out);
|
int vga_out(char c);
|
||||||
void vga_prindec(uint32_t out);
|
|
||||||
void vga_printf(const char* fmt, ...);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1,21 +1,26 @@
|
||||||
#include "interrupt_handlers.h"
|
#include "interrupt_handlers.h"
|
||||||
#include "kio.h"
|
#include "vga.h"
|
||||||
|
#include "io.h"
|
||||||
void generic_isr_handler(StateSnapshot_t* cpu_state) {
|
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.
|
//We made it to C for our interrupt! For now, let's just print our interrupt to the screen.
|
||||||
vga_clear();
|
switch(cpu_state->interrupt_id) {
|
||||||
vga_printf("INTERRUPT TRIGGERED! Info below.\n");
|
|
||||||
vga_printf("Int_ID|ERR: %X|%X\n", cpu_state->interrupt_id, cpu_state->error_code);
|
|
||||||
vga_printf("EFLAGS|CS|EIP: %X|%X|%X\n", cpu_state->eflags, cpu_state->cs,cpu_state->eip);
|
default:
|
||||||
vga_printf("GP Registers:\neax:%X\nebx:%X\necx:%X\nedx:%X\nesp:%X\nebp:%X\nesi:%X\nedi:%X\n",
|
vga_clear();
|
||||||
cpu_state->eax,
|
printf(vga_out, "INTERRUPT TRIGGERED! Info below.\n");
|
||||||
cpu_state->ebx,
|
printf(vga_out, "Int_ID|ERR: %X|%X\n", cpu_state->interrupt_id, cpu_state->error_code);
|
||||||
cpu_state->ecx,
|
printf(vga_out, "EFLAGS|CS|EIP: %X|%X|%X\n", cpu_state->eflags, cpu_state->cs,cpu_state->eip);
|
||||||
cpu_state->edx,
|
printf(vga_out, "GP Registers:\neax:%X\nebx:%X\necx:%X\nedx:%X\nesp:%X\nebp:%X\nesi:%X\nedi:%X\n",
|
||||||
cpu_state->esp,
|
cpu_state->eax,
|
||||||
cpu_state->ebp,
|
cpu_state->ebx,
|
||||||
cpu_state->esi,
|
cpu_state->ecx,
|
||||||
cpu_state->edi);
|
cpu_state->edx,
|
||||||
vga_printf("HALT!");
|
cpu_state->esp,
|
||||||
while(1);
|
cpu_state->ebp,
|
||||||
|
cpu_state->esi,
|
||||||
|
cpu_state->edi);
|
||||||
|
printf(vga_out, "HALT!");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
src/io.c
Normal file
75
src/io.c
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
#include "io.h"
|
||||||
|
#include "kttools.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int printhex(int (*sendDataFnc)(char), uint32_t out) {
|
||||||
|
char buff[9];
|
||||||
|
i_to_str(out, buff, 9, 0x10);
|
||||||
|
return print(sendDataFnc, buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
int printdec(int (*sendDataFnc)(char), uint32_t out) {
|
||||||
|
char buff[11];
|
||||||
|
i_to_str(out, buff, 11, 10);
|
||||||
|
return print(sendDataFnc, buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
int putc(int (*sendDataFnc)(char), char out) {
|
||||||
|
return sendDataFnc(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
int print(int (*sendDataFnc)(char), const char* out) {
|
||||||
|
int ret = 0;
|
||||||
|
for (int i = 0; out[i] != '\0' && !ret; i++)
|
||||||
|
ret = putc(sendDataFnc, out[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int println(int (*sendDataFnc)(char), const char* out) {
|
||||||
|
int ret = print(sendDataFnc, out);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
ret = print(sendDataFnc, "\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Print a format string to the outstream function.
|
||||||
|
*
|
||||||
|
* Print some format string to the output given in sendDataFnc. Supports a few format strings in C format.
|
||||||
|
*
|
||||||
|
* @param fmt: The format string to print
|
||||||
|
* @param ...: Values for the format specifiers
|
||||||
|
*
|
||||||
|
* @return No return value
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int printf(int (*sendDataFnc)(char), const char* fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
int ret = 0;
|
||||||
|
while(*fmt) {
|
||||||
|
if(*fmt == '%') {
|
||||||
|
fmt++;
|
||||||
|
switch(*fmt) {
|
||||||
|
case 'X':
|
||||||
|
ret = print(sendDataFnc, "0x");
|
||||||
|
case 'x':
|
||||||
|
ret = printhex(sendDataFnc, va_arg(args,uint32_t));
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
ret = printdec(sendDataFnc, va_arg(args,uint32_t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendDataFnc(*fmt);
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
14
src/main.c
14
src/main.c
|
|
@ -1,7 +1,8 @@
|
||||||
//Our own code, at this point...
|
//Our own code, at this point...
|
||||||
//#include <stddef.h>
|
//#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "kio.h"
|
#include "vga.h"
|
||||||
|
#include "io.h"
|
||||||
#include "kttools.h"
|
#include "kttools.h"
|
||||||
#include "kmultiboot.h"
|
#include "kmultiboot.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
|
|
@ -12,22 +13,21 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
||||||
//First interrupts.
|
//First interrupts.
|
||||||
setup_idt();
|
setup_idt();
|
||||||
|
|
||||||
|
|
||||||
//wipe the screen
|
//wipe the screen
|
||||||
vga_clear();
|
vga_clear();
|
||||||
//We're going to use this buffer as our 8char hex representation for reading mem
|
//We're going to use this buffer as our 8char hex representation for reading mem
|
||||||
|
|
||||||
vga_printf("Entry eax:%X\n", multiboot_magic);
|
printf(vga_out, "Entry eax:%X\n", multiboot_magic);
|
||||||
|
|
||||||
if(multiboot_magic != 0x2BADB002) {
|
if(multiboot_magic != 0x2BADB002) {
|
||||||
vga_println("Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
println(vga_out, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
vga_println("Multiboot detected! Continuing...");
|
println(vga_out, "Multiboot detected! Continuing...");
|
||||||
}
|
}
|
||||||
|
|
||||||
vga_printf("MEM_LOWER:%X\n", multiboot_info->mem_lower);
|
printf(vga_out, "MEM_LOWER:%X\n", multiboot_info->mem_lower);
|
||||||
vga_printf("MEM_UPPER:%X\n", multiboot_info->mem_upper);
|
printf(vga_out, "MEM_UPPER:%X\n", multiboot_info->mem_upper);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "kio.h"
|
#include "vga.h"
|
||||||
#include "kttools.h"
|
#include "kttools.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
@ -30,20 +30,21 @@ void vga_clear() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_putc(char c)
|
int vga_out(char c)
|
||||||
{
|
{
|
||||||
//Check for some freaky escape character first
|
//Check for some freaky escape character first
|
||||||
if(c == '\n') {
|
if(c == '\n') {
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
//mod implements wraparound
|
//mod implements wraparound
|
||||||
cursor_row = (cursor_row + 1) % (VGA_GRID_ROWS-1);
|
cursor_row = (cursor_row + 1) % (VGA_GRID_ROWS-1);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
//Calculate where in the vga buffer to put the character
|
//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 * cursor_row) + cursor_col;
|
||||||
//VGA buffer cell consists of the first half attributes, second half character
|
//VGA buffer cell consists of the first half attributes, second half character
|
||||||
vga_buffer[index] = vga_attributes | c;
|
vga_buffer[index] = vga_attributes | c;
|
||||||
cursor_col++;
|
cursor_col++;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_set_attributes(uint8_t attributes) {
|
void vga_set_attributes(uint8_t attributes) {
|
||||||
|
|
@ -51,61 +52,9 @@ void vga_set_attributes(uint8_t attributes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void vga_print(const char* out) {
|
|
||||||
for (int i = 0; out[i] != '\0'; i++)
|
|
||||||
vga_putc(out[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vga_println(const char* out) {
|
|
||||||
vga_print(out);
|
|
||||||
vga_print("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void vga_printhex(uint32_t out) {
|
|
||||||
char buff[9];
|
|
||||||
i_to_str(out, buff, 9, 0x10);
|
|
||||||
vga_print(buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vga_printdec(uint32_t out) {
|
|
||||||
char buff[11];
|
|
||||||
i_to_str(out, buff, 11, 10);
|
|
||||||
vga_print(buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Print a format string to the VGA output.
|
|
||||||
*
|
|
||||||
* Print some format string to the vga output cleanly. Supports a few format strings in C format.
|
|
||||||
*
|
|
||||||
* @param fmt: The format string to print
|
|
||||||
* @param ...: Values for the format specifiers
|
|
||||||
*
|
|
||||||
* @return No return value
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void vga_printf(const char* fmt, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
while(*fmt) {
|
|
||||||
if(*fmt == '%') {
|
|
||||||
fmt++;
|
|
||||||
switch(*fmt) {
|
|
||||||
case 'X':
|
|
||||||
vga_print("0x");
|
|
||||||
case 'x':
|
|
||||||
vga_printhex(va_arg(args,uint32_t));
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
vga_printdec(va_arg(args,uint32_t));
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vga_putc(*fmt);
|
|
||||||
}
|
|
||||||
fmt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue