diff --git a/drivers/serial/console.c b/drivers/serial/console.c index 1fb33b1e..97e1d564 100644 --- a/drivers/serial/console.c +++ b/drivers/serial/console.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include "stm32f4xx.h" @@ -21,7 +21,6 @@ #define UART1_ISR_PRIORITY 14 static int uart1_dma_puts(const char *data, size_t size); -ssize_t console_write(const char *buf, size_t size); ssize_t serial0_read(struct file *filp, char *buf, size_t size, off_t offset); ssize_t serial0_write(struct file *filp, @@ -33,8 +32,6 @@ int serial0_open(struct inode *inode, struct file *file); void USART1_IRQHandler(void); void DMA2_Stream7_IRQHandler(void); -void uart1_tx_tasklet_handler(unsigned long data); - uart_dev_t uart1 = { .rx_fifo = NULL, .rx_wait_size = 0, @@ -42,10 +39,6 @@ uart_dev_t uart1 = { .tx_state = UART_TX_IDLE, }; -static struct kfifo *uart1_tx_fifo; -static struct tasklet_struct uart1_tx_tasklet; -static LIST_HEAD(uart1_tx_wait_list); - static struct file_operations serial0_file_ops = { .read = serial0_read, .write = serial0_write, @@ -83,6 +76,9 @@ void uart1_init(uint32_t baudrate) }; USART_Init(USART1, &USART_InitStruct); USART_Cmd(USART1, ENABLE); +#if (ENABLE_UART1_DMA != 0) + USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); +#endif USART_ClearFlag(USART1, USART_FLAG_TC); /* Initialize interrupt of the UART1 */ @@ -116,17 +112,9 @@ void tty_init(void) /* Initialize mutex, kfifo, and tasklet for UART1 tx */ mutex_init(&uart1.tx_mtx); - uart1_tx_fifo = kfifo_alloc(PRINT_SIZE_MAX, UART1_TX_FIFO_SIZE); - tasklet_init(&uart1_tx_tasklet, uart1_tx_tasklet_handler, 0); /* Initialize UART1 */ uart1_init(115200); - -#ifndef BUILD_QEMU - /* Clean screen */ - char *cls_str = "\x1b[H\x1b[2J"; - console_write(cls_str, strlen(cls_str)); -#endif } void serial0_init(void) @@ -155,28 +143,16 @@ ssize_t serial0_read(struct file *filp, char *buf, size_t size, off_t offset) } } -ssize_t console_write(const char *buf, size_t size) -{ - kfifo_in(uart1_tx_fifo, buf, size); - tasklet_schedule(&uart1_tx_tasklet); - return size; -} - ssize_t serial0_write(struct file *filp, const char *buf, size_t size, off_t offset) { - CURRENT_THREAD_INFO(curr_thread); - - if (kfifo_avail(uart1_tx_fifo) > 0) { - kfifo_in(uart1_tx_fifo, buf, size); - tasklet_schedule(&uart1_tx_tasklet); - return size; - } else { - prepare_to_wait(&uart1_tx_wait_list, &curr_thread->list, THREAD_WAIT); - return -ERESTARTSYS; - } +#if (ENABLE_UART1_DMA != 0) + return uart1_dma_puts(buf, size); +#else + return uart_puts(USART1, buf, size); +#endif } void early_write(char *buf, size_t size) @@ -224,6 +200,7 @@ static int uart1_dma_puts(const char *data, size_t size) /* Wait until DMA completed data transfer */ init_wait(uart1.tx_wait); prepare_to_wait(&uart1.tx_wq, uart1.tx_wait, THREAD_WAIT); + return -ERESTARTSYS; } case UART_TX_DMA_BUSY: { @@ -236,6 +213,7 @@ static int uart1_dma_puts(const char *data, size_t size) } /* Notified by the DMA ISR, the data transfer is now complete */ + DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, DISABLE); uart1.tx_state = UART_TX_IDLE; return size; } @@ -245,23 +223,6 @@ static int uart1_dma_puts(const char *data, size_t size) } } -void uart1_tx_tasklet_handler(unsigned long data) -{ - char *buf; - size_t size; - - kfifo_dma_out_prepare(uart1_tx_fifo, &buf, &size); - uart_puts(USART1, buf, size); - kfifo_dma_out_finish(uart1_tx_fifo); - - /* Wake up a write-waiting thread */ - wake_up(&uart1_tx_wait_list); - - /* Schedule the tasklet again if the fifo is not cleared */ - if (!kfifo_is_empty(uart1_tx_fifo)) - tasklet_schedule(&uart1_tx_tasklet); -} - void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) { diff --git a/drivers/serial/debug_link.c b/drivers/serial/debug_link.c index 1c5e68cb..467679b7 100644 --- a/drivers/serial/debug_link.c +++ b/drivers/serial/debug_link.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "stm32f4xx.h" diff --git a/drivers/serial/mavlink.c b/drivers/serial/mavlink.c index e19a3fd7..89772691 100644 --- a/drivers/serial/mavlink.c +++ b/drivers/serial/mavlink.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "stm32f4xx.h" diff --git a/include/kernel/printk.h b/include/kernel/printk.h index 1b0e85bd..41e6cb5e 100644 --- a/include/kernel/printk.h +++ b/include/kernel/printk.h @@ -23,4 +23,8 @@ void printk(char *format, ...); */ void panic(char *format, ...); +void printkd_init(void); +void printkd_start(void); +void printkd(void); + #endif diff --git a/kconfig.h b/kconfig.h index 4d6001bb..7eea3508 100644 --- a/kconfig.h +++ b/kconfig.h @@ -16,6 +16,7 @@ #define IDLE_STACK_SIZE 2048 #define SOFTIRQD_STACK_SIZE 2048 #define FILESYSD_STACK_SIZE 2048 +#define PRINTKD_STACK_SIZE 1024 /* Task */ #define TASK_MAX 64 /* Max number of tasks in the system */ diff --git a/kernel/arch/v7m_port.c b/kernel/arch/v7m_port.c index bb51d185..70a38ba3 100644 --- a/kernel/arch/v7m_port.c +++ b/kernel/arch/v7m_port.c @@ -204,13 +204,13 @@ void fault_dump(uint32_t fault_type, uint32_t *msp, uint32_t *psp, uint32_t lr) if (lr == 0xfffffff1 || lr == 0xffffffe1) { fault_stack = msp; - fault_location = "Fault location: IRQ Handler (sp = msp)\n"; + fault_location = "Fault location: IRQ Handler (sp = msp)\n\r"; } else if (lr == 0xfffffff9 || lr == 0xffffffe9) { fault_stack = msp; - fault_location = "Fault location: Kernel (sp = msp)\n"; + fault_location = "Fault location: Kernel (sp = msp)\n\r"; } else if (lr == 0xfffffffd || lr == 0xffffffed) { fault_stack = psp; - fault_location = "Fault location: Thread (sp = psp)\n"; + fault_location = "Fault location: Thread (sp = psp)\n\r"; } char *fault_type_s = ""; diff --git a/kernel/kernel.c b/kernel/kernel.c index 194730bf..24e4f281 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -2685,6 +2685,11 @@ static void schedule(void) static void print_platform_info(void) { +#ifndef BUILD_QEMU + /* Clear screen */ + char *cls_str = "\x1b[H\x1b[2J"; + console_write("\x1b[H\x1b[2J", strlen(cls_str)); +#endif printk("Tenok RTOS (built time: %s %s)", __TIME__, __DATE__); printk("Machine model: %s", __BOARD_NAME__); } @@ -2738,6 +2743,7 @@ void init(void) link_stdin_dev(STDIN_DEV_PATH); link_stdout_dev(STDOUT_DEV_PATH); link_stderr_dev(STDERR_DEV_PATH); + printkd_start(); } preempt_enable(); @@ -2770,6 +2776,7 @@ void sched_start(void) slab_init(); heap_init(); tty_init(); + printkd_init(); rootfs_init(); /* Initialize ready lists */ @@ -2781,6 +2788,7 @@ void sched_start(void) kthread_create(init, 0, IDLE_STACK_SIZE); kthread_create(softirqd, KTHREAD_PRI_MAX, SOFTIRQD_STACK_SIZE); kthread_create(filesysd, KTHREAD_PRI_MAX - 1, FILESYSD_STACK_SIZE); + kthread_create(printkd, KTHREAD_PRI_MAX - 1, PRINTKD_STACK_SIZE); /* Dequeue thread 0 (Idle) to execute */ running_thread = &threads[0]; diff --git a/kernel/printk.c b/kernel/printk.c index a3d3b6ae..54e49177 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -3,7 +3,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -11,6 +17,52 @@ #include "kconfig.h" +#define PRINTK_QUEUE_SIZE 10 + +struct printk_data { + struct list_head list; + size_t size; + char data[PRINT_SIZE_MAX]; +}; + +static struct printk_data printk_buf[PRINTK_QUEUE_SIZE]; + +static LIST_HEAD(printkd_wait); +static LIST_HEAD(printk_free_list); +static LIST_HEAD(printk_wait_list); + +static bool stdout_initialized; +static bool printk_is_writing; + +ssize_t console_write(const char *buf, size_t size) +{ + struct printk_data *entry; + + /* Check if the free list still has space */ + if (list_empty(&printk_free_list)) { + /* No, overwrite the oldest buffer */ + entry = list_first_entry(&printk_wait_list, struct printk_data, list); + /* Move the buffer to the end of the wait queue */ + list_del(&entry->list); + list_add(&entry->list, &printk_wait_list); + } else { + /* Yes, take one buffer from the free queue */ + entry = list_first_entry(&printk_free_list, struct printk_data, list); + /* Move the buffer to the wait queue */ + list_move(&entry->list, &printk_wait_list); + } + + /* Copy write message to the prink buffer */ + memcpy(entry->data, buf, sizeof(char) * size); + entry->size = size; + + /* Wake up the printk daemon */ + if (!printk_is_writing) + wake_up_all(&printkd_wait); + + return 0; +} + void printk(char *format, ...) { va_list args; @@ -55,3 +107,63 @@ void panic(char *format, ...) while (1) ; } + +void printkd_init(void) +{ + /* Place all prink buffers to the free queue */ + for (int i = 0; i < PRINTK_QUEUE_SIZE; i++) + list_add(&printk_buf[i].list, &printk_free_list); +} + +void printkd_start(void) +{ + /* Initiate the printk daemon */ + stdout_initialized = true; + wake_up_all(&printkd_wait); +} + +static void printkd_sleep(void) +{ + CURRENT_THREAD_INFO(curr_thread); + + preempt_disable(); + prepare_to_wait(&printkd_wait, &curr_thread->list, THREAD_WAIT); + jump_to_kernel(); + preempt_enable(); +} + +void printkd(void) +{ + setprogname("printk"); + + struct printk_data *entry; + + /* Wait until stdout is ready */ + while (!stdout_initialized) + printkd_sleep(); + + while (1) { + /* Check if there is any printk message to write */ + if (list_empty(&printk_wait_list)) { + /* No, suspend the daemon */ + printkd_sleep(); + } else { + /* Pop one prink data from the wait queue */ + preempt_disable(); + entry = + list_first_entry(&printk_wait_list, struct printk_data, list); + list_del(&entry->list); + preempt_enable(); + + /* Write printk message to the serial */ + printk_is_writing = true; + write(STDOUT_FILENO, entry->data, entry->size); + printk_is_writing = false; + + /* Place the used buffer back to the free queue */ + preempt_disable(); + list_add(&entry->list, &printk_free_list); + preempt_enable(); + } + } +} diff --git a/kernel/softirq.c b/kernel/softirq.c index f00ff4af..49b7d93a 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -55,7 +55,8 @@ void softirqd(void) softirqd_sleep(); } else { preempt_disable(); - + while (1) + ; /* Retrieve the next tasklet */ t = list_first_entry(&tasklet_list, struct tasklet_struct, list); list_del(&t->list);