diff --git a/arch/x86_64/extra.mk b/arch/x86_64/extra.mk index 88e60cd..5eee39f 100644 --- a/arch/x86_64/extra.mk +++ b/arch/x86_64/extra.mk @@ -4,10 +4,7 @@ QEMU_MONITOR_FLAGS := -serial stdio QEMU_FLAGS := \ -m 10M \ -display sdl \ - -smp 4 -cpu qemu64,pdpe1gb \ - -device ahci,id=ahci \ - -drive id=hd0,file=$(BUILD_DIR)/disk.img,if=none -device ide-hd,drive=hd0,bus=ahci.0 \ - -drive id=cd0,file=$(BUILD_DIR)/disk2.img,if=none -device ide-cd,drive=cd0,bus=ahci.1 + -smp 4 -cpu qemu64,pdpe1gb ARCH_TEMP_FILES := $(BUILD_DIR)/$(KERNEL_EXEC).elf32 diff --git a/arch/x86_64/include/arch/serial.h b/arch/x86_64/include/arch/serial.h new file mode 100644 index 0000000..2c5da92 --- /dev/null +++ b/arch/x86_64/include/arch/serial.h @@ -0,0 +1,27 @@ +#ifndef ARCH_SERIAL_H_ +#define ARCH_SERIAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SERIAL_PORT_A 0x3F8 +#define SERIAL_PORT_B 0x2F8 +#define SERIAL_PORT_C 0x3E8 +#define SERIAL_PORT_D 0x2E8 + +extern void serial_putchar(int port, char ch); + +extern void serial_wait(int device); +extern void serial_send_byte(int device, char out); +extern char serial_recv_byte(int device); + +extern int serial_rcvd(int device); + +extern void early_serialcon_init(int baud); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/arch/x86_64/init.c b/arch/x86_64/init.c index 6f63aef..a7ac87f 100644 --- a/arch/x86_64/init.c +++ b/arch/x86_64/init.c @@ -1,4 +1,7 @@ +#include "arch/serial.h" + #include +#include #include #include #include @@ -49,12 +52,15 @@ void early_console_init(void) { const char *dest = arg_value("kernel.early-console"); if (!dest) { - return; + dest = "ttyS0"; } -} -static void init_bootfb(multiboot_info_t *mb) -{ + if (!strcmp(dest, "tty0")) { + /* show log messages on VGA */ + } else if (!strcmp(dest, "ttyS0")) { + /* write log messages to serial port */ + early_serialcon_init(115200); + } } static void use_uniprocessor_topology(void) @@ -69,19 +75,14 @@ int ml_init(uintptr_t arg) parse_cmdline(PTR32(mb->cmdline)); - init_bootfb(mb); + early_console_init(); bootstrap_cpu_init(); clock_calibrate(500); - early_console_init(); - print_kernel_banner(); early_vm_init(); - printk("video mode: %ux%u", - mb->framebuffer_width, - mb->framebuffer_height); e820_scan(PTR32(mb->mmap_addr), mb->mmap_length); @@ -118,6 +119,7 @@ int ml_init(uintptr_t arg) sched_init(); + pit_start(500); ml_int_enable(); return 0; diff --git a/arch/x86_64/irq.c b/arch/x86_64/irq.c index 5378681..4337cf7 100644 --- a/arch/x86_64/irq.c +++ b/arch/x86_64/irq.c @@ -10,7 +10,7 @@ #define MAX_ISR_HANDLERS 16 -extern void syscall_gate(); +extern void syscall_gate(void); extern uintptr_t pf_faultptr(void); static int_hook isr_handlers[NR_IDT_ENTRIES]; @@ -92,7 +92,7 @@ static void set_syscall_gate(uintptr_t rip) } #endif -static void init_pic() +static void init_pic(void) { // Remap the PIC outportb(0x20, 0x11); diff --git a/arch/x86_64/pit.c b/arch/x86_64/pit.c index f0d2ab3..47555c9 100644 --- a/arch/x86_64/pit.c +++ b/arch/x86_64/pit.c @@ -1,34 +1,33 @@ -#include +#include +#include #include #include -#include -#include +#include -#define PIT_COUNTER0 0x40 -#define PIT_CMD 0x43 +#define PIT_COUNTER0 0x40 +#define PIT_CMD 0x43 -#define CMD_BINARY 0x00 // Use Binary counter values -#define CMD_BCD 0x01 // Use Binary Coded Decimal counter values +#define CMD_BINARY 0x00 // Use Binary counter values +#define CMD_BCD 0x01 // Use Binary Coded Decimal counter values -#define CMD_MODE0 0x00 // Interrupt on Terminal Count -#define CMD_MODE1 0x02 // Hardware Retriggerable One-Shot -#define CMD_MODE2 0x04 // Rate Generator -#define CMD_MODE3 0x06 // Square Wave -#define CMD_MODE4 0x08 // Software Trigerred Strobe -#define CMD_MODE5 0x0a // Hardware Trigerred Strobe +#define CMD_MODE0 0x00 // Interrupt on Terminal Count +#define CMD_MODE1 0x02 // Hardware Retriggerable One-Shot +#define CMD_MODE2 0x04 // Rate Generator +#define CMD_MODE3 0x06 // Square Wave +#define CMD_MODE4 0x08 // Software Trigerred Strobe +#define CMD_MODE5 0x0a // Hardware Trigerred Strobe -#define CMD_LATCH 0x00 -#define CMD_RW_LOW 0x10 // Least Significant Byte -#define CMD_RW_HI 0x20 // Most Significant Byte -#define CMD_RW_BOTH 0x30 // Least followed by Most Significant Byte +#define CMD_LATCH 0x00 +#define CMD_RW_LOW 0x10 // Least Significant Byte +#define CMD_RW_HI 0x20 // Most Significant Byte +#define CMD_RW_BOTH 0x30 // Least followed by Most Significant Byte -#define CMD_COUNTER0 0x00 -#define CMD_COUNTER1 0x40 -#define CMD_COUNTER2 0x80 -#define CMD_READBACK 0xc0 - -#define PIT_FREQUENCY 1193182 +#define CMD_COUNTER0 0x00 +#define CMD_COUNTER1 0x40 +#define CMD_COUNTER2 0x80 +#define CMD_READBACK 0xc0 +#define PIT_FREQUENCY 1193182 static volatile unsigned long long ticks = 0; @@ -40,9 +39,7 @@ static int pit_callback(void) return 0; } -static struct irq_hook pit_irq_hook = { - .irq_callback = pit_callback -}; +static struct irq_hook pit_irq_hook = {.irq_callback = pit_callback}; void pit_start(unsigned int hz) { diff --git a/arch/x86_64/serial.c b/arch/x86_64/serial.c new file mode 100644 index 0000000..f8c0f32 --- /dev/null +++ b/arch/x86_64/serial.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define COM1 0x3F8 +#define COM2 0x2F8 +#define COM3 0x3E8 +#define COM4 0x2E8 + +static int transmit_empty(int device) +{ + return inportb(device + 5) & 0x20; +} + +static int serial_received(int device) +{ + return inportb(device + 5) & 0x1; +} + +void serial_send_byte(int device, char out) +{ + volatile unsigned int _count = 0; + while (!transmit_empty(device)) { + _count++; + } + + outportb(device, out); + + while (!transmit_empty(device)) { + _count++; + } +} + +char serial_recv_byte(int device) +{ + volatile unsigned int _count = 0; + while (!serial_received(device)) { + _count++; + } + + char c = inportb(device); + + outportb(device + 5, inportb(device + 5) & ~0x1); + + return c; +} + +void serial_putchar(int port, char ch) +{ + if (ch == '\n') { + serial_send_byte(port, '\r'); + } + + serial_send_byte(port, ch); +} + +void serialcon_write(struct console *con, const char *s, unsigned int len) +{ + for (unsigned int i = 0; i < len; i++) { + serial_putchar(COM1, s[i]); + } +} + +static int get_baud_divisor(int baud) +{ + int freq = 115200; + int best_baud = -1; + int best_div = -1; + + for (int i = 1; i < 254; i++) { + int this_baud = freq / i; + + if (this_baud == baud) { + return i; + } + + if (best_baud == -1) { + best_baud = this_baud; + best_div = i; + continue; + } + + if (this_baud < baud && best_baud > baud) { + /* TODO pick divisor that gives the closest baud rate */ + return best_div; + } + + best_baud = this_baud; + best_div = i; + } + + return best_div; +} + +static void init_serial_port(int port, int baud) +{ + int baud_div = get_baud_divisor(baud); + outportb(port + 1, 0x00); // Disable all interrupts + outportb(port + 3, 0x80); // Enable DLAB (set baud rate divisor) + outportb(port + 0, baud_div); // Set divisor + outportb(port + 1, 0x00); + outportb(port + 3, 0x03); // 8 bits, no parity, one stop bit + outportb( + port + 2, + 0xC7); // Enable FIFO, clear them, with 14-byte threshold + outportb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set + outportb( + port + 4, + 0x1E); // Set in loopback mode, test the serial chip + outportb(port + 0, 0xAE); // Test serial chip (send byte 0xAE and + // check if serial returns same byte) + + volatile unsigned int q = 0; + while (!serial_received(port)) { + q++; + } + + // Check if serial is faulty (i.e: not same byte as sent) + if (inportb(port + 0) != 0xAE) { + return; + } + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + outportb(port + 1, 0x01); + outportb(port + 4, 0x0F); + printk("serial: port %x initialised", port); +} + +static struct console serialcon = { + .c_name = "serialcon", + .c_flags = CON_BOOT, + .c_write = serialcon_write, + .c_lock = SPIN_LOCK_INIT, +}; + +static int serial_irq1(void) +{ + if (serial_received(COM1)) { + unsigned char c = serial_recv_byte(COM1); + printk("serial: COM1 received %c", c); + } + + if (serial_received(COM3)) { + unsigned char c = serial_recv_byte(COM3); + printk("serial: COM3 received %c", c); + } + + return 0; +} + +static struct irq_hook irq1_hook = { + .irq_callback = serial_irq1, +}; + +void early_serialcon_init(int baud) +{ + hook_irq(IRQ4, &irq1_hook); + init_serial_port(COM1, baud); + console_register(&serialcon); +}