]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[disklog] Generalise disk log console mechanism
authorMichael Brown <mcb30@ipxe.org>
Tue, 7 Apr 2026 12:22:10 +0000 (13:22 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 7 Apr 2026 17:42:30 +0000 (18:42 +0100)
Split out the generic portions of the INT13 disk log console support
to a separate file that can be shared between BIOS and UEFI platforms.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/x86/interface/pcbios/int13con.c
src/arch/x86/prefix/usbdisk.S
src/core/disklog.c [new file with mode: 0644]
src/include/ipxe/disklog.h [new file with mode: 0644]
src/include/ipxe/errfile.h

index b073ca0e798dce321d680bb8ad176705e60879f0..0cd2b030390c59b0272afac0e81b5bd9919a5ca3 100644 (file)
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <string.h>
 #include <errno.h>
 #include <ipxe/console.h>
+#include <ipxe/disklog.h>
 #include <ipxe/init.h>
 #include <realmode.h>
 #include <int13.h>
@@ -53,21 +54,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 /** Disk drive number */
 #define INT13CON_DRIVE 0x80
 
-/** Log partition type */
-#define INT13CON_PARTITION_TYPE 0xe0
-
-/** Maximum number of outstanding unwritten characters */
-#define INT13CON_MAX_UNWRITTEN 64
-
-/** Log partition header */
-struct int13con_header {
-       /** Magic signature */
-       char magic[10];
-} __attribute__ (( packed ));
-
-/** Log partition magic signature */
-#define INT13CON_MAGIC "iPXE LOG\n\n"
-
 /** Original INT13 vector */
 static struct segoff __bss16 ( int13con_vector );
 #define int13con_vector __use_data16 ( int13con_vector )
@@ -80,17 +66,8 @@ static uint8_t __bss16_array ( int13con_buffer, [INT13_BLKSIZE] );
 static struct int13_disk_address __bss16 ( int13con_address );
 #define int13con_address __use_data16 ( int13con_address )
 
-/** Current LBA */
-static uint64_t int13con_lba;
-
-/** Maximum LBA */
-static uint64_t int13con_max_lba;
-
-/** Current offset within sector */
-static size_t int13con_offset;
-
-/** Number of unwritten characters */
-static size_t int13con_unwritten;
+/** Disk log */
+static struct disklog int13con_disklog;
 
 struct console_driver int13con __console_driver;
 
@@ -131,56 +108,30 @@ static int int13con_rw ( unsigned int op, uint64_t lba ) {
 }
 
 /**
- * Write character to console
+ * Write current logical block
  *
- * @v character                Character
+ * @ret rc             Return status code
  */
-static void int13con_putchar ( int character ) {
-       static int busy;
-       int rc;
-
-       /* Ignore if we are already mid-logging */
-       if ( busy )
-               return;
-       busy = 1;
-
-       /* Write character to buffer */
-       int13con_buffer[int13con_offset++] = character;
-       int13con_unwritten++;
-
-       /* Write sector to disk, if applicable */
-       if ( ( int13con_offset == INT13_BLKSIZE ) ||
-            ( int13con_unwritten == INT13CON_MAX_UNWRITTEN ) ||
-            ( character == '\n' ) ) {
-
-               /* Write sector to disk */
-               if ( ( rc = int13con_rw ( INT13_EXTENDED_WRITE,
-                                         int13con_lba ) ) != 0 ) {
-                       DBG ( "INT13CON could not write log\n" );
-                       /* Ignore and continue; there's nothing we can do */
-               }
+static int int13con_write ( void ) {
 
-               /* Reset count of unwritten characters */
-               int13con_unwritten = 0;
-       }
-
-       /* Move to next sector, if applicable */
-       if ( int13con_offset == INT13_BLKSIZE ) {
-
-               /* Disable console if we have run out of space */
-               if ( int13con_lba >= int13con_max_lba )
-                       int13con.disabled = 1;
+       /* Write block */
+       return int13con_rw ( INT13_EXTENDED_WRITE, int13con_disklog.lba );
+}
 
-               /* Clear log buffer */
-               memset ( int13con_buffer, 0, sizeof ( int13con_buffer ) );
-               int13con_offset = 0;
+/** INT13 disk log operations */
+static struct disklog_operations int13con_op = {
+       .write = int13con_write,
+};
 
-               /* Move to next sector */
-               int13con_lba++;
-       }
+/**
+ * Write character to console
+ *
+ * @v character                Character
+ */
+static void int13con_putchar ( int character ) {
 
-       /* Clear busy flag */
-       busy = 0;
+       /* Write character */
+       disklog_putchar ( &int13con_disklog, character );
 }
 
 /**
@@ -191,8 +142,6 @@ static void int13con_putchar ( int character ) {
 static int int13con_find ( void ) {
        struct master_boot_record *mbr =
                ( ( struct master_boot_record * ) int13con_buffer );
-       struct int13con_header *hdr =
-               ( ( struct int13con_header * ) int13con_buffer );
        struct partition_table_entry part[4];
        unsigned int i;
        int rc;
@@ -215,7 +164,7 @@ static int int13con_find ( void ) {
        for ( i = 0 ; i < ( sizeof ( part ) / sizeof ( part[0] ) ) ; i++ ) {
 
                /* Skip partitions of the wrong type */
-               if ( part[i].type != INT13CON_PARTITION_TYPE )
+               if ( part[i].type != DISKLOG_PARTITION_TYPE )
                        continue;
 
                /* Read partition header */
@@ -226,24 +175,22 @@ static int int13con_find ( void ) {
                        continue;
                }
 
-               /* Check partition header */
-               if ( memcmp ( hdr->magic, INT13CON_MAGIC,
-                             sizeof ( hdr->magic ) ) != 0 ) {
-                       DBG ( "INT13CON partition %d bad magic\n", ( i + 1 ) );
-                       DBG2_HDA ( 0, hdr, sizeof ( *hdr ) );
+               /* Initialise disk log console */
+               disklog_init ( &int13con_disklog, &int13con_op, &int13con,
+                              int13con_buffer, INT13_BLKSIZE, part[i].start,
+                              ( part[i].start + part[i].length - 1 ) );
+
+               /* Open disk log console */
+               if ( ( rc = disklog_open ( &int13con_disklog ) ) != 0 ) {
+                       DBG ( "INT13CON partition %d could not initialise: "
+                             "%s\n", ( i + 1 ), strerror ( rc ) );
                        continue;
                }
 
                /* Found log partition */
-               DBG ( "INT13CON partition %d at [%08x,%08x)\n", ( i + 1 ),
-                     part[i].start, ( part[i].start + part[i].length ) );
-               int13con_lba = part[i].start;
-               int13con_max_lba = ( part[i].start + part[i].length - 1 );
-
-               /* Initialise log buffer */
-               memset ( &int13con_buffer[ sizeof ( *hdr ) ], 0,
-                        ( sizeof ( int13con_buffer ) - sizeof ( *hdr ) ) );
-               int13con_offset = sizeof ( hdr->magic );
+               DBG ( "INT13CON partition %d at [%08llx,%08llx)\n", ( i + 1 ),
+                     ( ( unsigned long long ) int13con_disklog.lba ),
+                     ( ( unsigned long long ) int13con_disklog.max_lba ) );
 
                return 0;
        }
index ab4a011a308cab22130903f8ef04f33735355eb7..389ef86bd399189472c9356b99f44249f1df6008 100644 (file)
@@ -1,5 +1,6 @@
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
 
+#include <ipxe/disklog.h>
 #include <config/console.h>
 
        .section ".note.GNU-stack", "", @progbits
@@ -61,7 +62,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
 
        /* Partition 3: log partition (for CONSOLE_INT13) */
        .if LOGPART
-       partition 0x00, 0xe0, LOGSTART, LOGCOUNT
+       partition 0x00, DISKLOG_PARTITION_TYPE, LOGSTART, LOGCOUNT
        .else
        .space 16
        .endif
@@ -76,7 +77,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
 /* Skip to start of log partition */
        .if LOGPART
        .org CYLADDR(LOGSTART)
-       .ascii "iPXE LOG\n\n"
+       .ascii DISKLOG_MAGIC
        .endif
 
 /* Skip to start of boot partition */
diff --git a/src/core/disklog.c b/src/core/disklog.c
new file mode 100644 (file)
index 0000000..bdcbf3a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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., 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 <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <ipxe/disklog.h>
+
+/** @file
+ *
+ * Disk log console
+ *
+ */
+
+/**
+ * Open disk log console
+ *
+ * @v disklog          Disk log
+ * @ret rc             Return status code
+ *
+ * The data buffer must already contain the initial logical block.
+ */
+int disklog_open ( struct disklog *disklog ) {
+       struct disklog_header *hdr =
+               ( ( struct disklog_header * ) disklog->buffer );
+
+       /* Sanity checks */
+       assert ( disklog->console != NULL );
+       assert ( disklog->buffer != NULL );
+       assert ( disklog->blksize > 0 );
+       assert ( ( disklog->blksize & ( disklog->blksize - 1 ) ) == 0 );
+       assert ( disklog->lba <= disklog->max_lba );
+       assert ( disklog->op != NULL );
+       assert ( disklog->op->write != NULL );
+
+       /* Check magic signature */
+       if ( ( disklog->blksize < sizeof ( *hdr ) ) ||
+            ( memcmp ( hdr->magic, DISKLOG_MAGIC,
+                       sizeof ( hdr->magic ) ) != 0 ) ) {
+               DBGC ( disklog, "DISKLOG has bad magic signature\n" );
+               return -EINVAL;
+       }
+
+       /* Initialise buffer */
+       disklog->offset = sizeof ( *hdr );
+       disklog->unwritten = 0;
+       memset ( ( disklog->buffer + sizeof ( *hdr ) ), 0,
+                ( disklog->blksize - sizeof ( *hdr ) ) );
+
+       /* Enable console */
+       disklog->console->disabled = 0;
+
+       return 0;
+}
+
+/**
+ * Write character to disk log console
+ *
+ * @v disklog          Disk log
+ * @v character                Character
+ */
+void disklog_putchar ( struct disklog *disklog, int character ) {
+       static int busy;
+       int rc;
+
+       /* Ignore if we are already mid-logging */
+       if ( busy )
+               return;
+       busy = 1;
+
+       /* Sanity checks */
+       assert ( disklog->offset < disklog->blksize );
+
+       /* Write character to buffer */
+       disklog->buffer[disklog->offset++] = character;
+       disklog->unwritten++;
+
+       /* Write sector to disk, if applicable */
+       if ( ( disklog->offset == disklog->blksize ) ||
+            ( disklog->unwritten == DISKLOG_MAX_UNWRITTEN ) ||
+            ( character == '\n' ) ) {
+
+               /* Write sector to disk */
+               if ( ( rc = disklog->op->write() ) != 0 ) {
+                       DBGC ( disklog, "DISKLOG could not write: %s\n",
+                              strerror ( rc ) );
+                       /* Ignore and continue; there's nothing we can do */
+               }
+
+               /* Reset count of unwritten characters */
+               disklog->unwritten = 0;
+       }
+
+       /* Move to next sector, if applicable */
+       if ( disklog->offset == disklog->blksize ) {
+
+               /* Disable console if we have run out of space */
+               if ( disklog->lba >= disklog->max_lba )
+                       disklog->console->disabled = 1;
+
+               /* Clear log buffer */
+               memset ( disklog->buffer, 0, disklog->blksize );
+               disklog->offset = 0;
+
+               /* Move to next sector */
+               disklog->lba++;
+       }
+
+       /* Clear busy flag */
+       busy = 0;
+}
diff --git a/src/include/ipxe/disklog.h b/src/include/ipxe/disklog.h
new file mode 100644 (file)
index 0000000..f7f56d2
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _IPXE_DISKLOG_H
+#define _IPXE_DISKLOG_H
+
+/** @file
+ *
+ * Disk log console
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
+
+#ifndef ASSEMBLY
+
+#include <stdint.h>
+#include <ipxe/console.h>
+
+/** Disk log partition header */
+struct disklog_header {
+       /** Magic signature */
+       char magic[10];
+} __attribute__ (( packed ));
+
+/** A disk log */
+struct disklog {
+       /** Console device */
+       struct console_driver *console;
+       /** Disk log operations */
+       struct disklog_operations *op;
+       /** Logical block data buffer */
+       uint8_t *buffer;
+       /** Logical block size */
+       size_t blksize;
+       /** Current logical block index */
+       uint64_t lba;
+       /** Maximum logical block index */
+       uint64_t max_lba;
+       /** Current offset within logical block */
+       unsigned int offset;
+       /** Current number of unwritten characters */
+       unsigned int unwritten;
+};
+
+/** Disk log operations */
+struct disklog_operations {
+       /**
+        * Write current logical block
+        *
+        * @ret rc              Return status code
+        */
+       int ( * write ) ( void );
+};
+
+/**
+ * Initialise disk log console
+ *
+ * @v disklog          Disk log
+ * @v op               Disk log operations
+ * @v console          Console device
+ * @v buffer           Data buffer
+ * @v blksize          Logical block size
+ * @v lba              Starting logical block index
+ * @v max_lba          Maximum logical block index
+ */
+static inline __attribute__ (( always_inline )) void
+disklog_init ( struct disklog *disklog, struct disklog_operations *op,
+              struct console_driver *console, void *buffer, size_t blksize,
+              uint64_t lba, uint64_t max_lba ) {
+
+       disklog->op = op;
+       disklog->console = console;
+       disklog->buffer = buffer;
+       disklog->blksize = blksize;
+       disklog->lba = lba;
+       disklog->max_lba = max_lba;
+}
+
+extern int disklog_open ( struct disklog *disklog );
+extern void disklog_putchar ( struct disklog *disklog, int character );
+
+#endif /* ASSEMBLY */
+
+/** Disk log partition type */
+#define DISKLOG_PARTITION_TYPE 0xe0
+
+/** Disk log partition magic signature */
+#define DISKLOG_MAGIC "iPXE LOG\n\n"
+
+/** Maximum number of outstanding unwritten characters */
+#define DISKLOG_MAX_UNWRITTEN 64
+
+#endif /* _IPXE_DISKLOG_H */
index 27c2bb97ce52fba36015a4cc14aabd576591e332..f452648ce3350b611916a4878bc38f1912e3d4f5 100644 (file)
@@ -90,6 +90,7 @@ FILE_SECBOOT ( PERMITTED );
 #define ERRFILE_efi_connect           ( ERRFILE_CORE | 0x00310000 )
 #define ERRFILE_gpio                  ( ERRFILE_CORE | 0x00320000 )
 #define ERRFILE_spcr                  ( ERRFILE_CORE | 0x00330000 )
+#define ERRFILE_disklog                       ( ERRFILE_CORE | 0x00340000 )
 
 #define ERRFILE_eisa                ( ERRFILE_DRIVER | 0x00000000 )
 #define ERRFILE_isa                 ( ERRFILE_DRIVER | 0x00010000 )