diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 99088d1909d..84639a0929e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -108,6 +108,17 @@ endif # X86_MULTIBOOT_FRAMEBUF endif # X86_MULTIBOOT +config X86_VERY_EARLY_CONSOLE + bool "Support very early boot printk" + depends on PRINTK + help + Non-emulated X86 devices often require special hardware to attach + a debugger, which may not be easily available. This option adds a + very minimal serial driver which gets initialized at the very + beginning of z_cstart(), via kernel_arch_init(). This driver enables + printk to emit messages to the 16550 UART port 0 instance in device + tree. This mini-driver assumes I/O to the UART is done via ports. + source "arch/x86/core/Kconfig.ia32" source "arch/x86/core/Kconfig.x64" diff --git a/arch/x86/core/CMakeLists.txt b/arch/x86/core/CMakeLists.txt index 2a7776bde37..f4fa9ae86d0 100644 --- a/arch/x86/core/CMakeLists.txt +++ b/arch/x86/core/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_compile_options_ifdef(CONFIG_COVERAGE_GCOV zephyr_library_sources_if_kconfig(pcie.c) zephyr_library_sources_if_kconfig(reboot_rst_cnt.c) zephyr_library_sources_ifdef(CONFIG_X86_MULTIBOOT multiboot.c) +zephyr_library_sources_ifdef(CONFIG_X86_VERY_EARLY_CONSOLE early_serial.c) if(CONFIG_X86_LONGMODE) include(x64.cmake) diff --git a/arch/x86/core/early_serial.c b/arch/x86/core/early_serial.c new file mode 100644 index 00000000000..1af4a8625e6 --- /dev/null +++ b/arch/x86/core/early_serial.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* Super-primitive 8250/16550 serial output-only driver, 115200 8n1 */ + +#define PORT ((io_port_t)DT_UART_NS16550_PORT_0_BASE_ADDR) + +#define REG_IER 0x01 /* Interrupt enable reg. */ +#define REG_LCR 0x03 /* Line control reg. */ +#define REG_MCR 0x04 /* Modem control reg. */ +#define REG_LSR 0x05 /* Line status reg. */ +#define REG_DL_LO 0x00 /* Divisor latch low byte */ +#define REG_DL_HI 0x01 /* Divisor latch high byte */ + +#define IER_DISABLE 0x00 +#define LCR_8N1 (BIT(0) | BIT(1)) +#define LCR_DLAB_SELECT BIT(7) +#define MCR_DTR BIT(0) +#define MCR_RTS BIT(1) +#define LCR_THRE BIT(5) + +static void serout(int c) +{ + while (!(sys_in8(PORT + REG_LSR) & LCR_THRE)) { + } + sys_out8(c, PORT); +} + +static int console_out(int c) +{ + if (c == '\n') { + serout('\r'); + } + serout(c); + return c; +} + +extern void __printk_hook_install(int (*fn)(int)); + +void z_x86_early_serial_init(void) +{ + /* In fact Qemu already has most of this set up and works by + * default + */ + sys_out8(IER_DISABLE, PORT + REG_IER); /* Disable interrupts */ + sys_out8(LCR_DLAB_SELECT, PORT + REG_LCR); /* DLAB select */ + sys_out8(1, PORT + REG_DL_LO); /* Baud divisor = 1 */ + sys_out8(0, PORT + REG_DL_HI); + sys_out8(LCR_8N1, PORT + REG_LCR); /* LCR = 8n1 + DLAB off */ + sys_out8(MCR_DTR | MCR_RTS, PORT + REG_MCR); + + /* Will be replaced later when a real serial driver comes up */ + __printk_hook_install(console_out); +} diff --git a/arch/x86/include/ia32/kernel_arch_func.h b/arch/x86/include/ia32/kernel_arch_func.h index c7dbd8029a9..6ab064df59c 100644 --- a/arch/x86/include/ia32/kernel_arch_func.h +++ b/arch/x86/include/ia32/kernel_arch_func.h @@ -23,6 +23,11 @@ extern "C" { extern K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE); +#ifdef CONFIG_X86_VERY_EARLY_CONSOLE +/* Setup ultra-minimal serial driver for printk() */ +void z_x86_early_serial_init(void); +#endif + /** * * @brief Performs architecture-specific initialization @@ -38,6 +43,10 @@ static inline void kernel_arch_init(void) _kernel.nested = 0; _kernel.irq_stack = Z_THREAD_STACK_BUFFER(_interrupt_stack) + CONFIG_ISR_STACK_SIZE; + +#ifdef CONFIG_X86_VERY_EARLY_CONSOLE + z_x86_early_serial_init(); +#endif #if CONFIG_X86_STACK_PROTECTION z_x86_mmu_set_flags(&z_x86_kernel_pdpt, _interrupt_stack, MMU_PAGE_SIZE, MMU_ENTRY_NOT_PRESENT, MMU_PTE_P_MASK); diff --git a/boards/x86/qemu_x86/qemu_x86_defconfig b/boards/x86/qemu_x86/qemu_x86_defconfig index cc41ed75acf..f90157126c0 100644 --- a/boards/x86/qemu_x86/qemu_x86_defconfig +++ b/boards/x86/qemu_x86/qemu_x86_defconfig @@ -18,3 +18,4 @@ CONFIG_X86_MMU=y CONFIG_DEBUG_INFO=y CONFIG_SCHED_SCALABLE=y CONFIG_WAITQ_SCALABLE=y +CONFIG_X86_VERY_EARLY_CONSOLE=y