Skip to content
Permalink
Browse files

x86: support very early printk() if desired

Adapted from similar code in the x86_64 port.
Useful when debugging boot problems on actual x86
hardware if a JTAG isn't handy or feasible.

Turn this on for qemu_x86.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
  • Loading branch information...
andrewboie committed Aug 1, 2019
1 parent 14db558 commit bd709c7322904d530be4353a210942899318bdb0
@@ -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"

@@ -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)
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <generated_dts_board.h>
#include <arch/cpu.h>
#include <misc/util.h>

/* 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);
}
@@ -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);
@@ -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

0 comments on commit bd709c7

Please sign in to comment.
You can’t perform that action at this time.