mirror of
https://github.com/ipxe/ipxe.git
synced 2026-04-22 22:21:23 +02:00
[disklog] Generalise disk log console mechanism
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>
This commit is contained in:
parent
ec38e98d40
commit
480b6f021f
@ -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;
|
||||
|
||||
@ -130,57 +107,31 @@ static int int13con_rw ( unsigned int op, uint64_t lba ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write current logical block
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int int13con_write ( void ) {
|
||||
|
||||
/* Write block */
|
||||
return int13con_rw ( INT13_EXTENDED_WRITE, int13con_disklog.lba );
|
||||
}
|
||||
|
||||
/** INT13 disk log operations */
|
||||
static struct disklog_operations int13con_op = {
|
||||
.write = int13con_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* Write character to console
|
||||
*
|
||||
* @v character Character
|
||||
*/
|
||||
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 */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Clear log buffer */
|
||||
memset ( int13con_buffer, 0, sizeof ( int13con_buffer ) );
|
||||
int13con_offset = 0;
|
||||
|
||||
/* Move to next sector */
|
||||
int13con_lba++;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
134
src/core/disklog.c
Normal file
134
src/core/disklog.c
Normal file
@ -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;
|
||||
}
|
||||
92
src/include/ipxe/disklog.h
Normal file
92
src/include/ipxe/disklog.h
Normal file
@ -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 */
|
||||
@ -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 )
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user