Skip to content

Commit

Permalink
uart serial input
Browse files Browse the repository at this point in the history
  • Loading branch information
82marbag committed Oct 13, 2020
1 parent b7f50fe commit ea6e454
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 3 deletions.
13 changes: 13 additions & 0 deletions arch/x86/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ ENTRY(handle_exception)
#endif
END_FUNC(handle_exception)

ENTRY(asm_uart_handler)
cld
SAVE_REGS
lea com_ports, %_ASM_DI
call uart_handler
RESTORE_REGS
#if defined(__x86_64__)
iretq
#else
iret
#endif
END_FUNC(asm_uart_handler)

ENTRY(usermode_call_asm)
/* FIXME: Add 32-bit support */

Expand Down
7 changes: 7 additions & 0 deletions arch/x86/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <console.h>
#include <drivers/serial.h>
#include <ktf.h>
#include <lib.h>
#include <percpu.h>
Expand All @@ -37,6 +38,7 @@
#include <mm/vmm.h>

extern void ret2kern_handler(void);
extern void asm_uart_handler(void);

static void init_tss(percpu_t *percpu) {
#if defined(__i386__)
Expand Down Expand Up @@ -143,6 +145,11 @@ void init_traps(unsigned int cpu) {
set_intr_gate(&percpu->idt[X86_RET2KERN_INT], __KERN_CS, _ul(ret2kern_handler), GATE_DPL3, GATE_PRESENT, 0);
/* clang-format on */

set_intr_gate(&percpu->idt[COM1_IRQ0_OFFSET], __KERN_CS, _ul(asm_uart_handler),
GATE_DPL0, GATE_PRESENT, 0);
set_intr_gate(&percpu->idt[COM2_IRQ0_OFFSET], __KERN_CS, _ul(asm_uart_handler),
GATE_DPL0, GATE_PRESENT, 0);

barrier();
lidt(&percpu->idt_ptr);

Expand Down
2 changes: 1 addition & 1 deletion common/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,5 @@ void kernel_main(void) {
printk("All tasks done.\n");

while (1)
halt();
io_delay();
}
3 changes: 3 additions & 0 deletions common/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ void __noreturn __text_init kernel_start(uint32_t multiboot_magic,
/* Initialize Programmable Interrupt Controller */
init_pic();

/* Initialize console input */
uart_input_init();

/* PIC is initialized - enable local interrupts */
sti();

Expand Down
9 changes: 9 additions & 0 deletions drivers/pic.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,12 @@ void init_pic(void) {
outb(PIC1_PORT_DATA, 0xFF);
outb(PIC2_PORT_DATA, 0xFF);
}

void pic_enable_irq(pic_device_sel_t pic, uint8_t irq) {
BUG_ON((pic != PIC1_DEVICE_SEL && pic != PIC2_DEVICE_SEL) ||
irq >= PIC_IRQ_END_OFFSET);
uint8_t port = (pic == PIC1_DEVICE_SEL ? PIC1_PORT_DATA : PIC2_PORT_DATA);
uint8_t unmasked_irqs = inb(port);

outb(port, (~(1 << irq)) & unmasked_irqs);
}
38 changes: 36 additions & 2 deletions drivers/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <drivers/pic.h>
#include <ktf.h>
#include <lib.h>
#include <setup.h>

#include <drivers/serial.h>

#define INPUT_BUF 80
static struct {
char buf[INPUT_BUF];
unsigned curr;
unsigned init;
} input_state;

static inline void set_port_mode(io_port_t port, bool stop_bit, uint8_t width) {
lcr_t lcr = {0};

Expand Down Expand Up @@ -63,8 +71,8 @@ static inline bool receiver_ready(io_port_t port) {
void uart_init(io_port_t port, unsigned baud) {
mcr_t mcr = {0};

/* Disable interrupts */
outb(port + UART_IER_REG_OFFSET, 0x00);
/* Enable interrupts for received data available */
outb(port + UART_IER_REG_OFFSET, 0x01);

/* Disable FIFO control */
outb(port + UART_FCR_REG_OFFSET, 0x00);
Expand All @@ -83,6 +91,16 @@ void uart_init(io_port_t port, unsigned baud) {
outb(port + UART_MCR_REG_OFFSET, mcr.reg);
}

void uart_input_init() {
/* Initialize input state */
memset(&input_state, 0, sizeof(input_state));

/* Enable IRQ lines */
printk("Enabling serial input\n");
pic_enable_irq(PIC1_DEVICE_SEL, COM1_IRQ);
pic_enable_irq(PIC2_DEVICE_SEL, COM2_IRQ);
}

static inline int uart_port_status(io_port_t port) {
if (!receiver_ready(port))
return -1; /* ENODEV */
Expand Down Expand Up @@ -137,3 +155,19 @@ int serial_write(io_port_t port, const char *buf, size_t len) {

return rc;
}

void uart_handler(io_port_t ports[2]) {
unsigned int i;
for (i = 0; i < sizeof(*ports); ++i) {
uint8_t status = inb(ports[i] + UART_IIR_REG_OFFSET);
if ((status & UART_IIR_STATUS_MASK) == UART_IIR_RBR_READY) {
uint8_t input = inb(ports[i] + UART_RBR_REG_OFFSET);

input_state.buf[input_state.curr] = input;
input_state.curr = (input_state.curr + 1) % sizeof(input_state.buf);

printk("%c", input);
}
}
outb(PIC1_PORT_CMD, PIC_EOI);
}
6 changes: 6 additions & 0 deletions include/drivers/pic.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,14 @@
#define PIC_IRQ0_OFFSET 0x20
#define PIC_IRQ8_OFFSET 0x28

#define PIC_IRQ_END_OFFSET 0x08 /* One beyond the max IRQ number */

enum pic_device_sel { PIC1_DEVICE_SEL = 1, PIC2_DEVICE_SEL };
typedef enum pic_device_sel pic_device_sel_t;

/* External declarations */

extern void init_pic(void);
extern void pic_enable_irq(pic_device_sel_t pic, uint8_t irq);

#endif /* KTF_DRV_PIC_H */
13 changes: 13 additions & 0 deletions include/drivers/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#ifndef KTF_DRV_SERIAL_H
#define KTF_DRV_SERIAL_H

#include <drivers/pic.h>
#include <ktf.h>

union line_control_register {
Expand Down Expand Up @@ -98,10 +99,17 @@ union interrupt_enable_register {
};
typedef union interrupt_enable_register ier_t;

#define COM1_IRQ 4 /* IRQ 4 */
#define COM2_IRQ 3 /* IRQ 3 */
#define COM1_IRQ0_OFFSET (PIC_IRQ0_OFFSET + COM1_IRQ)
#define COM2_IRQ0_OFFSET (PIC_IRQ0_OFFSET + COM2_IRQ)

#define UART_TXD_REG_OFFSET 0x00
#define UART_RBR_REG_OFFSET 0x00
#define UART_IER_REG_OFFSET 0x01
#define UART_DLL_REG_OFFSET 0x00
#define UART_DLH_REG_OFFSET 0x01
#define UART_IIR_REG_OFFSET 0x02
#define UART_FCR_REG_OFFSET 0x02
#define UART_LCR_REG_OFFSET 0x03
#define UART_MCR_REG_OFFSET 0x04
Expand All @@ -111,9 +119,14 @@ typedef union interrupt_enable_register ier_t;

#define DEFAULT_BAUD_SPEED 115200

#define UART_IIR_STATUS_MASK 0x0E /* bits 3, 2, 1 */
#define UART_IIR_RBR_READY 0x04

/* External declarations */

extern void uart_init(io_port_t port, unsigned baud);
extern void uart_handler(io_port_t ports[2]);
extern void uart_input_init();
extern int serial_putchar(io_port_t port, char c);
extern int serial_write(io_port_t port, const char *buf, size_t len);

Expand Down

0 comments on commit ea6e454

Please sign in to comment.