1 /*
2 * Copyright (c) 2018 Travis Geiselbrecht
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 <lk/reg.h>
9 #include <lk/trace.h>
10 #include <lib/cbuf.h>
11 #include <kernel/thread.h>
12 #include <platform.h>
13 #include <platform/interrupts.h>
14 #include <platform/debug.h>
15 #include <platform/virt.h>
16 #include <sys/types.h>
17
18 #include "platform_p.h"
19
20 // simple 16550 driver for the emulated serial port on qemu riscv virt machine
21
22 static volatile uint8_t *const uart_base = (uint8_t *)UART0_BASE_VIRT;
23
24 #define RXBUF_SIZE 128
25 static char uart_rx_buf_data[RXBUF_SIZE];
26 static cbuf_t uart_rx_buf;
27
uart_read_8(size_t offset)28 static inline uint8_t uart_read_8(size_t offset) {
29 return uart_base[offset];
30 }
31
uart_write_8(size_t offset,uint8_t val)32 static inline void uart_write_8(size_t offset, uint8_t val) {
33 uart_base[offset] = val;
34 }
35
uart_irq_handler(void * arg)36 static enum handler_return uart_irq_handler(void *arg) {
37 unsigned char c;
38 bool resched = false;
39
40 while (uart_read_8(5) & (1<<0)) {
41 c = uart_read_8(0);
42 cbuf_write_char(&uart_rx_buf, c, false);
43 resched = true;
44 }
45
46 return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
47 }
48
uart_init(void)49 void uart_init(void) {
50 /* finish uart init to get rx going */
51 cbuf_initialize_etc(&uart_rx_buf, RXBUF_SIZE, uart_rx_buf_data);
52
53 register_int_handler(IRQ_UART0, uart_irq_handler, NULL);
54
55 uart_write_8(1, 0x1); // enable receive data available interrupt
56
57 unmask_interrupt(IRQ_UART0);
58 }
59
uart_putc(char c)60 static void uart_putc(char c) {
61 while ((uart_read_8(5) & (1<<6)) == 0)
62 ;
63 uart_write_8(0, c);
64 }
65
uart_getc(char * c,bool wait)66 static int uart_getc(char *c, bool wait) {
67 return cbuf_read_char(&uart_rx_buf, c, wait);
68 }
69
platform_dputc(char c)70 void platform_dputc(char c) {
71 if (c == '\n')
72 platform_dputc('\r');
73 uart_putc(c);
74 }
75
platform_dgetc(char * c,bool wait)76 int platform_dgetc(char *c, bool wait) {
77 int ret = uart_getc(c, wait);
78
79 return ret;
80 }
81
82 /* panic-time getc/putc */
platform_pgetc(char * c,bool wait)83 int platform_pgetc(char *c, bool wait) {
84 if (uart_read_8(5) & (1<<0)) {
85 *c = uart_read_8(0);
86 return 0;
87 }
88 return -1;
89 }
90
91