[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