From 4899877cec60dc976ef2aa66a32cb3950c901da9 Mon Sep 17 00:00:00 2001 From: lordtet Date: Sun, 29 Jun 2025 01:13:43 -0400 Subject: [PATCH] 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. --- include/io.h | 18 ++++++++++ include/{kio.h => vga.h} | 20 +++++------ src/interrupt_handlers.c | 39 ++++++++++++--------- src/io.c | 75 ++++++++++++++++++++++++++++++++++++++++ src/main.c | 14 ++++---- src/{kio.c => vga.c} | 59 +++---------------------------- 6 files changed, 135 insertions(+), 90 deletions(-) create mode 100644 include/io.h rename include/{kio.h => vga.h} (64%) create mode 100644 src/io.c rename src/{kio.c => vga.c} (50%) diff --git a/include/io.h b/include/io.h new file mode 100644 index 0000000..a58a26e --- /dev/null +++ b/include/io.h @@ -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 + +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 diff --git a/include/kio.h b/include/vga.h similarity index 64% rename from include/kio.h rename to include/vga.h index c5ad053..198a226 100644 --- a/include/kio.h +++ b/include/vga.h @@ -1,10 +1,10 @@ -/* kio.h - * Kernel I/O +/* vga.h + * VGA * - * Responsible for kernel related in/output, such as VGA and serial + * Responsible for VGA buffer control. */ -#ifndef KIO_H -#define KIO_H +#ifndef VGA_H +#define VGA_H #define VGA_GRID_COLS 80 #define VGA_GRID_ROWS 25 #include @@ -31,12 +31,10 @@ extern uint16_t vga_attributes; // Black background, White foreground //Clear the VGA buffer void vga_clear(); //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_print(const char* out); -void vga_println(const char* out); -void vga_printhex(uint32_t out); -void vga_prindec(uint32_t out); -void vga_printf(const char* fmt, ...); +//Write character c to cursor +//Implements IO generic ASCII output +int vga_out(char c); + #endif diff --git a/src/interrupt_handlers.c b/src/interrupt_handlers.c index 362f5a5..c928384 100644 --- a/src/interrupt_handlers.c +++ b/src/interrupt_handlers.c @@ -1,21 +1,26 @@ #include "interrupt_handlers.h" -#include "kio.h" - +#include "vga.h" +#include "io.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. - vga_clear(); - 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); - vga_printf("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); - vga_printf("HALT!"); - while(1); + 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); + } } diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..8cb32cd --- /dev/null +++ b/src/io.c @@ -0,0 +1,75 @@ +#include "io.h" +#include "kttools.h" +#include + +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; + +} diff --git a/src/main.c b/src/main.c index 28dfd22..38c3df1 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,8 @@ //Our own code, at this point... //#include #include -#include "kio.h" +#include "vga.h" +#include "io.h" #include "kttools.h" #include "kmultiboot.h" #include "idt.h" @@ -12,22 +13,21 @@ void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info) //First interrupts. setup_idt(); - //wipe the screen vga_clear(); //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) { - 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; } else { - vga_println("Multiboot detected! Continuing..."); + println(vga_out, "Multiboot detected! Continuing..."); } - vga_printf("MEM_LOWER:%X\n", multiboot_info->mem_lower); - vga_printf("MEM_UPPER:%X\n", multiboot_info->mem_upper); + printf(vga_out, "MEM_LOWER:%X\n", multiboot_info->mem_lower); + printf(vga_out, "MEM_UPPER:%X\n", multiboot_info->mem_upper); } diff --git a/src/kio.c b/src/vga.c similarity index 50% rename from src/kio.c rename to src/vga.c index 24fa2a0..22cf66c 100644 --- a/src/kio.c +++ b/src/vga.c @@ -1,4 +1,4 @@ -#include "kio.h" +#include "vga.h" #include "kttools.h" #include @@ -30,20 +30,21 @@ void vga_clear() { } } -void vga_putc(char c) +int vga_out(char c) { //Check for some freaky escape character first if(c == '\n') { cursor_col = 0; //mod implements wraparound cursor_row = (cursor_row + 1) % (VGA_GRID_ROWS-1); - return; + return 0; } //Calculate where in the vga buffer to put the character 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[index] = vga_attributes | c; cursor_col++; + return 0; } 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++; - } - -}