[PATCH] Added command "dmesg" to provide a means of logging and replaying console output. Dmesg can display output via pages directly through the command line interface, or it can dump the entire buffer to a remote host via a TCP connection.
Matthew Lowe
mlowe at shaw.ca
Sat Jul 3 12:24:58 EDT 2010
There are three components to dmesg:
- dmesg memory buffer (core/dmesg.c)
- dmesg console driver (core/dmesg_console.c)
- dmesg userspace command (hci/commandline/dmesg_cmd.c)
Signed-off-by: Matthew Lowe <mlowe at shaw.ca>
---
src/config/config.c | 5 +
src/config/general.h | 4 +
src/core/dmesg.c | 170 ++++++++++++++++
src/core/dmesg_console.c | 56 ++++++
src/hci/commands/dmesg_cmd.c | 439
++++++++++++++++++++++++++++++++++++++++++
src/include/gpxe/dmesg.h | 57 ++++++
src/include/gpxe/errfile.h | 2 +
7 files changed, 733 insertions(+), 0 deletions(-)
create mode 100644 src/core/dmesg.c
create mode 100644 src/core/dmesg_console.c
create mode 100644 src/hci/commands/dmesg_cmd.c
create mode 100644 src/include/gpxe/dmesg.h
diff --git a/src/config/config.c b/src/config/config.c
index a6e7622..7b44564 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -252,6 +252,11 @@ REQUIRE_OBJECT ( gdbidt );
REQUIRE_OBJECT ( gdbudp );
REQUIRE_OBJECT ( gdbstub_cmd );
#endif
+#ifdef DMESG
+REQUIRE_OBJECT ( dmesg );
+REQUIRE_OBJECT ( dmesg_console );
+REQUIRE_OBJECT ( dmesg_cmd );
+#endif
=20
/*
* Drag in objects that are always required, but not dragged in via
diff --git a/src/config/general.h b/src/config/general.h
index bfab5b6..244acaf 100644
--- a/src/config/general.h
+++ b/src/config/general.h
@@ -144,6 +144,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#undef GDBSERIAL /* Remote GDB debugging over serial */
#undef GDBUDP /* Remote GDB debugging over UDP
* (both may be set) */
+#undef DMESG /* Console memory buffer for debugging
*/
+#define DMESG_PAGE_SIZE 10240 /* Memory buffer page size */
+#define DMESG_PAGES 20 /* Total memory buffer size is
+ * pages * page_size */
=20
#include <config/local/general.h>
=20
diff --git a/src/core/dmesg.c b/src/core/dmesg.c
new file mode 100644
index 0000000..409cbc4
--- /dev/null
+++ b/src/core/dmesg.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2010 Matthew Lowe <mlowe at shaw.ca>.
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <curses.h>
+#include <errno.h>
+#include <config/general.h>
+#include <gpxe/dmesg.h>
+#include <gpxe/init.h>
+#include <gpxe/umalloc.h>
+#include <gpxe/errfile.h>
+
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct dmesg_buffer dmesg_buffer =3D {
+ .buffer =3D NULL,
+ .pos =3D NULL,
+ .size =3D 0,
+ .locked =3D FALSE,
+};
+
+/**
+ *=20
+ * Cycle data buffer by one page
+ *
+ */
+void shift_one_page ()
+{
+ int len =3D (int) ( dmesg_buffer.pos + 1 - dmesg_buffer.buffer) -
DMESG_PAGE_SIZE;
+
+ if ( len <=3D 0)
+ return;
+
+ /* Copy buffer memory and include null terminator */
+ memcpy ( dmesg_buffer.buffer, dmesg_buffer.buffer + DMESG_PAGE_SIZE,
+ len );
+
+ dmesg_buffer.pos -=3D DMESG_PAGE_SIZE;
+}
+
+/**
+ *
+ * Write character to buffer
+ * @v ch Character to write
+ *
+ */
+void dmesg_putc ( int ch ) {
+
+ /* Ensure the buffer is not locked and is allocated */
+ if ( dmesg_buffer.locked || !dmesg_buffer.size )
+ return;
+
+ /* Remap delete to backspace */
+ if ( ch =3D=3D 0x7f )
+ ch =3D 0x08;
+
+ /* If we're out of buffer space (include NULL terminator),=20
+ * cycle the buffer one page */
+ if ( (unsigned int) ( dmesg_buffer.pos + 1 - dmesg_buffer.buffer ) =
=3D=3D
+ dmesg_buffer.size )=20
+ shift_one_page ();
+ =20
+ *(dmesg_buffer.pos++) =3D (char) ch;
+
+ /* Null terminate buffer for convenience, but do not increment write
position */
+ *dmesg_buffer.pos =3D '\0';
+
+}
+
+/**
+ * Dmesg getc console driver function
+ * @ret ch Always 0, no input to return
+ */
+int dmesg_getc ( void ) {
+ return 0;=20
+}
+
+/**
+ * Dmesg ischar console driver function
+ * @ret status Always 0, no input to return
+ */
+int dmesg_ischar ( void ) {
+ return 0;
+}
+
+/**
+ * Initialize dmesg memory buffer
+ */
+static void dmesg_init ( void ) {
+ =20
+ /* If buffer is already initialized, do not initialize again */
+ if ( dmesg_buffer.buffer )
+ return;
+
+#if DMESG_PAGES < 2
+# error "DMESG_PAGES must be at least 2"
+#endif
+
+#if DMESG_PAGE_SIZE < 2
+# error "DMESG_PAGES must be at least 2"
+#endif
+
+ dmesg_buffer.user_buffer =3D umalloc ( DMESG_PAGE_SIZE * DMESG_PAGES =
);
+
+ if ( !dmesg_buffer.user_buffer )
+ {
+ DBGC ( dmesg_buffer, "Could not initiliaze dmesg console buffer:
%s\n", strerror (-ENOMEM) );
+ goto out;
+ }
+=20
+ dmesg_buffer.buffer =3D (char *) user_to_phys (
dmesg_buffer.user_buffer, 0 );
+
+ dmesg_buffer.size =3D DMESG_PAGE_SIZE * DMESG_PAGES;
+ dmesg_buffer.pos =3D dmesg_buffer.buffer;
+
+ out:
+ return;
+}
+
+/**
+ * Free dmesg buffer
+ * @v __unused Unused
+ */
+static void dmesg_fini ( int flags __unused ) {
+
+ /* Sanity check - don't free the buffer while in use */
+ if ( dmesg_buffer.locked )
+ {
+ DBGC ( dmesg_buffer, "Could not free dmesg buffer because buffer
is locked.\n" );
+ return;
+ }
+
+ /* Only free buffer if one was allocated */
+ if ( dmesg_buffer.user_buffer )
+ ufree ( dmesg_buffer.user_buffer );
+ =20
+ /* Zero memory buffer access structure */
+ memset ( &dmesg_buffer, 0, sizeof (dmesg_buffer) ); =20
+}
+
+/**
+ * Dmesg driver initialization function
+ *
+ * Initialize memory buffer at the same time as the serial driver.
+ * Why does the serial driver have it's own INIT level?
+ */
+struct init_fn dmesg_init_fn __init_fn ( INIT_SERIAL ) =3D {
+ .initialise =3D dmesg_init,
+};
+
+/** Dmesg driver startup (and shutdown) function */
+struct startup_fn dmesg_startup_fn __startup_fn ( STARTUP_EARLY ) =3D {
+ .shutdown =3D dmesg_fini,
+};
diff --git a/src/core/dmesg_console.c b/src/core/dmesg_console.c
new file mode 100644
index 0000000..fac2617
--- /dev/null
+++ b/src/core/dmesg_console.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Matthew Lowe <mlowe at shaw.ca>.
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <console.h>
+#include <gpxe/init.h>
+#include <gpxe/dmesg.h>
+
+/** @file
+ *
+ * Dmesg console
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct console_driver dmesg_console __console_driver;
+
+/**
+ * Enable console
+ */
+static void dmesg_console_init ( void ) {
+ dmesg_console.disabled =3D 0;
+}
+
+/**=20
+ * Dmesg console driver
+ */
+struct console_driver dmesg_console __console_driver =3D {
+ .putchar =3D dmesg_putc,
+ .getchar =3D dmesg_getc,
+ .iskey =3D dmesg_ischar,
+ .disabled =3D 1,
+};
+
+/**
+ * Dmesg console initialization function
+ */
+struct init_fn dmesg_console_init_fn __init_fn ( INIT_CONSOLE ) =3D {
+ .initialise =3D dmesg_console_init,
+};
diff --git a/src/hci/commands/dmesg_cmd.c b/src/hci/commands/dmesg_cmd.c
new file mode 100644
index 0000000..bdd4ff2
--- /dev/null
+++ b/src/hci/commands/dmesg_cmd.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2010 Matthew Lowe <mlowe at shaw.ca>.
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <curses.h>
+#include <console.h>
+#include <byteswap.h>
+#include <gpxe/process.h>
+#include <gpxe/errfile.h>
+#include <gpxe/command.h>
+#include <gpxe/xfer.h>
+#include <gpxe/tcpip.h>
+#include <gpxe/open.h>
+#include <gpxe/job.h>
+#include <gpxe/monojob.h>
+#include <gpxe/dmesg.h>
+
+/** @file
+ *=20
+ * Dmesg userpace command
+ *=20
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern struct dmesg_buffer dmesg_buffer;
+
+/**=20
+ *
+ * Dump dmesg buffer and page output
+ *
+ * @v rows Rows per page
+ * @v cols Columns per row
+ * @ret rc Return status code
+ */=20
+static int page_dmesg (int rows, int cols)
+{
+ char *ls, *pos, c;
+ int lines;
+
+ /* Ensure the buffer is not locked */
+ if ( dmesg_buffer.locked )
+ return -EADDRINUSE;
+
+ if ( !dmesg_buffer.buffer )
+ return -EINVAL;
+ =20
+ dmesg_buffer.locked =3D TRUE;
+ =20
+ ls =3D pos =3D dmesg_buffer.buffer;
+
+ /* Begin parsing buffer, one line at a time */
+ while ( pos < dmesg_buffer.pos )
+ {
+ pos =3D strchr (ls, '\n');
+ =20
+ if ( !pos )
+ pos =3D dmesg_buffer.pos;
+
+ /* Auto-wrap output if characters before NL
+ * is greater than desired columns */
+ if ((pos - ls) > cols)
+ pos =3D ls + cols;
+
+ /* Null terminate line */
+ c =3D *pos;
+ *pos =3D '\0';
+ =20
+ printf ("%s\n",ls);
+ =20
+ /* Remove null terminator */
+ *pos =3D c;
+
+ if (c =3D=3D '\n')
+ pos++;
+
+ ls =3D pos;
+ lines ++;
+
+ /* If we've displayed one page out output, wait for user
+ * input to continue */
+ if (lines =3D=3D (rows - 1))
+ {
+ lines =3D 0;
+ printf ( "--More--" );
+ c =3D getchar();
+
+ /* Erase prompt - incase we are logging output somewhere else
+ * such as a serial console */
+ printf ( "\r \r" );
+
+ if (c =3D=3D 'q')
+ {
+ dmesg_buffer.locked =3D FALSE;
+ return -ECANCELED;
+ }
+
+ }
+ }
+
+ dmesg_buffer.locked =3D FALSE;
+ return PXENV_STATUS_SUCCESS;
+}
+
+/** TCP Sender */
+struct tcpsender {
+ /** Reference count for this object */
+ struct refcnt refcnt;
+
+ /** Job control interface */
+ struct job_interface job;
+
+ /** Process control interface */
+ struct process process;
+
+ /** TCP Socket */
+ struct xfer_interface socket;
+ struct sockaddr_tcpip server;
+
+ /** Data Information */
+ char *pos;
+ char *end;
+};
+
+/**
+ * Cleanup all interfaces and terminate process
+ *
+ * @v tcsender TCPsender session
+ * @v rc Return status code
+ */
+static void tcpsender_finished ( struct tcpsender *tcpsender, int rc )
{
+
+ /* Remove process */
+ process_del ( &tcpsender->process );
+
+ /* Block further incoming messages */
+ job_nullify ( &tcpsender->job );
+ xfer_nullify ( &tcpsender->socket );
+
+ /* Free resources and close interfaces */
+ xfer_close ( &tcpsender->socket, rc );
+ job_done ( &tcpsender->job, rc );
+}
+
+/**
+ * Gracefully handle socket closure
+ *
+ * @v socket TCP socket
+ * @v rc Return status code
+ */
+static void tcpsender_xfer_close ( struct xfer_interface *socket, int
rc ) {
+ struct tcpsender *tcpsender =3D
+ container_of ( socket, struct tcpsender, socket );
+
+ /* Terminate tcpsender */
+ tcpsender_finished ( tcpsender, rc );
+}
+
+/**
+ * Tcpsender process
+ *
+ * @v process Tcpsender process
+ */
+static void tcpsender_step ( struct process *process ) {
+ int rc;
+ int ws;
+
+ struct tcpsender *tcpsender =3D
+ container_of ( process, struct tcpsender, process );
+
+ /* Set processing positions in dmesg buffer if they are not set yet
*/
+ if ( !tcpsender->pos )
+ tcpsender->pos =3D dmesg_buffer.buffer;
+ =20
+ if ( !tcpsender->end )
+ tcpsender->end =3D dmesg_buffer.pos;
+ =20
+ /* Wait for TCP connection to establish or TX queue to empty */
+ if ( ( ws =3D xfer_window ( &tcpsender->socket ) ) )
+ {
+ /* If we have no more data terminate the job */
+ if ( tcpsender->pos =3D=3D tcpsender->end)
+ {
+ tcpsender_finished ( tcpsender, PXENV_STATUS_SUCCESS );
+ return;
+ }
+
+ if ( ( tcpsender->pos + ws ) > tcpsender->end )
+ ws =3D (int) ( tcpsender->end - tcpsender->pos );
+ =20
+ =20
+ rc =3D xfer_deliver_raw ( &tcpsender->socket, tcpsender->pos, ws =
);
+ tcpsender->pos +=3D ws;
+
+ if ( rc )
+ tcpsender_finished ( tcpsender, rc );
+ }
+}
+
+/**
+ * Gracefully handle kill request
+ * @v job Job interface
+ */
+static void tcpsender_job_kill ( struct job_interface *job ) {
+ struct tcpsender *tcpsender =3D
+ container_of ( job, struct tcpsender, job );
+
+ /* Terminate tcpsender */
+ tcpsender_finished ( tcpsender, -ECANCELED );
+}
+
+/* Tcpsender job control interface */
+static struct job_interface_operations tcpsender_job_operations =3D {
+ .done =3D ignore_job_done,
+ .kill =3D tcpsender_job_kill,
+ .progress =3D ignore_job_progress,
+};
+
+/* Tcpsender xfer interface */
+static struct xfer_interface_operations tcpsender_socket_operations =3D =
{
+ .close =3D tcpsender_xfer_close,
+ .vredirect =3D xfer_vreopen,
+ .window =3D unlimited_xfer_window,
+ .alloc_iob =3D default_xfer_alloc_iob,
+ .deliver_iob =3D xfer_deliver_as_raw,
+ .deliver_raw =3D ignore_xfer_deliver_raw,
+ };
+
+/**
+ * Free tcpsender session
+ * @v refcnt Reference counter
+ */
+static void tcpsender_free ( struct refcnt *refcnt ) {
+ struct tcpsender *tcpsender =3D
+ container_of ( refcnt, struct tcpsender, refcnt );
+
+ free ( tcpsender );
+}
+
+/**
+ * Send dmesg buffer to remote host
+ * @v host Remote host
+ * @v port Destination port
+ * @ret rc Return status
+ */
+static int dmesg_tcp (char *host, char *port)
+{
+ struct tcpsender *tcpsender;
+ int rc;
+
+ /* Sanity check host and port parameters */
+ if (!host || !port)
+ return -EINVAL;
+ =20
+ /* Ensure the dmesg buffer is available */
+ if ( dmesg_buffer.locked )
+ {
+ printf ("DMESG buffer is currently locked.\n");
+ return -EADDRINUSE;
+ }
+
+ dmesg_buffer.locked =3D TRUE;
+
+ /* Allocate and initialize tcpsender session */
+ if ( ! ( tcpsender =3D zalloc ( sizeof(*tcpsender) ) ) )
+ {
+ dmesg_buffer.locked =3D FALSE;
+ return -ENOMEM;
+ }
+
+ tcpsender->refcnt.free =3D tcpsender_free;
+
+ job_init ( &tcpsender->job, &tcpsender_job_operations,=20
+ &tcpsender->refcnt );
+
+ xfer_init ( &tcpsender->socket, &tcpsender_socket_operations,=20
+ &tcpsender->refcnt );
+
+ process_init ( &tcpsender->process, tcpsender_step,
&tcpsender->refcnt );
+
+ tcpsender->server.st_port =3D htons ( strtoul ( port, NULL, 0 ) );
+ =20
+ /* Open socket to remote host */
+ if ( ( rc =3D xfer_open_named_socket ( &tcpsender->socket, =
SOCK_STREAM,
+ (struct sockaddr *)
&tcpsender->server,
+ host, NULL ) ) !=3D 0 )
+ goto err;
+ =20
+ /* Attach parent interface */
+ job_plug_plug ( &tcpsender->job, &monojob );
+
+ /* Wait for send to complete */
+ rc =3D monojob_wait ( "Sending" );
+ =20
+ ref_put ( &tcpsender->refcnt );
+ =20
+ dmesg_buffer.locked =3D FALSE;
+
+ return rc;
+ =20
+ err:
+ tcpsender_finished ( tcpsender, rc );
+ ref_put ( &tcpsender->refcnt );
+ =20
+ dmesg_buffer.locked =3D FALSE;
+ =20
+ return rc;
+}
+
+/**
+ * Display command usage
+ */
+static void dmesg_print_syntax ( ) {
+ printf ( "Usage:\n"
+ " dmesg [OPTIONS]\n"
+ " -h, --help - Show this help message\n"
+ " -n, --nopage - Do not page output\n"
+ " -r rows, --rows rows - Print [rows] rows per page\n"
+ " -c cols, --cols cols - Print [cols] characters per
row\n"
+ " -t host:port, --tcp ip:port - Dump dmesg output to
[ip]:[port] via TCP\n"
+ "\n"
+ "Display debug messages\n");
+}
+
+/**
+ * dmesg command
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Exit code
+ */
+static int dmesg_exec ( int argc, char **argv ) {
+
+ static struct option longopts[] =3D {
+ { "help", no_argument, NULL, 'h' },
+ { "rows", required_argument, NULL, 'r' },
+ { "cols", required_argument, NULL, 'c' },
+ { "nopage", no_argument, NULL, 'n' },
+ { "tcp", required_argument, NULL, 't'},
+ { NULL, 0, NULL, 0 },
+ };
+
+ int c;
+ int rows =3D 25;
+ int cols =3D 80;
+ char *port;
+
+ /* Parse options */
+ while ( ( c =3D getopt_long ( argc, argv, "hr:c:nt:",
+ longopts, NULL ) ) >=3D 0 ) {
+ switch ( c ) {
+ case 'r':
+ /* Set number of rows per page */
+ rows =3D strtoul ( optarg, NULL, 0 ); =20
+
+ /* Sanity check */
+ if ( rows < 2 )
+ {
+ dmesg_print_syntax ();
+ return -EINVAL;
+ }
+ =20
+ break;
+ case 'c':
+ /* Set number of cols per row */
+ cols =3D strtoul ( optarg, NULL, 10 );
+
+ /* Sanity check */
+ if ( cols < 1 )
+ {
+ dmesg_print_syntax ();
+ return -EINVAL;
+ }
+
+ break;
+ case 'n':
+ /* Do not page output, just dump it all to console */
+
+ /* Ensure the buffer is not locked */
+ if ( dmesg_buffer.locked )
+ return -EADDRINUSE;
+ =20
+ /* Lock buffer and dump contents to console */
+ dmesg_buffer.locked =3D TRUE;
+ printf ( "%s", dmesg_buffer.buffer );
+ dmesg_buffer.locked =3D FALSE;
+
+ return PXENV_STATUS_SUCCESS;
+ case 't':
+ /* Send debug output to remote host via TCP */
+ port =3D strchr ( optarg, ':' );
+
+ if ( !port || !*(port+1) )
+ {
+ printf ( "Error: No port specified.\n" );
+ dmesg_print_syntax ();
+ return -EINVAL;
+ }
+ *(port++) =3D '\0';
+ =20
+ return dmesg_tcp (optarg, port);
+ case 'h':
+ /* Display help text */
+ default:
+ /* Unrecognised/invalid option */
+ dmesg_print_syntax ();
+
+ return -EINVAL;
+ }
+ }
+
+ return (page_dmesg (rows,cols));
+}
+
+/** Dmesg command */
+struct command time_command __command =3D {
+ .name =3D "dmesg",
+ .exec =3D dmesg_exec,
+};
+
diff --git a/src/include/gpxe/dmesg.h b/src/include/gpxe/dmesg.h
new file mode 100644
index 0000000..ae83d75
--- /dev/null
+++ b/src/include/gpxe/dmesg.h
@@ -0,0 +1,57 @@
+#ifndef _GPXE_DMESG_H
+#define _GPXE_DMESG_H
+
+/*
+ * Copyright (C) 2010 Matthew Lowe <mlowe at shaw.ca>.
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Dmesg driver functions
+ *
+ */
+
+/* Include user memory pointer type */
+#include <gpxe/umalloc.h>
+
+
+
+/* Container structure that describes console memory buffer */
+struct dmesg_buffer {
+ userptr_t user_buffer;
+
+ /* Physical buffer locations */
+ char *buffer;
+ char *pos;
+ =20
+ unsigned int size;
+
+ /* Basic access control */
+ int locked;
+};
+
+/* Console interface prototypes */
+extern void dmesg_putc ( int ch );
+extern int dmesg_getc ( void );
+extern int dmesg_ischar ( void );
+
+
+#endif /* _GPXE_DMESG_H */
diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h
index a17da90..f0e6afe 100644
--- a/src/include/gpxe/errfile.h
+++ b/src/include/gpxe/errfile.h
@@ -55,6 +55,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_bitmap ( ERRFILE_CORE | 0x000f0000 )
#define ERRFILE_base64 ( ERRFILE_CORE | 0x00100000 )
#define ERRFILE_base16 ( ERRFILE_CORE | 0x00110000 )
+#define ERRFILE_dmesg ( ERRFILE_CORE | 0x00120000 )
=20
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
@@ -210,6 +211,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_login_ui ( ERRFILE_OTHER | 0x00170000 )
#define ERRFILE_ib_srpboot ( ERRFILE_OTHER | 0x00180000 )
#define ERRFILE_iwmgmt ( ERRFILE_OTHER | 0x00190000 )
+#define ERRFILE_dmesg_cmd ( ERRFILE_OTHER | 0x001A0000 )
=20
/** @} */
=20
--=20
1.7.1
More information about the gPXE
mailing list