From 1c4814c43c949e3154fad0f9b326b9a16bdc0b66 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Mon, 24 Jan 2022 17:38:52 +0100 Subject: [PATCH 1/4] setup: move COM ports detection to serial driver Signed-off-by: Pawel Wieczorkiewicz --- common/setup.c | 9 ++++----- drivers/serial.c | 15 ++++++++++++++- include/drivers/serial.h | 11 +++++++++++ include/setup.h | 15 --------------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/common/setup.c b/common/setup.c index 022f0575..0697dfee 100644 --- a/common/setup.c +++ b/common/setup.c @@ -60,8 +60,6 @@ #include #endif -io_port_t __data_rmode com_ports[2] = {COM1_PORT, COM2_PORT}; - boot_flags_t boot_flags; static unsigned bsp_cpu_id = 0; @@ -70,11 +68,12 @@ unsigned get_bsp_cpu_id(void) { return bsp_cpu_id; } void set_bsp_cpu_id(unsigned cpu_id) { bsp_cpu_id = cpu_id; } #define QEMU_CONSOLE_PORT 0x0e9 + static void __text_init init_console(void) { - get_com_ports(); + io_port_t com_port = get_first_com_port(); - uart_init(com_ports[0], DEFAULT_BAUD_SPEED); - register_console_callback(serial_console_write, _ptr(com_ports[0])); + uart_init(com_port, DEFAULT_BAUD_SPEED); + register_console_callback(serial_console_write, _ptr(com_port)); printk("COM1: %x, COM2: %x\n", com_ports[0], com_ports[1]); diff --git a/drivers/serial.c b/drivers/serial.c index 7937355f..f9f7340e 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -37,7 +37,20 @@ static struct { unsigned init; } input_state; -extern io_port_t com_ports[2]; +io_port_t __data_rmode com_ports[4]; + + +io_port_t get_first_com_port(void) { + memcpy((void *) com_ports, _ptr(BDA_COM_PORTS_ENTRY), sizeof(com_ports)); + + for (unsigned int i = 0; i < ARRAY_SIZE(com_ports); i++) { + if (com_ports[i] != 0x0) + return com_ports[i]; + } + + /* Fallback to COM1 */ + return COM1_PORT; +} static inline void set_port_mode(io_port_t port, bool stop_bit, uint8_t width) { lcr_t lcr = {0}; diff --git a/include/drivers/serial.h b/include/drivers/serial.h index f15d1503..4bb90a85 100644 --- a/include/drivers/serial.h +++ b/include/drivers/serial.h @@ -41,6 +41,14 @@ typedef union line_control_register lcr_t; #define FRAME_SIZE_6_BITS 0x01 #define FRAME_SIZE_5_BITS 0x00 +enum com_port { + COM1_PORT = 0x3f8, + COM2_PORT = 0x2f8, + COM3_PORT = 0x3e8, + COM4_PORT = 0x2e8, +}; +typedef enum com_port com_port_t; + #define STOP_BIT_1 0x00 #define STOP_BIT_2 0x01 @@ -124,6 +132,9 @@ typedef union interrupt_enable_register ier_t; /* External declarations */ +extern io_port_t com_ports[4]; + +extern io_port_t get_first_com_port(void); extern void uart_init(io_port_t port, unsigned baud); extern void uart_input_init(uint8_t dst_cpus); extern void uart_interrupt_handler(void); diff --git a/include/setup.h b/include/setup.h index 23b480cf..1f93a65a 100644 --- a/include/setup.h +++ b/include/setup.h @@ -25,9 +25,6 @@ #ifndef KTF_SETUP_H #define KTF_SETUP_H -#define COM1_PORT 0x3f8 -#define COM2_PORT 0x2f8 - #ifndef __ASSEMBLY__ #include #include @@ -41,23 +38,11 @@ struct boot_flags { }; typedef struct boot_flags boot_flags_t; -extern io_port_t com_ports[2]; - extern char cpu_identifier[49]; extern boot_flags_t boot_flags; /* Static declarations */ -static inline void get_com_ports(void) { - memcpy((void *) com_ports, (void *) (BDA_COM_PORTS_ENTRY), sizeof(com_ports)); - - if (com_ports[0] == 0x0) - com_ports[0] = COM1_PORT; - - if (com_ports[1] == 0x0) - com_ports[1] = COM2_PORT; -} - /* External declarations */ extern unsigned get_bsp_cpu_id(void); From 3a12d894680e7464ae802bb79d27346f80c076ed Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Mon, 24 Jan 2022 18:20:49 +0100 Subject: [PATCH 2/4] cmdline,serial: add parsing for COM ports configuration Signed-off-by: Pawel Wieczorkiewicz --- common/cmdline.c | 193 +++++++++++++++++++++++++++++++++++++++ drivers/serial.c | 2 +- grub/boot/grub/grub.cfg | 2 +- include/cmdline.h | 7 +- include/drivers/serial.h | 75 ++++++++++++--- 5 files changed, 261 insertions(+), 18 deletions(-) diff --git a/common/cmdline.c b/common/cmdline.c index 446feda1..8cd9487c 100644 --- a/common/cmdline.c +++ b/common/cmdline.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Amazon.com, Inc. or its affiliates. + * Copyright (c) 2022 Open Source Security, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,6 +25,7 @@ */ #include +#include #include #include #include @@ -56,6 +58,18 @@ bool_cmd("qemu_console", opt_qemu_console); bool opt_poweroff = true; bool_cmd("poweroff", opt_poweroff); +static char opt_com1[20]; +string_cmd("com1", opt_com1); + +static char opt_com2[20]; +string_cmd("com2", opt_com2); + +static char opt_com3[20]; +string_cmd("com3", opt_com3); + +static char opt_com4[20]; +string_cmd("com4", opt_com4); + const char *kernel_cmdline; void __text_init cmdline_parse(const char *cmdline) { @@ -116,3 +130,182 @@ void __text_init cmdline_parse(const char *cmdline) { } } } + +static __text_init bool _parse_com_port(char *port_str, io_port_t *port) { + unsigned long tmp; + + if (string_empty(port_str)) + return false; + + tmp = strtoul(port_str, NULL, 16); + switch (tmp) { + case COM1_PORT: + case COM2_PORT: + case COM3_PORT: + case COM4_PORT: + *port = tmp; + break; + default: + return false; + } + + return true; +} + +static __text_init bool _parse_com_baud(char *baud_str, com_baud_t *baud) { + unsigned long tmp; + + if (string_empty(baud_str)) + return false; + + tmp = strtoul(baud_str, NULL, 0); + switch (tmp) { + case COM_BAUD_300: + case COM_BAUD_1200: + case COM_BAUD_2400: + case COM_BAUD_4800: + case COM_BAUD_9600: + case COM_BAUD_19200: + case COM_BAUD_38400: + case COM_BAUD_57600: + case COM_BAUD_115200: + *baud = tmp; + break; + default: + return false; + } + + return true; +} + +static __text_init bool _parse_com_width(char *frame_size_str, + com_frame_size_t *frame_size) { + unsigned long tmp; + + if (string_empty(frame_size_str)) + return false; + + tmp = strtoul(frame_size_str, NULL, 0); + switch (tmp) { + case 8: + *frame_size = COM_FRAME_SIZE_8_BITS; + break; + case 7: + *frame_size = COM_FRAME_SIZE_7_BITS; + break; + case 6: + *frame_size = COM_FRAME_SIZE_6_BITS; + break; + case 5: + *frame_size = COM_FRAME_SIZE_5_BITS; + break; + default: + return false; + } + + return true; +} + +static __text_init bool _parse_com_parity(char *parity_str, com_parity_t *parity) { + if (string_empty(parity_str) || strlen(parity_str) > 1) + return false; + + switch (parity_str[0]) { + case 'n': + *parity = COM_NO_PARITY; + break; + case 'o': + *parity = COM_ODD_PARITY; + break; + case 'e': + *parity = COM_EVEN_PARITY; + break; + case 'h': + *parity = COM_HIGH_PARITY; + break; + case 'l': + *parity = COM_LOW_PARITY; + break; + default: + return false; + } + + return true; +} + +static __text_init bool _parse_com_stop_bit(char *stop_bit_str, + com_stop_bit_t *stop_bit) { + unsigned long tmp; + + if (string_empty(stop_bit_str)) + return false; + + tmp = strtoul(stop_bit_str, NULL, 0); + switch (tmp) { + case 1: + *stop_bit = COM_STOP_BIT_1; + break; + case 2: + *stop_bit = COM_STOP_BIT_2; + break; + default: + return false; + } + + return true; +} + +__text_init bool parse_com_port(com_idx_t com, uart_config_t *cfg) { + char *tmp_str = NULL; + char *opt_com; + + switch (com) { + case COM1: + opt_com = opt_com1; + break; + case COM2: + opt_com = opt_com2; + break; + case COM3: + opt_com = opt_com3; + break; + case COM4: + opt_com = opt_com4; + break; + default: + return false; + } + + if (string_empty(opt_com)) + return false; + + tmp_str = strtok(opt_com, ","); + if (!_parse_com_port(tmp_str, &cfg->port)) + return false; + + tmp_str = strtok(NULL, ","); + if (string_empty(tmp_str)) + cfg->baud = DEFAULT_BAUD_SPEED; + else if (!_parse_com_baud(tmp_str, &cfg->baud)) + return false; + + tmp_str = strtok(NULL, ","); + if (string_empty(tmp_str)) + cfg->frame_size = COM_FRAME_SIZE_8_BITS; + else if (!_parse_com_width(tmp_str, &cfg->frame_size)) + return false; + + tmp_str = strtok(NULL, ","); + if (string_empty(tmp_str)) + cfg->parity = COM_NO_PARITY; + else if (!_parse_com_parity(tmp_str, &cfg->parity)) + return false; + + tmp_str = strtok(NULL, ","); + if (string_empty(tmp_str)) + cfg->stop_bit = COM_STOP_BIT_1; + else if (!_parse_com_stop_bit(tmp_str, &cfg->stop_bit)) + return false; + + return true; +} diff --git a/drivers/serial.c b/drivers/serial.c index f9f7340e..c2a2c2d2 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -94,7 +94,7 @@ void uart_init(io_port_t port, unsigned baud) { outb(port + UART_FCR_REG_OFFSET, 0x00); /* Set 8n1 mode */ - set_port_mode(port, STOP_BIT_1, FRAME_SIZE_8_BITS); + set_port_mode(port, COM_STOP_BIT_1, COM_FRAME_SIZE_8_BITS); /* Set baud speed by applying divisor to DLL+DLH */ set_dlab(port, true); diff --git a/grub/boot/grub/grub.cfg b/grub/boot/grub/grub.cfg index b3438746..5b06d569 100644 --- a/grub/boot/grub/grub.cfg +++ b/grub/boot/grub/grub.cfg @@ -5,6 +5,6 @@ terminal_input --append serial terminal_output --append serial menuentry "kernel64" { - multiboot /boot/kernel64.bin poweroff=1 + multiboot /boot/kernel64.bin poweroff=1 com1=0x3f8,115200,8,n,1 boot } diff --git a/include/cmdline.h b/include/cmdline.h index 85e6a354..49640f20 100644 --- a/include/cmdline.h +++ b/include/cmdline.h @@ -30,6 +30,8 @@ #include #include +#include + #define PARAM_MAX_LENGTH 32 struct __packed ktf_param { @@ -47,7 +49,7 @@ struct __packed ktf_param { #define cmd_param(_name, _var, _type) \ __param_size_check(_var, _name); \ - __ktfparam __cmd_##_var = {_name, _type, &_var, sizeof(_var)}; + __ktfparam __cmd_##_var = {_name, _type, &(_var), sizeof(_var)}; #define bool_cmd(_cmdname, _varname) cmd_param(_cmdname, _varname, BOOL) #define ulong_cmd(_cmdname, _varname) cmd_param(_cmdname, _varname, ULONG) @@ -65,10 +67,13 @@ extern bool opt_hpet; extern bool opt_fpu; extern bool opt_qemu_console; extern bool opt_poweroff; + extern const char *kernel_cmdline; extern void cmdline_parse(const char *cmdline); +extern bool parse_com_port(com_idx_t com, uart_config_t *cfg); + /* Static declarations */ static inline int parse_bool(const char *s) { diff --git a/include/drivers/serial.h b/include/drivers/serial.h index 4bb90a85..1cc4c434 100644 --- a/include/drivers/serial.h +++ b/include/drivers/serial.h @@ -36,10 +36,13 @@ union line_control_register { }; typedef union line_control_register lcr_t; -#define FRAME_SIZE_8_BITS 0x03 -#define FRAME_SIZE_7_BITS 0x02 -#define FRAME_SIZE_6_BITS 0x01 -#define FRAME_SIZE_5_BITS 0x00 +enum com_idx { + COM1 = 0, + COM2 = 1, + COM3 = 2, + COM4 = 3, +}; +typedef enum com_idx com_idx_t; enum com_port { COM1_PORT = 0x3f8, @@ -49,14 +52,52 @@ enum com_port { }; typedef enum com_port com_port_t; -#define STOP_BIT_1 0x00 -#define STOP_BIT_2 0x01 +enum com_baud { + COM_BAUD_300 = 300, + COM_BAUD_1200 = 1200, + COM_BAUD_2400 = 2400, + COM_BAUD_4800 = 4800, + COM_BAUD_9600 = 9600, + COM_BAUD_19200 = 19200, + COM_BAUD_38400 = 38400, + COM_BAUD_57600 = 57600, + COM_BAUD_115200 = 115200, +}; +typedef enum com_baud com_baud_t; + +#define DEFAULT_BAUD_SPEED COM_BAUD_115200 -#define NO_PARITY 0x00 -#define ODD_PARITY 0x01 -#define EVEN_PARITY 0x03 -#define HIGH_PARITY 0x05 -#define LOW_PARITY 0x07 +enum com_frame_size { + COM_FRAME_SIZE_8_BITS = 0x03, + COM_FRAME_SIZE_7_BITS = 0x02, + COM_FRAME_SIZE_6_BITS = 0x01, + COM_FRAME_SIZE_5_BITS = 0x00, +}; +typedef enum com_frame_size com_frame_size_t; + +enum com_stop_bit { + COM_STOP_BIT_1 = 0x00, + COM_STOP_BIT_2 = 0x01, +}; +typedef enum com_stop_bit com_stop_bit_t; + +enum com_parity { + COM_NO_PARITY = 0x00, + COM_ODD_PARITY = 0x01, + COM_EVEN_PARITY = 0x03, + COM_HIGH_PARITY = 0x05, + COM_LOW_PARITY = 0x07, +}; +typedef enum com_parity com_parity_t; + +struct uart_config { + io_port_t port; + com_baud_t baud; + com_frame_size_t frame_size; + com_parity_t parity; + com_stop_bit_t stop_bit; +}; +typedef struct uart_config uart_config_t; union modem_control_register { uint8_t reg; @@ -107,8 +148,14 @@ union interrupt_enable_register { }; typedef union interrupt_enable_register ier_t; -#define COM1_IRQ 4 /* IRQ 4 */ -#define COM2_IRQ 3 /* IRQ 3 */ +enum com_irq { + COM1_IRQ = 4, /* IRQ 4 */ + COM2_IRQ = 3, /* IRQ 3 */ + COM3_IRQ = COM1_IRQ, + COM4_IRQ = COM2_IRQ, +}; +typedef enum com_irq com_irq_t; + #define COM1_IRQ0_OFFSET (PIC_IRQ0_OFFSET + COM1_IRQ) #define COM2_IRQ0_OFFSET (PIC_IRQ0_OFFSET + COM2_IRQ) @@ -125,8 +172,6 @@ typedef union interrupt_enable_register ier_t; #define UART_MSR_REG_OFFSET 0x06 #define UART_SCR_REG_OFFSET 0x07 -#define DEFAULT_BAUD_SPEED 115200 - #define UART_IIR_STATUS_MASK 0x0E /* bits 3, 2, 1 */ #define UART_IIR_RBR_READY 0x04 From b4df455c4662962ee6bcfba12079ff8a78993c40 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Mon, 24 Jan 2022 18:29:55 +0100 Subject: [PATCH 3/4] drivers,serial: use cmdline configuration for UART devices Signed-off-by: Pawel Wieczorkiewicz --- common/setup.c | 20 +++++++++++++------- drivers/serial.c | 40 +++++++++++++++++++++------------------- include/drivers/serial.h | 4 ++-- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/common/setup.c b/common/setup.c index 0697dfee..8a93fdfb 100644 --- a/common/setup.c +++ b/common/setup.c @@ -70,12 +70,18 @@ void set_bsp_cpu_id(unsigned cpu_id) { bsp_cpu_id = cpu_id; } #define QEMU_CONSOLE_PORT 0x0e9 static void __text_init init_console(void) { - io_port_t com_port = get_first_com_port(); - - uart_init(com_port, DEFAULT_BAUD_SPEED); - register_console_callback(serial_console_write, _ptr(com_port)); - - printk("COM1: %x, COM2: %x\n", com_ports[0], com_ports[1]); + uart_config_t cfg = {0}; + + if (!parse_com_port(COM1, &cfg)) { + /* Use first COM port indicated by BIOS (if none, use COM1) */ + cfg.port = get_first_com_port(); + cfg.baud = DEFAULT_BAUD_SPEED; + cfg.frame_size = COM_FRAME_SIZE_8_BITS; + cfg.parity = COM_NO_PARITY; + cfg.stop_bit = COM_STOP_BIT_1; + } + init_uart(&cfg); + register_console_callback(serial_console_write, _ptr(cfg.port)); if (opt_qemu_console) { register_console_callback(qemu_console_write, _ptr(QEMU_CONSOLE_PORT)); @@ -217,7 +223,7 @@ void __noreturn __text_init kernel_start(uint32_t multiboot_magic, init_pci(); /* Initialize console input */ - uart_input_init(get_bsp_cpu_id()); + init_uart_input(get_bsp_cpu_id()); /* Initialize timers */ bool hpet_initialized = false; diff --git a/drivers/serial.c b/drivers/serial.c index c2a2c2d2..b7ea05cd 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -52,14 +52,6 @@ io_port_t get_first_com_port(void) { return COM1_PORT; } -static inline void set_port_mode(io_port_t port, bool stop_bit, uint8_t width) { - lcr_t lcr = {0}; - - lcr.stop_bit = stop_bit; - lcr.width = width; - outb(port + UART_LCR_REG_OFFSET, lcr.reg); -} - static inline void set_dlab(io_port_t port, bool dlab) { lcr_t lcr; @@ -68,6 +60,21 @@ static inline void set_dlab(io_port_t port, bool dlab) { outb(port + UART_LCR_REG_OFFSET, lcr.reg); } +static inline void set_port_mode(uart_config_t *cfg) { + lcr_t lcr = {0}; + + lcr.stop_bit = cfg->stop_bit; + lcr.width = cfg->frame_size; + lcr.parity = cfg->parity; + + outb(cfg->port + UART_LCR_REG_OFFSET, lcr.reg); + + /* Set baud speed by applying divisor to DLL+DLH */ + set_dlab(cfg->port, true); + outw(cfg->port + UART_DLL_REG_OFFSET, DEFAULT_BAUD_SPEED / cfg->baud); + set_dlab(cfg->port, false); +} + static inline bool thr_empty(io_port_t port) { lsr_t lsr; @@ -84,30 +91,25 @@ static inline bool receiver_ready(io_port_t port) { return msr.dsr && msr.cts; } -void uart_init(io_port_t port, unsigned baud) { +void __text_init init_uart(uart_config_t *cfg) { mcr_t mcr = {0}; /* Enable interrupts for received data available */ - outb(port + UART_IER_REG_OFFSET, 0x01); + outb(cfg->port + UART_IER_REG_OFFSET, 0x01); /* Disable FIFO control */ - outb(port + UART_FCR_REG_OFFSET, 0x00); + outb(cfg->port + UART_FCR_REG_OFFSET, 0x00); /* Set 8n1 mode */ - set_port_mode(port, COM_STOP_BIT_1, COM_FRAME_SIZE_8_BITS); - - /* Set baud speed by applying divisor to DLL+DLH */ - set_dlab(port, true); - outw(port + UART_DLL_REG_OFFSET, DEFAULT_BAUD_SPEED / baud); - set_dlab(port, false); + set_port_mode(cfg); /* Set tx/rx ready state */ mcr.dtr = 1; mcr.rts = 1; - outb(port + UART_MCR_REG_OFFSET, mcr.reg); + outb(cfg->port + UART_MCR_REG_OFFSET, mcr.reg); } -void uart_input_init(uint8_t dst_cpus) { +void __text_init init_uart_input(uint8_t dst_cpus) { /* Initialize input state */ memset(&input_state, 0, sizeof(input_state)); diff --git a/include/drivers/serial.h b/include/drivers/serial.h index 1cc4c434..e01f128d 100644 --- a/include/drivers/serial.h +++ b/include/drivers/serial.h @@ -180,8 +180,8 @@ typedef enum com_irq com_irq_t; extern io_port_t com_ports[4]; extern io_port_t get_first_com_port(void); -extern void uart_init(io_port_t port, unsigned baud); -extern void uart_input_init(uint8_t dst_cpus); +extern void init_uart(uart_config_t *cfg); +extern void init_uart_input(uint8_t dst_cpus); extern void uart_interrupt_handler(void); extern int serial_putchar(io_port_t port, char c); extern int serial_write(io_port_t port, const char *buf, size_t len); From d171ac9b4597471d6e4b12e9b9e8539d38fb3781 Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Mon, 24 Jan 2022 18:30:17 +0100 Subject: [PATCH 4/4] setup: display serial console configuration Signed-off-by: Pawel Wieczorkiewicz --- common/setup.c | 3 +++ drivers/serial.c | 34 ++++++++++++++++++++++++++++++++++ include/drivers/serial.h | 2 ++ 3 files changed, 39 insertions(+) diff --git a/common/setup.c b/common/setup.c index 8a93fdfb..6a13239b 100644 --- a/common/setup.c +++ b/common/setup.c @@ -87,6 +87,9 @@ static void __text_init init_console(void) { register_console_callback(qemu_console_write, _ptr(QEMU_CONSOLE_PORT)); printk("Initialized QEMU console at port 0x%x", QEMU_CONSOLE_PORT); } + + printk("Serial console at: "); + display_uart_config(&cfg); } static __always_inline void zero_bss(void) { diff --git a/drivers/serial.c b/drivers/serial.c index b7ea05cd..ec921962 100644 --- a/drivers/serial.c +++ b/drivers/serial.c @@ -39,6 +39,40 @@ static struct { io_port_t __data_rmode com_ports[4]; +static inline const char *com_port_name(com_port_t port) { + switch (port) { + case COM1_PORT: + return "COM1"; + case COM2_PORT: + return "COM2"; + case COM3_PORT: + return "COM3"; + case COM4_PORT: + return "COM4"; + default: + BUG(); + } +} + +static const uint8_t com_frame_size_values[] = { + [COM_FRAME_SIZE_5_BITS] = 5, + [COM_FRAME_SIZE_6_BITS] = 6, + [COM_FRAME_SIZE_7_BITS] = 7, + [COM_FRAME_SIZE_8_BITS] = 8, +}; + +static const char com_parity_names[] = { + [COM_NO_PARITY] = 'n', [COM_ODD_PARITY] = 'o', [COM_EVEN_PARITY] = 'e', + [COM_HIGH_PARITY] = 'h', [COM_LOW_PARITY] = 'l', +}; + +#define COM_STOP_BIT_VALUE(cfg) ((cfg)->stop_bit + 1) + +void display_uart_config(const uart_config_t *cfg) { + printk("[%s] 0x%x %u,%u%c%u\n", com_port_name(cfg->port), cfg->port, cfg->baud, + com_frame_size_values[cfg->frame_size], com_parity_names[cfg->parity], + COM_STOP_BIT_VALUE(cfg)); +} io_port_t get_first_com_port(void) { memcpy((void *) com_ports, _ptr(BDA_COM_PORTS_ENTRY), sizeof(com_ports)); diff --git a/include/drivers/serial.h b/include/drivers/serial.h index e01f128d..a8d5906f 100644 --- a/include/drivers/serial.h +++ b/include/drivers/serial.h @@ -186,4 +186,6 @@ extern void uart_interrupt_handler(void); extern int serial_putchar(io_port_t port, char c); extern int serial_write(io_port_t port, const char *buf, size_t len); +extern void display_uart_config(const uart_config_t *cfg); + #endif /* KTF_DRV_SERIAL_H */