Added support for setting up a serial port. This first serial driver appears to only work correctly in QEMU.
This commit is contained in:
@@ -4,3 +4,4 @@
|
||||
*.iso
|
||||
*.bin
|
||||
*.ini
|
||||
*.out
|
||||
|
||||
@@ -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:
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
+11
-19
@@ -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);
|
||||
}
|
||||
|
||||
+5
-2
@@ -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){
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user