1 /*
2  * Copyright (c) 2009 Corey Tabaka
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <stdarg.h>
9 #include <lk/reg.h>
10 #include <stdio.h>
11 #include <kernel/thread.h>
12 #include <arch/x86.h>
13 #include <lib/cbuf.h>
14 #include <platform.h>
15 #include <platform/interrupts.h>
16 #include <platform/pc.h>
17 #include <platform/console.h>
18 #include <platform/keyboard.h>
19 #include <platform/debug.h>
20 
21 #include "platform_p.h"
22 
23 #ifndef DEBUG_BAUD_RATE
24 #define DEBUG_BAUD_RATE 115200
25 #endif
26 #ifndef DEBUG_COM_PORT
27 #define DEBUG_COM_PORT 1
28 #endif
29 
30 static const int uart_baud_rate = DEBUG_BAUD_RATE;
31 static const int uart_io_port = (DEBUG_COM_PORT == 1) ? COM1_REG :
32                                 (DEBUG_COM_PORT == 2) ? COM2_REG :
33                                 (DEBUG_COM_PORT == 3) ? COM3_REG :
34                                 COM4_REG;
35 static const int uart_irq = (DEBUG_COM_PORT == 1 || DEBUG_COM_PORT == 3) ? INT_COM1_COM3 : INT_COM2_COM4;
36 
37 cbuf_t console_input_buf;
38 
uart_irq_handler(void * arg)39 static enum handler_return uart_irq_handler(void *arg) {
40     unsigned char c;
41     bool resched = false;
42 
43     while (inp(uart_io_port + 5) & (1<<0)) {
44         c = inp(uart_io_port + 0);
45         cbuf_write_char(&console_input_buf, c, false);
46         resched = true;
47     }
48 
49     return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
50 }
51 
platform_init_debug_early(void)52 void platform_init_debug_early(void) {
53     /* configure the uart */
54     const int divisor = 115200 / uart_baud_rate;
55 
56     /* get basic config done so that tx functions */
57     outp(uart_io_port + 1, 0); // mask all irqs
58     outp(uart_io_port + 3, 0x80); // set up to load divisor latch
59     outp(uart_io_port + 0, divisor & 0xff); // lsb
60     outp(uart_io_port + 1, divisor >> 8); // msb
61     outp(uart_io_port + 3, 3); // 8N1
62     outp(uart_io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold
63     outp(uart_io_port + 4, 0x3); // drive flow control bits high
64 }
65 
platform_init_debug(void)66 void platform_init_debug(void) {
67     /* finish uart init to get rx going */
68     cbuf_initialize(&console_input_buf, 1024);
69 
70     register_int_handler(uart_irq, uart_irq_handler, NULL);
71     unmask_interrupt(uart_irq);
72 
73     outp(uart_io_port + 1, 0x1); // enable receive data available interrupt
74 
75     // modem control register: Auxiliary Output 2 is another IRQ enable bit
76     const uint8_t mcr = inp(uart_io_port + 4);
77     outp(uart_io_port + 4, mcr | 0x8);
78 }
79 
debug_uart_putc(char c)80 static void debug_uart_putc(char c) {
81     while ((inp(uart_io_port + 5) & (1<<6)) == 0)
82         ;
83     outp(uart_io_port + 0, c);
84 }
85 
platform_dputc(char c)86 void platform_dputc(char c) {
87     if (c == '\n')
88         platform_dputc('\r');
89 
90     cputc(c);
91     debug_uart_putc(c);
92 }
93 
platform_dgetc(char * c,bool wait)94 int platform_dgetc(char *c, bool wait) {
95     return cbuf_read_char(&console_input_buf, c, wait);
96 }
97 
platform_halt(platform_halt_action suggested_action,platform_halt_reason reason)98 void platform_halt(platform_halt_action suggested_action,
99                    platform_halt_reason reason) {
100     for (;;) {
101         x86_cli();
102         x86_hlt();
103     }
104 }
105 
106