blob: bdcbf3a1c88990d7d969106f76e27b924d2a6d42 [file]
/*
* 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;
}