Basic serial driver

This commit is contained in:
Jarkko Toivanen 2023-06-15 03:06:27 +03:00
parent e9fd2e98bf
commit c33a57fa33
Signed by: jt
GPG key ID: 9151B109B73ECAD5
4 changed files with 91 additions and 12 deletions

View file

@ -8,16 +8,18 @@ kernel.o: kernel.c
tcc -m32 -c kernel.c tcc -m32 -c kernel.c
vga.o: vga.c vga.o: vga.c
tcc -m32 -c vga.c tcc -m32 -c vga.c
serial.o: serial.c
tcc -m32 -c serial.c
kernel-i386.elf: kernel.o start32.o vga.o kernel-i386.elf: kernel.o start32.o vga.o serial.o
tcc -m32 -nostdlib -Wl,-Ttext,0x100000 start32.o kernel.o vga.o -o kernel-i386.elf tcc -m32 -nostdlib -Wl,-Ttext,0x100000 start32.o kernel.o vga.o serial.o -o kernel-i386.elf
qemu-multiboot: kernel-i386.elf qemu-multiboot: kernel-i386.elf
qemu-system-i386 -kernel kernel-i386.elf -serial stdio qemu-system-i386 -kernel kernel-i386.elf -serial stdio
qemu-image: kernel-i386.elf mount qemu-image: kernel-i386.elf mount
cp kernel-i386.elf mnt/ cp kernel-i386.elf mnt/
sync sync
qemu-system-i386 koalemos.img -serial stdio qemu-system-i386 koalemos.img -serial stdio
mount: koalemos.img mnt/ mount: koalemos.img mnt/
@if ! mountpoint -q "mnt/"; then \ @if ! mountpoint -q "mnt/"; then \

View file

@ -1,9 +1,15 @@
#include "multiboot.h" #include "multiboot.h"
#include "vga.h" #include "vga.h"
#include "serial.h"
static inline void outb(unsigned short port, unsigned char val) { static inline void outb(unsigned short port, unsigned char val) {
asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port) : "memory"); asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
} }
static inline unsigned char inb(unsigned short port) {
unsigned char ret;
asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port) : "memory");
return ret;
}
char* itoa(int value, int base) { char* itoa(int value, int base) {
char* result; char* result;
@ -41,6 +47,14 @@ void kmain (unsigned int mbootmagick, multiboot_info_t* mbootinfo) {
vga_init(VGA_COLOR_BLACK, VGA_COLOR_GRAY); vga_init(VGA_COLOR_BLACK, VGA_COLOR_GRAY);
vga_write_line("=== KoalemOS ==="); vga_write_line("=== KoalemOS ===");
if (serial_init() > 0) {
vga_write_line_color("Serial initialization failed", VGA_COLOR_BLACK,
VGA_COLOR_ORANGE);
} else {
vga_write_line("\nInitialized serial.");
serial_write_string("\n=== KoalemOS ===\n");
}
vga_write("Checking multiboot loader: "); vga_write("Checking multiboot loader: ");
// Check multiboot header // Check multiboot header
@ -56,23 +70,30 @@ void kmain (unsigned int mbootmagick, multiboot_info_t* mbootinfo) {
vga_write("\nMultiboot flags: "); vga_write("\nMultiboot flags: ");
vga_write(itoa(mbootinfo->flags, 2)); vga_write(itoa(mbootinfo->flags, 2));
// Check videomode serial_write_string("\nMultiboot flags: ");
vga_write("\nVideomode: "); serial_write_string(itoa(mbootinfo->flags, 2));
// Check videomode
if (mbootinfo->flags & MULTIBOOT_INFO_VBE_INFO) { if (mbootinfo->flags & MULTIBOOT_INFO_VBE_INFO) {
vga_write("VBE 0x"); vga_write("\nVBE Mode: 0x");
vga_write(itoa(mbootinfo->vbe_mode, 16)); vga_write(itoa(mbootinfo->vbe_mode, 16));
} else if (mbootinfo->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) { serial_write_string("\nVBE Mode: 0x");
vga_write("Framebuffer"); serial_write_string(itoa(mbootinfo->vbe_mode, 16));
vga_write("\nVideo address: 0x"); }
if (mbootinfo->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO) {
vga_write("\nFramebuffer: ");
vga_write("address: 0x");
vga_write(itoa(mbootinfo->framebuffer_addr, 16)); vga_write(itoa(mbootinfo->framebuffer_addr, 16));
unsigned long long *vmem = &mbootinfo->framebuffer_addr; serial_write_string("\nFramebuffer: ");
serial_write_string("address: 0x");
serial_write_string(itoa(mbootinfo->framebuffer_addr, 16));
unsigned long *vmem = &mbootinfo->framebuffer_addr;
*vmem = 0xff00ff; *vmem = 0xff00ff;
} else { } else {
vga_write_color("Not available", VGA_COLOR_BLACK, VGA_COLOR_RED); vga_write_color("Info not available", VGA_COLOR_BLACK, VGA_COLOR_RED);
serial_write_string("Info not available");
return; return;
} }
vga_write_line("\nExecution finished, halting..."); vga_write_line("\nExecution finished, halting...");
} }

49
serial.c Normal file
View file

@ -0,0 +1,49 @@
#include "serial.h"
#define PORT 0x3f8 // COM1
static inline void outb(unsigned short port, unsigned char val) {
asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
}
static inline unsigned char inb(unsigned short port) {
unsigned char ret;
asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port) : "memory");
return ret;
}
int serial_init() {
outb(PORT + 1, 0x00); // Disable all interrupts
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
outb(PORT + 1, 0x00); // (hi byte)
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial
// returns same byte)
// Check if serial is faulty (i.e: not same byte as sent)
if (inb(PORT + 0) != 0xAE) {
return 1;
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
outb(PORT + 4, 0x0F);
return 0;
}
static int serial_is_transmit_empty() { return inb(PORT + 5) & 0x20; }
static void serial_write_char(char chr) {
while (serial_is_transmit_empty() == 0);
outb(PORT, chr);
}
void serial_write_string(const char* text) {
int i = 0;
while(text[i]) {
serial_write_char(text[i]);
i++;
}
}

7
serial.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef HEADER_SERIAL
#define HEADER_SERIAL
int serial_init(void);
void serial_write_string(const char* text);
#endif