diff --git a/Makefile b/Makefile index 51b6a39..da82431 100644 --- a/Makefile +++ b/Makefile @@ -31,10 +31,6 @@ $(A_OBJ): $(BUILD_DIR)/%.S.o : %.S @mkdir -p $(@D) nasm $< -f elf64 -o $@ -$(BUILD_DIR)/$(SRC_DIR)/arch/amd64/shim.o: $(SRC_DIR)/arch/amd64/shim.c - @mkdir -p $(@D) - $(CC) -c $(CFLAGS) -o $@ $< -m32 - $(C_OBJ): $(BUILD_DIR)/%.o : %.c @mkdir -p $(@D) $(CC) -c $(CFLAGS) -o $@ $< diff --git a/include/serial.h b/include/serial.h new file mode 100644 index 0000000..0500ff1 --- /dev/null +++ b/include/serial.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +enum serial_com_port { + COM1 = 1, + COM2 = 2, + COM3 = 3, + COM4 = 4, +}; + +int serial_init(enum serial_com_port com); +uint8_t serial_in(enum serial_com_port com); +void serial_out(enum serial_com_port com, uint8_t ch); +void serial_out_str(enum serial_com_port com, char *str); diff --git a/src/arch/amd64/serial.c b/src/arch/amd64/serial.c new file mode 100644 index 0000000..685da7f --- /dev/null +++ b/src/arch/amd64/serial.c @@ -0,0 +1,58 @@ +#include +#include "bindings.h" + +// port numbers for first four serial ports +static uint16_t SERIAL_PORTS[] = { + [COM1] = 0x3F8, + [COM2] = 0x2F8, + [COM3] = 0x3E8, + [COM4] = 0x2E8, +}; + +// initialize the specified COM port for serial +// see https://wiki.osdev.org/Serial_Ports +// and https://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming +int serial_init(enum serial_com_port com) { + uint16_t port = SERIAL_PORTS[com]; + outb(port + 1, 0x00); // disable interrupts + outb(port + 3, 0x80); // enable DLAB (divisor latch access bit) + outb(port + 0, 0x03); // (lo) Set baud divisor to 3 38400 baud + outb(port + 1, 0x00); // (hi) + outb(port + 3, 0x03); // disable DLAB, set 8 bits per word, one stop bit, no parity + outb(port + 2, 0xC7); // enable and clear FIFOs, set to maximum threshold + // outb(port + 4, 0x0B); // TODO copied this from osdev wiki but i don't think you need it here + outb(port + 4, 0x1E); // set in loopback mode for test + outb(port + 0, 0xAE); // test by sending 0xAE + + uint8_t response = inb(port + 0); + if(response != 0xAE) { + // TODO panic here? + return -1; + } + + // disable loopback, enable IRQs + outb(port + 4, 0x0F); + return 0; +} + +uint8_t serial_in(enum serial_com_port com) { + uint16_t port = SERIAL_PORTS[com]; + // wait for data to be available + while((inb(port + 5) & 0x01) == 0); + return inb(port); +} + +void serial_out(enum serial_com_port com, uint8_t ch) { + uint16_t port = SERIAL_PORTS[com]; + // wait for output to be free + while((inb(port + 5) & 0x20) == 0); + outb(port, ch); +} + +void serial_out_str(enum serial_com_port com, char *str) { + uint16_t port = SERIAL_PORTS[com]; + for(; *str != '\0'; str++) { + while((inb(port + 5) & 0x20) == 0); + outb(port, *str); + } +}