From: Michael Brown Date: Thu, 16 Jul 2026 14:01:57 +0000 (+0100) Subject: [dmesg] Add an in-memory ring buffer console X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e30422e49f54170374cf38941207bc8a4f2de463;p=thirdparty%2Fipxe.git [dmesg] Add an in-memory ring buffer console Add a trivial ring buffer console that can be used to extract the most recent 8kB of (non-UI) console output as the ${dmesg} setting. This allows previous console output to be displayed after the screen has been cleared, such as when a background picture has been loaded. For example: #!ipxe console -p http://boot.ipxe.org/ipxe.png show -q dmesg It also allows console output to be captured and sent as part of an HTTP POST, to allow for remote diagnostics. For example: #!ipxe params param dmesg ${dmesg:base64} imgfetch http://192.168.0.1/api/diags##params The recorded console output may be cleared if necessary by clearing the setting: clear builtin/dmesg The name ${dmesg} is chosen as being unlikely to collide with any existing variables used in end-user scripts. A separate "dmesg" command is not provided, but could easily be added if useful. Note that iPXE supports recursive variable expansion in shell commands. Typing an interactive command such as "echo ${dmesg}" or "param dmesg ${dmesg}" is therefore a great way to exercise the memory allocator to the point of exhaustion. Use "show -q dmesg" to show the ring buffer contents. Signed-off-by: Michael Brown --- diff --git a/src/config/config.c b/src/config/config.c index 563f85d67..1995b8cd4 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -82,6 +82,9 @@ REQUIRE_OBJECT ( debugcon ); #ifdef CONSOLE_SBI REQUIRE_OBJECT ( sbi_console ); #endif +#ifdef CONSOLE_DMESG +REQUIRE_OBJECT ( dmesg ); +#endif /* * Drag in all requested network protocols diff --git a/src/config/console.h b/src/config/console.h index 60d7aa838..a6285481d 100644 --- a/src/config/console.h +++ b/src/config/console.h @@ -25,6 +25,7 @@ FILE_SECBOOT ( PERMITTED ); #define CONSOLE_FRAMEBUFFER /* Graphical framebuffer console */ #define CONSOLE_SYSLOG /* Syslog console */ #define CONSOLE_SYSLOGS /* Encrypted syslog console */ +#define CONSOLE_DMESG /* In-memory ring buffer console */ //#define CONSOLE_DISKLOG /* Disk log console */ /* Console types supported only on systems with serial ports */ diff --git a/src/core/dmesg.c b/src/core/dmesg.c new file mode 100644 index 000000000..66f9607f3 --- /dev/null +++ b/src/core/dmesg.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2026 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +#include +#include +#include +#include + +/** @file + * + * In-memory ring buffer console + * + */ + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_DMESG ) && CONSOLE_EXPLICIT ( CONSOLE_DMESG ) ) +#undef CONSOLE_DMESG +#define CONSOLE_DMESG ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI ) +#endif + +/** Size of ring buffer */ +#define DMESG_LEN 8192 + +/** Ring buffer */ +static char dmesg[DMESG_LEN]; + +/** Offset within ring buffer */ +static unsigned int dmesg_offset; + +/** Ring buffer ANSI escape sequence handlers */ +static struct ansiesc_handler dmesg_ansiesc_handlers[] = { + { 0, NULL } +}; + +/** Ring buffer ANSI escape sequence context */ +static struct ansiesc_context dmesg_ansiesc_ctx = { + .handlers = dmesg_ansiesc_handlers, +}; + +/** + * Print a character to the ring buffer + * + * @v character Character to be printed + */ +static void dmesg_putchar ( int character ) { + + /* Strip ANSI escape sequences */ + character = ansiesc_process ( &dmesg_ansiesc_ctx, character ); + if ( character < 0 ) + return; + + /* Handle backspace characters */ + if ( character == '\b' ) { + if ( dmesg_offset ) + dmesg_offset--; + return; + } + + /* Record character */ + dmesg[ dmesg_offset++ % DMESG_LEN ] = character; +} + +/** Ring buffer console driver */ +struct console_driver dmesg_console __console_driver = { + .putchar = dmesg_putchar, + .usage = CONSOLE_DMESG, +}; + +/** + * Fetch ring buffer setting + * + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int dmesg_fetch ( void *data, size_t len ) { + uint8_t *bytes = data; + size_t max; + unsigned int offset; + + /* Calculate length */ + max = dmesg_offset; + if ( max > DMESG_LEN ) + max = DMESG_LEN; + if ( len > max ) + len = max; + + /* Copy data */ + offset = ( dmesg_offset - len ); + while ( len-- ) + *(bytes++) = dmesg[ offset++ % DMESG_LEN ]; + + return max; +} + +/** + * Store ring buffer setting + * + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +static int dmesg_store ( const void *data __unused, size_t len ) { + + /* Only clearing the log is supported */ + if ( len ) + return -ENOTSUP; + + /* Clear log */ + dmesg_offset = 0; + + return 0; +} + +/** Ring buffer setting */ +const struct setting dmesg_setting __setting ( SETTING_MISC, dmesg ) = { + .name = "dmesg", + .description = "Ring buffer", + .type = &setting_type_string, + .scope = &builtin_scope, +}; + +/** Ring buffer built-in setting */ +struct builtin_setting dmesg_builtin_setting __builtin_setting = { + .setting = &dmesg_setting, + .fetch = dmesg_fetch, + .store = dmesg_store, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 035358009..6faf79d32 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -93,6 +93,7 @@ FILE_SECBOOT ( PERMITTED ); #define ERRFILE_disklog ( ERRFILE_CORE | 0x00340000 ) #define ERRFILE_efi_disklog ( ERRFILE_CORE | 0x00350000 ) #define ERRFILE_datauri ( ERRFILE_CORE | 0x00360000 ) +#define ERRFILE_dmesg ( ERRFILE_CORE | 0x00370000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )