/* $Id: VBoxDebugLib.c $ */ /** @file * VBoxDebugLib.c - Debug logging and assertions support routines using DevEFI. */ /* * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include #include #include "VBoxDebugLib.h" #include #include #include #include #include "DevEFI.h" #if 0 static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *g_DevPath2Txt; #endif VOID EFIAPI DebugPrint(IN UINTN ErrorLevel, IN CONST CHAR8 *Format, ...) { CHAR8 szBuf[256]; VA_LIST va; UINTN cch; RTCCUINTREG SavedFlags; /* No pool noise, please. */ if (ErrorLevel == DEBUG_POOL) return; VA_START(va, Format); cch = AsciiVSPrint(szBuf, sizeof(szBuf), Format, va); VA_END(va); /* make sure it's terminated and doesn't end with a newline */ if (cch >= sizeof(szBuf)) cch = sizeof(szBuf) - 1; while (cch > 0 && (szBuf[cch - 1] == '\n' || szBuf[cch - 1] == '\r')) cch--; szBuf[cch] = '\0'; /* Output the log string. */ SavedFlags = ASMIntDisableFlags(); VBoxPrintString("dbg/"); VBoxPrintHex(ErrorLevel, sizeof(ErrorLevel)); VBoxPrintChar(' '); VBoxPrintString(szBuf); VBoxPrintChar('\n'); ASMSetFlags(SavedFlags); } /** * Our own log worker function, avoid the dbg/00000xxx prefix and makes it clear * which log statements we added.. * * @param pszFormat Format string. EFI style! * @param ... Argument referneced in the format string. */ VOID EFIAPI VBoxLogWorker(const char *pszFormat, ...) { CHAR8 szBuf[384]; VA_LIST va; RTCCUINTREG SavedFlags; /* Format it. */ VA_START(va, pszFormat); AsciiVSPrint(szBuf, sizeof(szBuf), pszFormat, va); VA_END(va); szBuf[sizeof(szBuf) - 1] = '\0'; /* Output the log string. */ SavedFlags = ASMIntDisableFlags(); VBoxPrintString(szBuf); VBoxPrintChar('\n'); ASMSetFlags(SavedFlags); } /** * Adds a character to the panic message. * * @param ch The ASCII char to add. */ static void VBoxPanicMsgChar(int ch) { ASMOutU16(EFI_PANIC_PORT, EFI_PANIC_CMD_MSG_FROM_CHAR(ch)); } /** * Adds a string to the panic message. * * @param pszString The string to add. */ static void VBoxPanicMsgString(const char *pszString) { char ch; while ((ch = *pszString++) != '\0') VBoxPanicMsgChar(ch); } /** * Adds a unsigned decimal number to the panic message. * * @param uValue The value. */ static void VBoxPanicMsgDecimalU32(uint32_t uValue) { char szTmp[32]; unsigned off = sizeof(szTmp) - 1; szTmp[off] = '\0'; do { char chDigit = uValue % 10; uValue /= 10; szTmp[--off] = chDigit + '0'; } while (uValue != 0 && off > 0); VBoxPanicMsgString(&szTmp[off]); } VOID EFIAPI DebugAssert(IN CONST CHAR8 *FileName, IN UINTN LineNumber, IN CONST CHAR8 *Description) { RTCCUINTREG SavedFlags = ASMIntDisableFlags(); ASMOutU8(EFI_PANIC_PORT, EFI_PANIC_CMD_START_MSG); VBoxPanicMsgString("EFI Assertion failed!" "\nFile: "); VBoxPanicMsgString(FileName ? FileName : ""); VBoxPanicMsgString("\nLine: "); VBoxPanicMsgDecimalU32((uint32_t)LineNumber); VBoxPanicMsgString("\nEDescription: "); VBoxPanicMsgString(Description ? Description : ""); ASMOutU8(EFI_PANIC_PORT, EFI_PANIC_CMD_END_MSG); ASMSetFlags(SavedFlags); } CHAR16 *VBoxDebugDevicePath2Str(IN EFI_DEVICE_PATH_PROTOCOL *pDevicePath) { #if 0 EFI_STATUS rc; if (!g_DevPath2Txt) { rc = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&g_DevPath2Txt); if (EFI_ERROR(rc)) { DEBUG((DEBUG_INFO, "gEfiDevicePathToTextProtocolGuid:%g isn't instantied\n", gEfiDevicePathToTextProtocolGuid)); return NULL; } } return g_DevPath2Txt->ConvertDevicePathToText(pDevicePath, TRUE, FALSE); #else return NULL; #endif } CHAR16 *VBoxDebugHandleDevicePath2Str(IN EFI_HANDLE hHandle) { #if 0 EFI_STATUS rc; EFI_DEVICE_PATH_PROTOCOL *pDevicePath = NULL; CHAR16 *psz16TxtDevicePath; rc = gBS->OpenProtocol(hHandle, &gEfiDevicePathProtocolGuid, (VOID **)pDevicePath, NULL, hHandle, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); if (EFI_ERROR(rc)) { DEBUG((DEBUG_INFO, "%a:%d failed(%r) to open Device Path Protocol for Handle %p\n", __FUNCTION__, __LINE__, rc, hHandle)); return NULL; } psz16TxtDevicePath = VBoxDebugHandleDevicePath2Str(pDevicePath); return psz16TxtDevicePath; #else return NULL; #endif } CHAR16 *VBoxDebugPrintDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *pDevicePath) { #if 0 EFI_STATUS rc; if (!g_DevPath2Txt) { rc = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&g_DevPath2Txt); if (EFI_ERROR(rc)) { DEBUG((DEBUG_INFO, "gEfiDevicePathToTextProtocolGuid:%g isn't instantied\n", gEfiDevicePathToTextProtocolGuid)); return NULL; } } return g_DevPath2Txt->ConvertDevicePathToText(pDevicePath, TRUE, FALSE); #else return NULL; #endif } VOID * EFIAPI DebugClearMemory(OUT VOID *Buffer, IN UINTN Length) { return Buffer; } BOOLEAN EFIAPI DebugAssertEnabled(VOID) { return TRUE; } BOOLEAN EFIAPI DebugPrintEnabled(VOID) { /** @todo some PCD for this so we can disable it in release builds. */ return TRUE; } BOOLEAN EFIAPI DebugCodeEnabled(VOID) { /** @todo ditto */ return TRUE; } BOOLEAN EFIAPI DebugClearMemoryEnabled(VOID) { return FALSE; }