MakeAlternativeSource.cpp revision 6ba75a0a0676b4aa33edc952fc79454d56f58f62
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * MakeAlternative - Generate an Alternative BIOS Source that requires less tools.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Copyright (C) 2012 Oracle Corporation
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This file is part of VirtualBox Open Source Edition (OSE), as
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * available from http://www.virtualbox.org. This file is free software;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * you can redistribute it and/or modify it under the terms of the GNU
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * General Public License (GPL) as published by the Free Software
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Foundation, in version 2 as it comes in the "COPYING" file of the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/*******************************************************************************
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk* Header Files *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk*******************************************************************************/
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/*******************************************************************************
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk* Structures and Typedefs *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk*******************************************************************************/
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * A BIOS segment.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenktypedef struct BIOSSEG
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** Pointer to a BIOS segment. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * A BIOS object file.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** A BIOS object file. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Pointer to a BIOS map parser handle.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenktypedef struct BIOSMAP
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /** The stream pointer. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /** The file name. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /** Set when EOF has been reached. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /** The current line number (0 based).*/
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /** The length of the current line. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /** The offset of the first non-white character on the line. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /** The line buffer. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** Pointer to a BIOS map parser handle. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/*******************************************************************************
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk* Global Variables *
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk*******************************************************************************/
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** The verbosity level.*/
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** Pointer to the BIOS image. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** The size of the BIOS image. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** Debug module for the map file. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** The number of BIOS segments found in the map file. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** Array of BIOS segments from the map file. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** List of BIOSOBJFILE. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** The output stream. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** The type of BIOS we're working on. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk/** The flat ROM base address. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic bool outputPrintfV(const char *pszFormat, va_list va)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int rc = RTStrmPrintfV(g_hStrmOutput, pszFormat, va);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return false;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return true;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic bool outputPrintf(const char *pszFormat, ...)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Opens the output file for writing.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE+msg.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param pszOutput Path to the output file.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic RTEXITCODE OpenOutputFile(const char *pszOutput)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int rc = RTStrmOpen(pszOutput, "w", &g_hStrmOutput);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open output file '%s': %Rrc", pszOutput, rc);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Displays a disassembly error and returns @c false.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @returns @c false.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param pszFormat The error format string.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @param ... Format argument.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return false;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Output the disassembly file header.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * @returns @c true on success,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkstatic bool disFileHeader(void)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk ";; @file\n"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "; Auto Generated source file. Do not edit.\n"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * List the header of each source file, up to and including the
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * copyright notice.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk RTListForEach(&g_ObjList, pObjFile, BIOSOBJFILE, Node)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk int rc = RTStrmOpen(pObjFile->pszSource, "r", &hStrm);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "; Source file: %Rbn\n"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk while ((rc = RTStrmGetLine(hStrm, szLine, sizeof(szLine))) == VINF_SUCCESS)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* Check if we're done. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk /* Strip comment suffix. */
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (cch >= 2 && psz[cch - 1] == '/' && psz[cch - 2] == '*')
psz++;
psz++;
if ( !fSeenCopyright
fSeenCopyright = true;
) && fRc;
return fRc;
while (cb > 0)
pb++;
cb--;
return cb == 0;
pb++;
cb--;
while (cb-- > 0)
bool fRc;
else if (!cbOnLine)
cbOnLine++;
if (!fRc)
pb++;
while (cb > 0)
bool fRc;
else if (!cbOnLine)
if (!fRc)
pu16++;
while (cb > 0)
bool fRc;
else if (!cbOnLine)
if (!fRc)
pu32++;
while (cb > 0)
cchOnLine = 0;
if ( !cchOnLine
cchPrintable++;
bool fRc = true;
if (cchPrintable)
if (cchOnLine)
if (cchOnLine)
pb++;
cb--;
if (!fRc)
while (cb > 0)
cchOnLine = 0;
if ( !cchOnLine
cchPrintable++;
bool fRc = true;
if (cchPrintable)
if (cchOnLine)
if (cchOnLine)
pb++;
cb--;
if (!fRc)
if (g_cVerbose > 0)
static void disGetNextSymbolWorker(uint32_t uFlatAddr, uint32_t cbMax, uint32_t *poff, PRTDBGSYMBOL pSym)
int rc = RTDbgModSymbolByAddr(g_hMapMod, RTDBGSEGIDX_RVA, uFlatAddr, RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL, &off, pSym);
if (off <= 0)
while (cb > 0)
if (off > 0)
off = 0;
if (!cb)
bool fRc;
if (off == 0)
fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
if (!fRc)
cb = 0;
if (!fRc)
while (cb > 0)
if (off > 0)
off = 0;
if (!cb)
bool fRc;
if (off == 0)
fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
if (!fRc)
//else if (Sym.cb == 4 && disIsFarBiosAddr(uFlatAddr))
cb = 0;
if (!fRc)
switch (g_enmBiosType)
case kBiosType_System:
case kBiosType_Vga:
static size_t disHandleYasmDifferences(PDISCPUSTATE pCpuState, uint32_t uFlatAddr, uint32_t cbInstr,
fDifferent = true;
fDifferent = true;
if (fDifferent)
return cchUsed;
static DECLCALLBACK(int) disReadOpcodeBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
cbToRead = 0;
return VINF_SUCCESS;
while (cb > 0)
unsigned cbInstr;
cb--;
pb++;
uFlatAddr++;
while (cb > 0)
if (off > 0)
off = 0;
if (!cb)
bool fRc;
if (off == 0)
fRc = outputPrintf("%s: %*s; %#x LB %#x\n", Sym.szName, cchName < 41 - 2 ? cchName - 41 - 2 : 0, "", uFlatAddr, Sym.cb);
if (!fRc)
cb = 0;
if (!fRc)
if (!disFileHeader())
return RTEXITCODE_FAILURE;
bool fRc = true;
if (!fRc)
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Overlapping segments: %u and %u; uFlatAddr=%#x\n", iSeg - 1, iSeg, uFlatAddr);
if (!fRc)
return RTEXITCODE_FAILURE;
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Last segment spills beyond 1MB; uFlatAddr=%#x\n", uFlatAddr);
if (!fRc)
return RTEXITCODE_FAILURE;
return RTEXITCODE_SUCCESS;
return RTEXITCODE_SUCCESS;
off++;
if (pcch)
return psz;
return NULL;
if (pcch)
return NULL;
psz++;
psz++;
static bool mapSkipThruColumnHeadings(PBIOSMAP pMap, const char *pszSectionNm, uint32_t cColumns, ...)
if (!psz)
if (!psz)
if (!psz)
if (!psz)
RTMsgError("%s:%d: Expected column '%s' found '%s'", pMap->pszMapFile, pMap->iLine, pszColumn, psz);
psz++;
if (!psz)
if (!psz)
if (*psz)
g_cSegs++;
psz++;
if (!*psz)
static bool mapSortAndAddSegments(void)
if (g_cVerbose > 0)
int rc = RTDbgModSegmentAdd(g_hMapMod, g_aSegs[i].uFlatAddr, g_aSegs[i].cb, g_aSegs[i].szName, 0 /*fFlags*/, &idx);
offObj++;
char ch;
offSrc++;
offSrc++;
cchSrc++;
if (!pObjFile)
if (uFlatAddr != 0)
int rc = RTDbgModSymbolAdd(g_hMapMod, szName, RTDBGSEGIDX_RVA, uFlatAddr, 0 /*cb*/, 0 /*fFlags*/, NULL);
rc = RTDbgModSymbolAdd(g_hMapMod, szName, RTDBGSEGIDX_RVA, uFlatAddr - 1, 0 /*cb*/, 0 /*fFlags*/, NULL);
psz++;
if (*psz)
return RTEXITCODE_FAILURE;
return RTEXITCODE_FAILURE;
return RTEXITCODE_FAILURE;
return RTEXITCODE_FAILURE;
if (!mapSkipThruColumnHeadings(pMap, "Segments", 5, "Segment", "Class", "Group", "Address", "Size"))
return RTEXITCODE_FAILURE;
return RTEXITCODE_FAILURE;
if (!mapSortAndAddSegments())
return RTEXITCODE_FAILURE;
return RTEXITCODE_FAILURE;
return RTEXITCODE_FAILURE;
return RTEXITCODE_SUCCESS;
return rcExit;
void *pvImg;
switch (g_enmBiosType)
default: cbImgExpect = 0; break;
return RTMsgErrorExit(RTEXITCODE_FAILURE, "The BIOS image %u bytes intead of %u bytes", cbImg, cbImgExpect);
return RTEXITCODE_SUCCESS;
rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
switch (rc)
if (pszBiosImg)
if (pszBiosMap)
if (pszBiosSym)
if (pszOutput)
g_cVerbose++;
g_cVerbose = 0;
argv[0]);
return RTEXITCODE_SUCCESS;
return RTEXITCODE_SUCCESS;
if (!pszBiosImg)
if (!pszBiosMap)
if (!pszBiosSym)
return rcExit;