From b409b3e9d2bc4d6f24f2c47e74287609f589d4d5 Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Sun, 24 May 2020 03:24:25 -0500 Subject: [PATCH] Added support for setting up a serial port. This first serial driver appears to only work correctly in QEMU. --- .gitignore | 1 + Makefile | 2 +- build_numbers.c | 2 +- includes/io.h | 1 + includes/kernel.h | 4 --- includes/serial.h | 23 ++++++++++++++++ kernel/io.s | 10 +++++++ kernel/kmain.c | 30 ++++++++------------- kernel/screen.c | 7 +++-- kernel/serial.c | 59 ++++++++++++++++++++++++++++++++++++++++++ support_files/boch.txt | 1 + 11 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 includes/serial.h create mode 100644 kernel/serial.c diff --git a/.gitignore b/.gitignore index 2c08e49..b302462 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ *.iso *.bin *.ini +*.out diff --git a/Makefile b/Makefile index 54d9a24..dd1578f 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ kernel.iso: kernel.o grub-mkrescue --output=kernel.iso iso qemu: kernel.iso - qemu-system-x86_64 -m 256M -cdrom kernel.iso & + qemu-system-x86_64 -serial stdio -m 256M -cdrom kernel.iso .PHONY: clean clean: diff --git a/build_numbers.c b/build_numbers.c index f3f19aa..234dc3d 100644 --- a/build_numbers.c +++ b/build_numbers.c @@ -1,3 +1,3 @@ #ifndef KERNEL_VERSION_NUMBER -#define KERNEL_VERSION_NUMBER "0.0.1-293" +#define KERNEL_VERSION_NUMBER "0.0.1-333" #endif diff --git a/includes/io.h b/includes/io.h index cc1c42e..f9c55f5 100644 --- a/includes/io.h +++ b/includes/io.h @@ -1,4 +1,5 @@ #ifndef IO_H #define IO_H void outb(unsigned short port, unsigned char data); +unsigned char inb(unsigned short port); #endif diff --git a/includes/kernel.h b/includes/kernel.h index 6146951..b9d8539 100644 --- a/includes/kernel.h +++ b/includes/kernel.h @@ -1,9 +1,5 @@ #ifndef KERNEL_H #define KERNEL_H -void write_screen(unsigned int, char, unsigned char, unsigned char); -void move(unsigned short); -void draw_s(char*, unsigned char, unsigned char); int strlen(char*); -void clear_screen(void); #endif diff --git a/includes/serial.h b/includes/serial.h new file mode 100644 index 0000000..8ddcd6c --- /dev/null +++ b/includes/serial.h @@ -0,0 +1,23 @@ +#ifndef SERIAL_H +#define SERIAL_H +/* All the I/O ports are calculated relative to the data port. This is + because all serial ports have their ports in the same order but they + start at different values. +*/ + +#define COM1_PORT 0x3F8 + +#define SERIAL_DATA_PORT(base) (base) +#define SERIAL_FIFO_COMMAND_PORT(base) (base + 2) +#define SERIAL_LINE_COMMAND_PORT(base) (base + 3) +#define SERIAL_MODEM_COMMAND_PORT(base) (base + 4) +#define SERIAL_LINE_STATUS_PORT(base) (base + 5) + +// Tells the serial port to expect the highest 8 bits on the data port first, +// followed by the lowest 8 bits. +#define SERIAL_LINE_ENABLE_DLAB 0x80 + +void set_serial_baud_rate(unsigned short, unsigned short); +void configure_serial_line(unsigned short); +int serial_transmit_fifo_empty(unsigned int); +#endif diff --git a/kernel/io.s b/kernel/io.s index 1c963c1..73f7f8d 100644 --- a/kernel/io.s +++ b/kernel/io.s @@ -9,3 +9,13 @@ outb: mov dx, [esp + 4] ; Move the address of the I/O port into the DX register out dx, al ; Send the data to the I/O port ret ; Return + +global inb + +; inb - Returns a byte from the give I/O port. +; stack: [esp + 4] The address of the I/O port +; [esp ] The return address +inb: + mov dx, [esp + 4] ; Move the address of the I/O port to the dx register. + in al, dx ; Read a byte from the I/O port and store it in the al register + ret diff --git a/kernel/kmain.c b/kernel/kmain.c index c767f3e..ea9cad9 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -1,10 +1,16 @@ #include "../includes/io.h" +#include "../includes/serial.h" #include "../includes/screen.h" void kmain() { + set_serial_baud_rate(COM1_PORT, 0x03); + configure_serial_line(COM1_PORT); + write_to_com(COM1_PORT, "Info From Kernel: Set up COM1 for messaging.\n"); clear_screen(); + write_to_com(COM1_PORT, "Info From Kernel: Clearing screen.\n"); print_banner(); + write_to_com(COM1_PORT, "Info From Kernel: Displaying OS banner.\n"); //draw_rect(20, 5, 50, 7, 0x4, 0xF); draw_rect(0, 5, 5, 13, 0xF, 0x4); draw_rect(5, 8, 10, 10, 0x4, 0xF); @@ -14,11 +20,13 @@ void kmain() set_cursor(0, 14); move_cursor(0, 14); move_cursor(0, 15); - draw_s("Test print", 0x8, 0xF); + draw_string("Test print", 0x8, 0xF); move_cursor(0, 16); - draw_s("And now the cursor has been moved to y = 16.", 0x1, 0xF); + draw_string("And now the cursor has been moved to y = 16.", 0x1, 0xF); move_cursor(5, 20); - draw_s("Cursor moved over 5 cells and down 4 cells.", 0xF, 0x0); + draw_string("Cursor moved over 5 cells and down 4 cells.", 0xF, 0x0); + draw_string("And the cursor moves to the end of the string", 0x1, 0xF); + draw_string("Now this string should have a newline now:\nAnd now a new line is here.", 0xF, 0x0); //draw_rect(20, 5, 50, 7, 0x4, 0xF); //draw_rect(20, 5, 50, 7, 0x4, 0xF); //draw_rect(20, 5, 50, 7, 0x4, 0xF); @@ -28,19 +36,3 @@ void kmain() //draw_s("And 2nd Row. Now the 3rd row.", 2, 9); asm("hlt"); } - -void write_screen(unsigned int i, char c, unsigned char fg, unsigned char bg) -{ - char *fb = (char *) 0x000B8000; - fb[i] = c; - fb[i + 1] = ((fg & 0x0F) << 4) | (bg & 0x0F); -} - -void move(unsigned short pos) -{ - - outb(0x3D4, 14); - outb(0x3D5, ((pos >> 8 ) & 0x00FF)); - outb(0x3D4, 15); - outb(0x3D5, pos & 0x00FF); -} diff --git a/kernel/screen.c b/kernel/screen.c index cd327f2..23962a9 100644 --- a/kernel/screen.c +++ b/kernel/screen.c @@ -62,11 +62,12 @@ void draw_rect(int start_x, int start_y, int end_x, int end_y, unsigned char fg, } } -void draw_s(char* string, unsigned char fg, unsigned char bg) +void draw_string(char* string, unsigned char fg, unsigned char bg) { unsigned short *video_buffer = 0x000B8000; int attr = ((bg << 4) | (fg & 0x0F)); - for(int i = 0; i < strlen(string); i++) + int length = strlen(string); + for(int i = 0; i < length; i++) { unsigned char current_char = string[i]; unsigned short *where = (unsigned short *) video_buffer + (cursor_y * 80) + i + cursor_x; @@ -78,6 +79,8 @@ void draw_s(char* string, unsigned char fg, unsigned char bg) *where = string[i] | attr << 8; } + + cursor_x = cursor_x + length + 1; } void set_cursor(unsigned char x, unsigned char y){ diff --git a/kernel/serial.c b/kernel/serial.c new file mode 100644 index 0000000..a3a9302 --- /dev/null +++ b/kernel/serial.c @@ -0,0 +1,59 @@ +#include "../includes/io.h" +/* Sets the speed of the data being sent. The default speed of a serial port + is 115,200 bits/s. The argument is a divisor of that number, hence the resulting + speed becomes 115,200 / divisor bits/s. +*/ +void set_serial_baud_rate(unsigned short com, unsigned short divisor){ + outb(com + 3, 0x80);//SERIAL_LINE_ENABLE_DLAB); + + outb(com, (divisor >> 8) & 0x00FF); + + outb(com, divisor & 0x00FF); +} + +void configure_serial_line(unsigned short com){ + + // Configuring the Line + /* d: Enables (1) or disables (0) DLAB + b: Break if controls is enabled (1) + parity: The number of parity bits to use + s: The number of stop bits to use (0 = One Stop, 1 = 1.5 or 2 stops) + dl: Describes the langth of the data + + Bit: | 7 | 6 | 5 4 3 | 2 | 1 0 | + Content: | d | b | parity| s | dl | + Value: | 0 | 0 | 0 0 0 | 0 | 1 1 | = 0x03 + */ + outb(com + 3, 0x03); + // Configuring the Buffers + /* lvl: How many bytes should be stored in the FIFO buffers + bs: If the buffers should be 16 or 64 bytes large + r: Reserved + dma: How the serial port data should be accessed + clt: Clear the transmission FIFO buffer + clr: Clear the reciever FIFO buffer + e: If the FIFO bufffer should be enabled or not + + Bit: | 7 6 | 5 | 4 | 3 | 2 | 1 | 0 | + Content: | lvl | bs| r | dma| clt| clr| e | + Value: | 1 1 | 0 | 0 | 0 | 1 | 1 | 1 | + */ + outb(com + 2, 0xC7); + // Confirgure the Modem + outb(com + 4, 0x03); +} +/* @return 0 if the FIFO is not empty + 1 if the FIFO is empty +*/ +int serial_transmit_fifo_empty(unsigned int com){ + // 0x20 = 0010 0000 + return inb((com + 5) & 0x20); +} + +void write_to_com(unsigned int com, char* msg){ + for(int i = 0; msg[i] != '\0'; i++){ + while(serial_transmit_fifo_empty(com) == 0); + + outb(com, (char) msg[i]); + } +} diff --git a/support_files/boch.txt b/support_files/boch.txt index e36be6f..b1f6326 100644 --- a/support_files/boch.txt +++ b/support_files/boch.txt @@ -7,3 +7,4 @@ boot: cdrom log: bochs.log clock: sync=realtime, time0=local cpu: count=1, ips=1000000 +com1: enabled=1, mode=file, dev=com1.out