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