/
githubmirror
/
ipxe
Обзор
Документация
Войти
/
githubmirror
/
ipxe
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/interface/efi/efi_disklog.c
301 строка
8 KB
Michael Brown
[efi] Add disk log console support
07 апр 2026, 20:42
07 апр 2026, 20:42
0788733
Код
Авторство
О чём код?
/* * 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/console.h> #include <ipxe/disklog.h> #include <ipxe/init.h> #include <ipxe/umalloc.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/BlockIo.h> #include <ipxe/efi/Protocol/PartitionInfo.h> #include <config/console.h> /** @file * * EFI disk log console * */ /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_DISKLOG ) && CONSOLE_EXPLICIT ( CONSOLE_DISKLOG ) ) #undef CONSOLE_DISKLOG #define CONSOLE_DISKLOG ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif /** EFI disk log console device handle */ static EFI_HANDLE efi_disklog_handle; /** EFI disk log console block I/O protocol */ static EFI_BLOCK_IO_PROTOCOL *efi_disklog_block; /** EFI disk log console media ID */ static UINT32 efi_disklog_media_id; /** EFI disk log console */ static struct disklog efi_disklog; struct console_driver efi_disklog_console __console_driver; /** * Write current logical block * * @ret rc Return status code */ static int efi_disklog_write ( void ) { EFI_BLOCK_IO_PROTOCOL *block = efi_disklog_block; struct disklog *disklog = &efi_disklog; EFI_STATUS efirc; int rc; /* Write disk block */ if ( ( efirc = block->WriteBlocks ( block, efi_disklog_media_id, disklog->lba, disklog->blksize, disklog->buffer ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( disklog, "EFIDISKLOG %s could not write LBA %#llx: " "%s\n", efi_handle_name ( efi_disklog_handle ), ( ( unsigned long long ) disklog->lba ), strerror ( rc ) ); return rc; } return 0; } /** EFI disk log console operations */ static struct disklog_operations efi_disklog_op = { .write = efi_disklog_write, }; /** * Write character to console * * @v character Character */ static void efi_disklog_putchar ( int character ) { /* Write character */ disklog_putchar ( &efi_disklog, character ); } /** * Open EFI disk log partition * * @v handle Block device handle * @ret rc Return status code */ static int efi_disklog_open ( EFI_HANDLE handle ) { struct disklog *disklog = &efi_disklog; EFI_BLOCK_IO_PROTOCOL *block; EFI_BLOCK_IO_MEDIA *media; EFI_PARTITION_INFO_PROTOCOL *part; void *buffer; EFI_STATUS efirc; int rc; /* Record handle */ efi_disklog_handle = handle; /* Open block I/O protocol for ephemeral usage */ if ( ( rc = efi_open ( handle, &efi_block_io_protocol_guid, &block ) ) != 0 ) { DBGC ( disklog, "EFIDISKLOG %s could not open: %s\n", efi_handle_name ( handle ), strerror ( rc ) ); goto err_open; } media = block->Media; efi_disklog_block = block; efi_disklog_media_id = media->MediaId; /* Check this is a partition */ if ( ! media->LogicalPartition ) { DBGC2 ( disklog, "EFIDISKLOG %s is not a partition\n", efi_handle_name ( handle ) ); rc = -ENOTTY; goto err_not_partition; } /* Check partition type (if exposed by the platform) */ if ( ( rc = efi_open ( handle, &efi_partition_info_protocol_guid, &part ) ) == 0 ) { if ( ( part->Type != PARTITION_TYPE_MBR ) || ( part->Info.Mbr.OSIndicator != DISKLOG_PARTITION_TYPE )){ DBGC ( disklog, "EFIDISKLOG %s is not a log " "partition\n", efi_handle_name ( handle ) ); rc = -ENOTTY; goto err_not_log; } } else { DBGC2 ( disklog, "EFIDISKLOG %s has no partition info\n", efi_handle_name ( handle ) ); /* Continue anyway */ } /* Allocate buffer */ buffer = umalloc ( media->BlockSize ); if ( ! buffer ) { rc = -ENOMEM; goto err_alloc; } /* Read partition signature */ if ( ( efirc = block->ReadBlocks ( block, efi_disklog_media_id, 0, media->BlockSize, buffer ) ) != 0 ){ rc = -EEFI ( efirc ); DBGC ( disklog, "EFIDISKLOG %s could not read block 0: %s\n", efi_handle_name ( handle ), strerror ( rc ) ); goto err_read; } /* Initialise disk log console */ disklog_init ( disklog, &efi_disklog_op, &efi_disklog_console, buffer, media->BlockSize, 0, media->LastBlock ); /* Open disk log console */ if ( ( rc = disklog_open ( disklog ) ) != 0 ) { DBGC ( disklog, "EFIDISKLOG %s could not initialise log: " "%s\n", efi_handle_name ( handle ), strerror ( rc ) ); goto err_init; } /* Reopen handle for long-term use */ if ( ( rc = efi_open_by_driver ( handle, &efi_block_io_protocol_guid, &block ) ) != 0 ) { DBGC ( disklog, "EFIDISKLOG %s could not reopen: %s\n", efi_handle_name ( handle ), strerror ( rc ) ); goto err_reopen; } if ( block != efi_disklog_block ) { DBGC ( disklog, "EFIDISKLOG %s changed during reopening\n", efi_handle_name ( handle ) ); rc = -EPIPE; goto err_reopen_mismatch; } DBGC ( disklog, "EFIDISKLOG using %s\n", efi_handle_name ( handle ) ); DBGC2 ( disklog, "EFIDISKLOG has %zd-byte LBA [%#x,%#llx]\n", disklog->blksize, 0, ( ( unsigned long long ) disklog->max_lba ) ); return 0; err_reopen_mismatch: efi_close_by_driver ( handle, &efi_block_io_protocol_guid ); err_reopen: err_init: err_read: ufree ( buffer ); err_alloc: err_not_log: err_not_partition: efi_disklog_block = NULL; err_open: efi_disklog_handle = NULL; return rc; } /** * Initialise EFI disk log console * */ static void efi_disklog_init ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_GUID *protocol = &efi_block_io_protocol_guid; EFI_HANDLE *handles; UINTN count; unsigned int i; EFI_STATUS efirc; int rc; /* Locate all block I/O protocol handles */ if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, protocol, NULL, &count, &handles ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( &efi_disklog, "EFIDISKLOG could not locate block I/O: " "%s\n", strerror ( rc ) ); goto err_locate; } /* Try each handle in turn */ for ( i = 0 ; i < count ; i++ ) { if ( ( rc = efi_disklog_open ( handles[i] ) ) == 0 ) break; } bs->FreePool ( handles ); err_locate: return; } /** * EFI disk log console initialisation function */ struct init_fn efi_disklog_init_fn __init_fn ( INIT_CONSOLE ) = { .name = "disklog", .initialise = efi_disklog_init, }; /** * Shut down EFI disk log console * * @v booting System is shutting down for OS boot */ static void efi_disklog_shutdown ( int booting __unused ) { struct disklog *disklog = &efi_disklog; /* Do nothing if we have no EFI disk log console */ if ( ! efi_disklog_handle ) return; /* Close EFI disk log console */ DBGC ( disklog, "EFIDISKLOG %s closed\n", efi_handle_name ( efi_disklog_handle ) ); efi_close_by_driver ( efi_disklog_handle, &efi_block_io_protocol_guid ); ufree ( disklog->buffer ); disklog->buffer = NULL; efi_disklog_handle = NULL; efi_disklog_block = NULL; } /** EFI disk log console shutdown function */ struct startup_fn efi_disklog_startup_fn __startup_fn ( STARTUP_EARLY ) = { .name = "disklog", .shutdown = efi_disklog_shutdown, }; /** EFI disk log console driver */ struct console_driver efi_disklog_console __console_driver = { .putchar = efi_disklog_putchar, .disabled = CONSOLE_DISABLED, .usage = CONSOLE_DISKLOG, }; /* Request a log partition from genfsimg */ IPXE_NOTE ( DISKLOG );