From 531ba0c6f5f6f25098098e41856434316c1596c5 Mon Sep 17 00:00:00 2001 From: c0repwn3r Date: Tue, 17 May 2022 10:44:08 -0400 Subject: [PATCH] chore/feat: update include guards / start working on TTY functionality --- Makefile | 4 +- bin/shade.bin | Bin 36456 -> 36456 bytes bin/shade.iso | Bin 26617856 -> 26617856 bytes include/shade/cansid.h | 4 +- include/shade/kmsg.h | 22 ++- include/shade/platform/drivers/keyboard.h | 4 +- .../shade/platform/drivers/vga_text_mode.h | 9 +- include/shade/platform/gdt.h | 4 +- include/shade/platform/interrupts/idt.h | 4 +- include/shade/platform/interrupts/isr.h | 4 +- include/shade/platform/interrupts/pic.h | 4 +- include/shade/platform/ports.h | 4 +- include/shade/tty.h | 137 ++++++++++++++++++ include/shade/util.h | 19 ++- include/shade/version.h | 8 +- obj/kernel/kernel.o | Bin 3928 -> 4024 bytes src/kernel/platform/drivers/vga_text_mode.c | 34 +++-- src/kernel/tty.c | 82 +++++++++++ 18 files changed, 301 insertions(+), 42 deletions(-) create mode 100644 include/shade/tty.h create mode 100644 src/kernel/tty.c diff --git a/Makefile b/Makefile index ff90bb0..ee896a8 100644 --- a/Makefile +++ b/Makefile @@ -49,8 +49,8 @@ bin/shade.iso: bin/shade.bin rm src/iso/boot/shade.bin bin/shade.bin: $(sboot_object_files) $(kernel_object_files) $(libc_object_files) - echo "#ifndef VERSION_H" > include/shade/version.h - echo "#define VERSION_H" >> include/shade/version.h + echo "#ifndef SHADE_VERSION_H" > include/shade/version.h + echo "#define SHADE_VERSION_H" >> include/shade/version.h echo "// This file was autogenerated by the shadeOS build system. It should not be modified." >> include/shade/version.h echo "#define SHADE_OS_KERNEL_VERSION \"$(version)\"" >> include/shade/version.h echo "#define SHADE_OS_KERNEL \"$(stream)\"" >> include/shade/version.h diff --git a/bin/shade.bin b/bin/shade.bin index 612328a20db83d5b6e550993c57decb6f16f4fc3..a20093f646b33bb95c0e3ca2be48ba035f806f96 100755 GIT binary patch delta 3684 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 EKRDOO9smFU diff --git a/bin/shade.iso b/bin/shade.iso index a7b2e8502d1004811b845c6dcf9f874d876ebd1b..564e0885e260bf81c541fb1f37445beed9b735df 100644 GIT binary patch delta 67401 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 +/** + * @brief [ ok ] + * + * @param format + * @param ... + */ void kmsg_ok(char* format, ...); +/** + * @brief [ warn ] + * + * @param format + * @param ... + */ void kmsg_warn(char* format, ...); +/** + * @brief [ fail ] + * + * @param format + * @param ... + */ void kmsg_fail(char* format, ...); #endif \ No newline at end of file diff --git a/include/shade/platform/drivers/keyboard.h b/include/shade/platform/drivers/keyboard.h index 1b7cdec..3a3077c 100644 --- a/include/shade/platform/drivers/keyboard.h +++ b/include/shade/platform/drivers/keyboard.h @@ -1,5 +1,5 @@ -#ifndef KEYBOARD_H -#define KEYBOARD_H +#ifndef SHADE_KEYBOARD_H +#define SHADE_KEYBOARD_H void init_keyboard(); diff --git a/include/shade/platform/drivers/vga_text_mode.h b/include/shade/platform/drivers/vga_text_mode.h index abf8f2a..67da5a8 100644 --- a/include/shade/platform/drivers/vga_text_mode.h +++ b/include/shade/platform/drivers/vga_text_mode.h @@ -1,5 +1,8 @@ -#ifndef PRINT_H -#define PRINT_H +#ifndef SHADE_PRINT_H +#define SHADE_PRINT_H + +#include + #define REG_SCREEN_CTRL 0x3d4 #define REG_SCREEN_DATA 0x3d5 @@ -48,4 +51,6 @@ void kernel_msg_ok(char* msg); void init_state(); +tty_driver_t vga_text_mode_get_driver(); + #endif \ No newline at end of file diff --git a/include/shade/platform/gdt.h b/include/shade/platform/gdt.h index 4ad3f8a..664ab29 100644 --- a/include/shade/platform/gdt.h +++ b/include/shade/platform/gdt.h @@ -1,5 +1,5 @@ -#ifndef GDT_H -#define GDT_H +#ifndef SHADE_GDT_H +#define SHADE_GDT_H #define KERNEL_CODE 0x08 #define KERNEL_DATA 0x10 diff --git a/include/shade/platform/interrupts/idt.h b/include/shade/platform/interrupts/idt.h index b3b328e..4043214 100644 --- a/include/shade/platform/interrupts/idt.h +++ b/include/shade/platform/interrupts/idt.h @@ -1,5 +1,5 @@ -#ifndef IDT_H -#define IDT_H +#ifndef SHADE_IDT_H +#define SHADE_IDT_H #include #include diff --git a/include/shade/platform/interrupts/isr.h b/include/shade/platform/interrupts/isr.h index eb6ec96..af36ee2 100644 --- a/include/shade/platform/interrupts/isr.h +++ b/include/shade/platform/interrupts/isr.h @@ -1,5 +1,5 @@ -#ifndef ISR_H -#define ISR_H +#ifndef SHADE_ISR_H +#define SHADE_ISR_H #include diff --git a/include/shade/platform/interrupts/pic.h b/include/shade/platform/interrupts/pic.h index d83689e..d5e5532 100644 --- a/include/shade/platform/interrupts/pic.h +++ b/include/shade/platform/interrupts/pic.h @@ -1,5 +1,5 @@ -#ifndef PIC_H -#define PIC_H +#ifndef SHADE_PIC_H +#define SHADE_PIC_H #include diff --git a/include/shade/platform/ports.h b/include/shade/platform/ports.h index b5b0524..f406401 100644 --- a/include/shade/platform/ports.h +++ b/include/shade/platform/ports.h @@ -1,5 +1,5 @@ -#ifndef PORTS_H -#define PORTS_H +#ifndef SHADE_PORTS_H +#define SHADE_PORTS_H unsigned char inb(unsigned short port); void outb(unsigned short port, unsigned char data); diff --git a/include/shade/tty.h b/include/shade/tty.h new file mode 100644 index 0000000..ad39e3d --- /dev/null +++ b/include/shade/tty.h @@ -0,0 +1,137 @@ +#ifndef SHADE_TTY_H +#define SHADE_TTY_H + +#include +#include + +/** + * @brief A type to represent a tty driver + * + */ +typedef struct tty_driver_struct { + int max_rows; + int max_cols; + + void (*putchar) (char c, int x, int y, char style); + void (*setcurxy) (int x, int y); +} tty_driver_t; + +/** + * @brief A type to represent a tty + * + */ +typedef struct tty_struct { + // size information + int rows; + int cols; + + // cursor information + int cursor_row; + int cursor_col; + + // stateful information + cansid_state cansid; + + // buffers + tty_ochar_t output_buffer[65536]; + char input_buffer[1024]; + + // driver + tty_driver_t driver; + + // flags + bool active; +} tty_t; + +/** + * @brief A type to represent a printable char + * + */ +typedef struct tty_ochar_struct { + char character; + char style; +} tty_ochar_t; + +tty_t ttys[10]; +int active_tty; + +/** + * @brief Create a new tty_t with the provided driver + * + * @param driver + * @return tty_t + */ +tty_t tty_new(tty_driver_t driver); + +/** + * @brief Switch the screen to the provided tty - clear screen and flip to that tty + * + * @param index + */ +void tty_switch(int index); + +/** + * @brief Print the specified char c on the tty tty, at the current cursor location + * + * @param tty + * @param c + * @see tty_mvpchar + */ +void tty_pchar(int tty, char c); +/** + * @brief Print the specified char t to the tty tty, but move the cursor to x, y first. + * + * @param tty + * @param c + * @param x + * @param y + * @see tty_pchar + */ +void tty_mvpchar(int tty, char c, int x, int y); + +// tty_pnl family +/** + * @brief Print a newline at the current cursor location on the tty tty. + * + * @param tty + * @see tty_mvpnl + */ +void tty_pnl(int tty); +/** + * @brief Move to the specified cursor location and print a newline. + * + * @param tty + * @param c + * @param x + * @param y + * @see tty_pnl + */ +void tty_mvpnl(int tty, int x, int y); + +// tty_clr family +/** + * @brief Clear the entire screen of the specified tty. Uses tty_clrl internally. + * + * @param tty + * @see tty_clrl + */ +void tty_clr(int tty); +/** + * @brief Clear the specified line of the specified tty. + * + * @param tty + * @param line + * @see tty_clr + */ +void tty_clrl(int tty, int line); + +/** + * @brief Set the cursor position on the specified tty to the specified position. + * + * @param tty + * @param x + * @param y + */ +void tty_setcurxy(int tty, int x, int y); + +#endif \ No newline at end of file diff --git a/include/shade/util.h b/include/shade/util.h index 9985e39..fce4514 100644 --- a/include/shade/util.h +++ b/include/shade/util.h @@ -1,10 +1,25 @@ -#ifndef UTIL_H -#define UTIL_H +#ifndef SHADE_UTIL_H +#define SHADE_UTIL_H #define IS_DIGIT(x) (x == '0' || x == '1' || x == '2' || x == '3' || x == '4' || x == '5' || x == '6' || x == '7' || x == '8' || x == '9') #define IS_HEX(x) (IS_DIGIT(x) || x == 'a' || x == 'b' || x == 'c' || x == 'd' || x == 'e' || x == 'f') +/** + * @brief Copy nbytes bytes from source to dest + * + * @param source + * @param dest + * @param nbytes + */ void memcpy(char *source, char *dest, int nbytes); + +/** + * @brief Set len bytes from dest to val + * + * @param dest + * @param val + * @param len + */ void memset(char *dest, char val, int len); #endif \ No newline at end of file diff --git a/include/shade/version.h b/include/shade/version.h index d1f2ec2..00c3dc9 100644 --- a/include/shade/version.h +++ b/include/shade/version.h @@ -1,9 +1,9 @@ -#ifndef VERSION_H -#define VERSION_H +#ifndef SHADE_VERSION_H +#define SHADE_VERSION_H // This file was autogenerated by the shadeOS build system. It should not be modified. #define SHADE_OS_KERNEL_VERSION "0.1.1-alpha" #define SHADE_OS_KERNEL "shade-development" -#define SHADE_OS_BUILD "20b96b2" -#define SHADE_OS_COMPILE_DATE "Sun May 15 07:01:51 PM EDT 2022" +#define SHADE_OS_BUILD "02abf37" +#define SHADE_OS_COMPILE_DATE "Tue May 17 08:32:53 AM EDT 2022" #define SHADE_OS_CODENAME "willow" #endif diff --git a/obj/kernel/kernel.o b/obj/kernel/kernel.o index 300f5fc732a4a4424b367e8fb150c124f51a1b64..56ff0925bdcca54c817075934384d46348c52ed8 100644 GIT binary patch delta 283 zcmca1w?lq{24lrW%_>I0{R}{`14O(45wHJE-om(A!otebR3X4u!PO;1!N|bKh{3=p zF)7X1d~-QdDx)Jvp&^$Mmob+KmnoMSmpPXOmnD}07eWjs#K7S0>};i=;qDizsbFZN zXQ*cY(meSsb2+2L=2VtwMj&;Nbw8_Q3L{8@fq@H%nSoe=3B+Sy$eVnSOMG$z_YcOB z$(20joC+Ke@dJ~0@|ZJjnf#HbozZ=AC9gRrI}1cccyc3)@Z>YRDw7TPI41w#wO|aG lY{+NN_+WA&kX$i&BcDB!1pDMqe0H1yJP<7@U@bj7JOJtZJ*5Bu delta 195 zcmdlXe?xA92BXAA%_>Hw*Z(FjWRaeHfN{Qrp_QSTLV&M=t4oN2k%5sBgONd!rCE~E z=5nS~MnQLHXDbB_cfU|g1w$h}Lp_7ZvMl9{oSUbzL^A@ZkF5JyCqLl+!I(PvCXYGi z2X+Q9m@rwA*PL0 +#include + +// Initialize a new tty_t object with the specified driver +tty_t tty_new(tty_driver_t driver) { + tty_t tty; + tty.active = false; + tty.cansid = cansid_init(); + tty.cols = driver.max_cols; + tty.cursor_col = 0; + tty.cursor_row = 0; + tty.driver = driver; + tty.rows = driver.max_rows; + return tty; +} + +void tty_switch(int index); + +// private function: print the contents of a tty's output buffer to the screen +void _tty_flip(int tty, bool clear) { + // clear the screen if required (used in tty_switch) + if (clear) tty_clr(tty); + // iterate over every (known) character in the tty output buffer + for (int x = 0; x < ttys[tty].cols; x++) { + for (int y = 0; y < ttys[tty].rows; y++) { + // get the tty_ochar_t + tty_ochar_t cr = ttys[tty].output_buffer[x + ttys[tty].cols + y]; + // and print it with the driver + ttys[tty].driver.putchar(cr.character, x, y, cr.style); + } + } + // and update the real cursor position + ttys[tty].driver.setcurxy(ttys[tty].cursor_col, ttys[tty].cursor_row); +} + +// tty_pchar family +void tty_pchar(int tty, char c) { + if (c == 0) { + return; + } + + if (c == '\n') { + tty_pnl(tty); + return; + } + + if (ttys[tty].cursor_col > ttys[tty].cols) { + tty_pnl(tty); + } + + color_char ccr = cansid_process(&ttys[tty].cansid, c); + + tty_ochar_t cr; + cr.character = ccr.ascii; + cr.style = ccr.style; + ttys[tty].output_buffer[ttys[tty].cursor_col + ttys[tty].cols * ttys[tty].cursor_row] = cr; + + ttys[tty].cursor_col++; + tty_setcurxy(tty, ttys[tty].cursor_col, ttys[tty].cursor_row); + + // if tty is selected, flip + if (tty == active_tty) _tty_flip(tty, false); +} + +void tty_mvpchar(int tty, char c, int x, int y) { + tty_setcurxy(tty, x, y); + tty_pchar(tty, c); +} + +// tty_pnl family +void tty_pnl(int tty); +void tty_mvpnl(int tty, int x, int y); + +// tty_clr family +void tty_clr(int tty); // clear entire screen +void tty_clrl(int tty, int line); // clear a line + +void tty_setcurxy(int tty, int x, int y) { + ttys[tty].cursor_col = x; + ttys[tty].cursor_row = y; + ttys[tty].driver.setcurxy(x, y); +} \ No newline at end of file