Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix UART initialization and support early and cmdline specified serial consoles #304

Merged
merged 4 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions common/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,19 @@ void fb_console_write(void *fb_memory, const char *buf, size_t len) {
fb_write(fb_memory, buf, len, FB_WHITE);
}

static inline bool is_console_callback_registered(console_callback_t cb, void *arg) {
for (unsigned int i = 0; i < num_console_callbacks; i++) {
if (console_callbacks[i].cb == cb && console_callbacks[i].arg == arg)
return true;
}

return false;
}

void register_console_callback(console_callback_t cb, void *arg) {
if (is_console_callback_registered(cb, arg))
return;

console_callbacks[num_console_callbacks].cb = cb;
console_callbacks[num_console_callbacks++].arg = arg;
}
Expand Down
52 changes: 36 additions & 16 deletions common/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,45 @@ unsigned long cpu_frequency;

#define QEMU_CONSOLE_PORT 0x0e9

static void __text_init init_console(void) {
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));
static inline int __text_init init_uart_console(com_idx_t com, const uart_config_t *cfg) {
int rc = init_uart(com, cfg);

if (rc != 0)
return rc;

register_console_callback(serial_console_write, _ptr(cfg->port));
printk("Serial console at: ");
display_uart_config(com, cfg);

return rc;
}

static void __text_init init_early_console(void) {
uart_config_t 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_console(COM1, &cfg);

if (opt_qemu_console) {
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 void __text_init init_serial_consoles(void) {
uart_config_t cfg;

for (com_idx_t com = COM1; com < MAX_COM; com++) {
memset(&cfg, 0, sizeof(cfg));
if (parse_com_port(com, &cfg))
init_uart_console(com, &cfg);
}
}

static __always_inline void zero_bss(void) {
Expand Down Expand Up @@ -166,7 +184,7 @@ void __noreturn __text_init kernel_start(uint32_t multiboot_magic, unsigned long
zero_bss();

/* Initialize console early */
init_console();
init_early_console();

if (multiboot_magic == MULTIBOOT2_BOOTLOADER_MAGIC) {
/* Indentity mapping is still on, so fill in multiboot structures */
Expand All @@ -178,6 +196,8 @@ void __noreturn __text_init kernel_start(uint32_t multiboot_magic, unsigned long
if (!string_empty(kernel_cmdline))
printk("Command line: %s\n", kernel_cmdline);

init_serial_consoles();

init_boot_traps();

init_real_mode();
Expand Down
49 changes: 31 additions & 18 deletions drivers/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <apic.h>
#include <errno.h>
#include <ioapic.h>
#include <ktf.h>
#include <lib.h>
Expand All @@ -39,15 +40,15 @@ 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:
static inline const char *com_name(com_idx_t com) {
switch (com) {
case COM1:
return "COM1";
case COM2_PORT:
case COM2:
return "COM2";
case COM3_PORT:
case COM3:
return "COM3";
case COM4_PORT:
case COM4:
return "COM4";
default:
BUG();
Expand All @@ -68,8 +69,8 @@ static const char com_parity_names[] = {

#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,
void display_uart_config(com_idx_t com, const uart_config_t *cfg) {
printk("[%s] 0x%x %u,%u%c%u\n", com_name(com), cfg->port, cfg->baud,
com_frame_size_values[cfg->frame_size], com_parity_names[cfg->parity],
COM_STOP_BIT_VALUE(cfg));
}
Expand All @@ -94,7 +95,7 @@ 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) {
static inline void set_port_mode(const uart_config_t *cfg) {
lcr_t lcr = {0};

/* Set baud speed by applying divisor to DLL+DLH */
Expand Down Expand Up @@ -124,7 +125,20 @@ static inline bool receiver_ready(io_port_t port) {
return msr.dsr && msr.cts;
}

void __text_init init_uart(uart_config_t *cfg) {
#define PORT_TIMEOUT 100 /* ~100ms */
static inline int uart_port_ready(io_port_t port) {
unsigned retries = PORT_TIMEOUT;

do {
if (receiver_ready(port))
return 0;
io_delay();
} while (retries--);

return -ENODEV;
}

int __text_init init_uart(com_idx_t com, const uart_config_t *cfg) {
mcr_t mcr = {0};
fcr_t fcr = {0};
ier_t ier = {0};
Expand All @@ -151,8 +165,9 @@ void __text_init init_uart(uart_config_t *cfg) {
mcr.aux = 2;
outb(cfg->port + UART_MCR_REG_OFFSET, mcr.reg);

if (com_ports[0] == NO_COM_PORT)
com_ports[0] = cfg->port;
com_ports[com] = cfg->port;

return uart_port_ready(cfg->port);
}

void __text_init init_uart_input(const cpu_t *cpu) {
Expand All @@ -168,11 +183,11 @@ void __text_init init_uart_input(const cpu_t *cpu) {

static inline int uart_port_status(io_port_t port) {
if (!receiver_ready(port))
return -1; /* ENODEV */
return -ENODEV;

if (!thr_empty(port)) {
io_delay();
return 1; /* EAGAIN */
return -EAGAIN;
}

return 0;
Expand Down Expand Up @@ -203,8 +218,7 @@ int serial_putchar(io_port_t port, char c) {

do {
rc = uart_putc(port, c);
BUG_ON(rc < 0);
} while (rc > 0 && retries--);
} while (rc == -EAGAIN && retries--);

return rc;
}
Expand All @@ -215,8 +229,7 @@ int serial_write(io_port_t port, const char *buf, size_t len) {

do {
rc = uart_puts(port, buf, len);
BUG_ON(rc < 0);
} while (rc > 0 && retries--);
} while (rc == -EAGAIN && retries--);

return rc;
}
Expand Down
5 changes: 3 additions & 2 deletions include/drivers/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum com_idx {
COM2 = 1,
COM3 = 2,
COM4 = 3,
MAX_COM,
};
typedef enum com_idx com_idx_t;

Expand Down Expand Up @@ -199,12 +200,12 @@ 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 init_uart(uart_config_t *cfg);
extern int init_uart(com_idx_t com, const uart_config_t *cfg);
extern void init_uart_input(const cpu_t *cpu);
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);
extern void display_uart_config(com_idx_t com, const uart_config_t *cfg);

#endif /* KTF_DRV_SERIAL_H */