debugcon_printf for NetBSD This is a NetBSD specific loadable kernel module that implements a standalone printing mechanism to Bochs/Qemu-style debug console (port 0xe9). Prerequisites ============= * NetBSD distribution preinstalled with kernel sources (src/sys) * NetBSD/amd64 kernel tested (i386 should work) Building ======== Steps: 1. Fetch the sources of debugcon_printf. 2. Fetch the NetBSD kernel sources in the same version as your running kernel. 3. If the kernel sources are in a custom location, pass it with BSDSRCDIR. 4. Run make(1) and build the sources of the kernel module: $ make # BSDSRCDIR=/usr/src Testing ======= Testing is performed in user-space. The 'test' target builds two versions of test.c: with debugconf_printf() compiled in userland and printf(3) from libc. As a validation outputs from both functions are compared. In order to run tests, invoke: $ make test Files ===== debugcon_printf.kmod - loadable kernel module for the NetBSD kernel debugcon_printf.h - kernel header with the prototype of debugconf_printf() Usage ===== Start Qemu with extra arguments for debugcon and optionally specifying port: -debugcon dev Redirect the debug console to host device dev (same devices as the serial port). The debug console is an I/O port which is typically port 0xe9; writing to that I/O port sends output to this device. The default device is "vc" in graphical mode and "stdio" in non graphical mode. The debug console port can be specified with: -global isa-debugcon.iobase=0xe9 As root: # modload -i iobase=233 ./debugcon_printf.kmod # 233=0xe9 NB. The argument passed to -i as of NetBSD 8.99.42 must be decimal. Include the debugcon_printf header in your code: #include <debugcon_printf.h> /* or "debugcon_printf.h" */ Print "hello world" in your code: debugcon_printf("Hello world!\n"); Example ======= 1. Start a NetBSD Qemu guest with: $ qemu-system-x86_64 \ ... -debugcon file:/tmp/qemu.debug.log -global isa-debugcon.iobase=0xe9 \ ... 2. Fetch debugcon_printf repository. 3. Build debugconf_printf and insert into the kernel. $ make $ modload ./debugcon_printf.kmod 4. Build example/ and insert into the kernel. $ cd example $ modload ./example.kmod 5. Read the Qemu debug log file. $ cat /tmp/qemu.debug.log | head Hello world 'My string_12345' ' My string_12345' 'My string_12345 ' 'Tab.' '%' 'X' '88' '2' '3' Use-cases ========= Ad-hoc outputing debug text without patching the NetBSD kernel code. The debugging console is specific to an emulator (Bochs and Qemu) and it uses CPU specific code ("outb" instruction). Why to not merge this into mainline kernel code? This implementation is CPU specific and the code is shared with rumpkernels that shall not run privileged instructions. The main motivation here is to output log to an external console out of the guest machine, without triggering sanitizers or code coverage functions, what would be difficult to achieve with using generic kernel code stack. Printing to debug console allows to gather track of enormous kernel trace logs for gigabytes of data. Traditional mechanisms like dmesg(8) are highly restricted to small buffers and are not always suitable to see the full log of booting messages. Supported syntax ================ debugcon_printf() supports the subset of the standard ANSI printf(3) syntax. %[MODIFIERS][WIDTH][TYPE_MODIFIERS][TYPE] Supported modifiers: - '#' Print character with alternative form (supported for numbers only). - '-' Left adjustment (supported for strings only). - '+' Print leading '+' character for signed positive numbers. - ' ' Print leading ' ' character for signed positive numbers. - '0' Print number with leading zeros padding. Field width is a decimal number (supported for strings only). Supported type modifiers: - 'l' long - 'll' long long - 'h' short - 'hh' short short (char) - 'z' size_t type (mapped to long) Supported types: - 's' string (char *) - 'c' character - 'd' signed integer - 'u' unsigned integer - 'x' hex number - 'o' oct number '%%' is printed as '%'. Implementation details ====================== The kernel module is implemented in a single C file debugcon_printf.c with a header for external users debugcon_printf.h. The debugcon_printf() implementation does not call any external system function libraries. The propose of this design is to be independent from other kernel routines that could be instrumented with either sanitizer or code coverage. Porting notes ============= The code in debugcon_printf.c is NetBSD kernel specific. Expanding support to new CPUs requires porting the internal_putchar() function. This function implements I/O port byte write. License ======= BSD 2-clause. Author ====== Kamil Rytarowski <kamil @ NetBSD . org>