Added support for setting up a serial port. This first serial driver appears to only work correctly in QEMU.

This commit is contained in:
2020-05-24 03:24:25 -05:00
parent cf88cb98fb
commit b409b3e9d2
11 changed files with 113 additions and 27 deletions
+1
View File
@@ -4,3 +4,4 @@
*.iso *.iso
*.bin *.bin
*.ini *.ini
*.out
+1 -1
View File
@@ -30,7 +30,7 @@ kernel.iso: kernel.o
grub-mkrescue --output=kernel.iso iso grub-mkrescue --output=kernel.iso iso
qemu: kernel.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 .PHONY: clean
clean: clean:
+1 -1
View File
@@ -1,3 +1,3 @@
#ifndef KERNEL_VERSION_NUMBER #ifndef KERNEL_VERSION_NUMBER
#define KERNEL_VERSION_NUMBER "0.0.1-293" #define KERNEL_VERSION_NUMBER "0.0.1-333"
#endif #endif
+1
View File
@@ -1,4 +1,5 @@
#ifndef IO_H #ifndef IO_H
#define IO_H #define IO_H
void outb(unsigned short port, unsigned char data); void outb(unsigned short port, unsigned char data);
unsigned char inb(unsigned short port);
#endif #endif
-4
View File
@@ -1,9 +1,5 @@
#ifndef KERNEL_H #ifndef KERNEL_H
#define 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*); int strlen(char*);
void clear_screen(void);
#endif #endif
+23
View File
@@ -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
+10
View File
@@ -9,3 +9,13 @@ outb:
mov dx, [esp + 4] ; Move the address of the I/O port into the DX register 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 out dx, al ; Send the data to the I/O port
ret ; Return 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
+11 -19
View File
@@ -1,10 +1,16 @@
#include "../includes/io.h" #include "../includes/io.h"
#include "../includes/serial.h"
#include "../includes/screen.h" #include "../includes/screen.h"
void kmain() 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(); clear_screen();
write_to_com(COM1_PORT, "Info From Kernel: Clearing screen.\n");
print_banner(); print_banner();
write_to_com(COM1_PORT, "Info From Kernel: Displaying OS banner.\n");
//draw_rect(20, 5, 50, 7, 0x4, 0xF); //draw_rect(20, 5, 50, 7, 0x4, 0xF);
draw_rect(0, 5, 5, 13, 0xF, 0x4); draw_rect(0, 5, 5, 13, 0xF, 0x4);
draw_rect(5, 8, 10, 10, 0x4, 0xF); draw_rect(5, 8, 10, 10, 0x4, 0xF);
@@ -14,11 +20,13 @@ void kmain()
set_cursor(0, 14); set_cursor(0, 14);
move_cursor(0, 14); move_cursor(0, 14);
move_cursor(0, 15); move_cursor(0, 15);
draw_s("Test print", 0x8, 0xF); draw_string("Test print", 0x8, 0xF);
move_cursor(0, 16); 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); 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); //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); //draw_s("And 2nd Row. Now the 3rd row.", 2, 9);
asm("hlt"); 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);
}
+5 -2
View File
@@ -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; unsigned short *video_buffer = 0x000B8000;
int attr = ((bg << 4) | (fg & 0x0F)); 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 char current_char = string[i];
unsigned short *where = (unsigned short *) video_buffer + (cursor_y * 80) + i + cursor_x; 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; *where = string[i] | attr << 8;
} }
cursor_x = cursor_x + length + 1;
} }
void set_cursor(unsigned char x, unsigned char y){ void set_cursor(unsigned char x, unsigned char y){
+59
View File
@@ -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]);
}
}
+1
View File
@@ -7,3 +7,4 @@ boot: cdrom
log: bochs.log log: bochs.log
clock: sync=realtime, time0=local clock: sync=realtime, time0=local
cpu: count=1, ips=1000000 cpu: count=1, ips=1000000
com1: enabled=1, mode=file, dev=com1.out