#!/usr/bin/env python | |
# | |
# | |
# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> | |
# This program and the accompanying materials | |
# are licensed and made available under the terms and conditions of the BSD License | |
# which accompanies this distribution. The full text of the license may be found at | |
# http://opensource.org/licenses/bsd-license.php | |
# | |
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
# | |
# Import Modules | |
# | |
import re, os, glob | |
from Common.XmlRoutines import * | |
#"ModuleType"=>(PackageGuid, headerFileName) List | |
HeaderFiles = {} | |
GuidList = [] | |
GuidMap = {} | |
HeaderFileContents = {} | |
gTest = {} | |
GuidMacro2CName = {} | |
GuidAliasList = [] | |
def collectIncludeFolder(pkgDirName, guidType, pkgName): | |
includeFolder = os.path.join(pkgDirName, "Include", guidType) | |
if os.path.exists(includeFolder) and os.path.isdir(includeFolder): | |
for headerFileName in os.listdir(includeFolder): | |
if headerFileName[-2:] == ".h": | |
headerFile = open(os.path.join(includeFolder, headerFileName)) | |
HeaderFileContents[(guidType, headerFileName, pkgName)] = headerFile.read() | |
headerFile.close() | |
GuidMacroReg = re.compile(r"\b(?!EFI_GUID\b)[A-Z0-9_]+_GUID\b") | |
GuidCNameReg = re.compile(r"\bg\w+Guid\b") | |
GuidAliasReg = re.compile(r"#define\s+([A-Z0-9_]+_GUID)\s+([A-Z0-9_]+_GUID)\b") | |
def collectPackageInfo(spdFileName): | |
pkgDirName = os.path.dirname(spdFileName) | |
spd = XmlParseFile(spdFileName) | |
pkgName = XmlElement(spd, "/PackageSurfaceArea/SpdHeader/PackageName") | |
pkgGuid = XmlElement(spd, "/PackageSurfaceArea/SpdHeader/GuidValue") | |
for IncludePkgHeader in XmlList(spd, "/PackageSurfaceArea/PackageHeaders/IncludePkgHeader"): | |
moduleType = XmlAttribute(IncludePkgHeader, "ModuleType") | |
headerFilePath = XmlElementData(IncludePkgHeader) | |
headerFilePath = re.sub("Include/", "", headerFilePath, 1) | |
headerTuple = HeaderFiles.get(moduleType, []) | |
headerTuple.append((pkgGuid, headerFilePath)) | |
HeaderFiles[moduleType] = headerTuple | |
guidTypes = ["Guid", "Protocol", "Ppi"] | |
for guidType in guidTypes: | |
for guidEntry in XmlList(spd, "/PackageSurfaceArea/" + guidType + "Declarations/Entry"): | |
guidCName = XmlElement(guidEntry, "Entry/C_Name") | |
GuidList.append(guidCName) | |
collectIncludeFolder(pkgDirName, guidType, pkgName) | |
for DecFile in glob.glob(os.path.join(pkgDirName, "*.dec")): | |
fileContents = open(DecFile).read() | |
for GuidCNameMatch in GuidCNameReg.finditer(fileContents): | |
GuidCName = GuidCNameMatch.group(0) | |
if GuidCName not in GuidList: | |
GuidList.append(GuidCName) | |
def AddGuidMacro2GuidCName(GuidMacros, GuidCNames): | |
for GuidMacro in GuidMacros: | |
GuessGuidCName = "g" + GuidMacro.lower().title().replace("_", "") | |
if GuessGuidCName in GuidCNames: | |
GuidMacro2CName[GuidMacro] = GuessGuidCName | |
elif len(GuidCNames) == 1: | |
GuidMacro2CName[GuidMacro] = GuidCNames[0] | |
else: | |
for GuidCName in GuidCNames: | |
if GuidCName.lower() == GuessGuidCName.lower(): | |
GuidMacro2CName[GuidMacro] = GuidCName | |
break | |
else: | |
pass | |
#print "No matching GuidMacro %s" % GuidMacro | |
def TranslateGuid(GuidMacroMatch): | |
GuidMacro = GuidMacroMatch.group(0) | |
return GuidMacro2CName.get(GuidMacro, GuidMacro) | |
DepexReg = re.compile(r"DEPENDENCY_START(.*?)DEPENDENCY_END", re.DOTALL) | |
def TranslateDpxSection(fileContents): | |
DepexMatch = DepexReg.search(fileContents) | |
if not DepexMatch: | |
return "", [] | |
fileContents = DepexMatch.group(1) | |
fileContents = re.sub(r"\s+", " ", fileContents).strip() | |
fileContents = GuidMacroReg.sub(TranslateGuid, fileContents) | |
return fileContents, GuidMacroReg.findall(fileContents) | |
def InitializeAutoGen(workspace, db): | |
for spdFile in XmlList(db, "/FrameworkDatabase/PackageList/Filename"): | |
spdFileName = XmlElementData(spdFile) | |
collectPackageInfo(os.path.join(workspace, spdFileName)) | |
BlockCommentReg = re.compile(r"/\*.*?\*/", re.DOTALL) | |
LineCommentReg = re.compile(r"//.*") | |
GuidReg = re.compile(r"\b(" + '|'.join(GuidList) + r")\b") | |
for headerFile in HeaderFileContents: | |
Contents = HeaderFileContents[headerFile] | |
Contents = BlockCommentReg.sub("", Contents) | |
Contents = LineCommentReg.sub("", Contents) | |
FoundGuids = GuidReg.findall(Contents) | |
for FoundGuid in FoundGuids: | |
GuidMap[FoundGuid] = "%s/%s" % (headerFile[0], headerFile[1]) | |
#print "%-40s %s/%s" % (FoundGuid, headerFile[0], headerFile[1]) | |
GuidMacros = GuidMacroReg.findall(Contents) | |
GuidCNames = GuidCNameReg.findall(Contents) | |
for GuidAliasMatch in GuidAliasReg.finditer(Contents): | |
Name1, Name2 = GuidAliasMatch.group(1), GuidAliasMatch.group(2) | |
GuidAliasList.append((Name1, Name2)) | |
AddGuidMacro2GuidCName(GuidMacros, GuidCNames) | |
def AddSystemIncludeStatement(moduleType, PackageList): | |
IncludeStatement = "\n" | |
headerList = HeaderFiles.get(moduleType, []) | |
for pkgGuid in PackageList: | |
for pkgTuple in headerList: | |
if pkgTuple[0] == pkgGuid: | |
IncludeStatement += "#include <%s>\n" % pkgTuple[1] | |
return IncludeStatement | |
def AddLibraryClassStatement(LibraryClassList): | |
IncludeStatement = "\n" | |
for LibraryClass in LibraryClassList: | |
IncludeStatement += "#include <Library/%s.h>\n" % LibraryClass | |
return IncludeStatement | |
def AddGuidStatement(GuidList): | |
IncludeStatement = "\n" | |
GuidIncludeSet = {} | |
for Guid in GuidList: | |
if Guid in GuidMap: | |
GuidIncludeSet[GuidMap[Guid]] = 1 | |
else: | |
print "GUID CName: %s cannot be found in any public header file" % Guid | |
for GuidInclude in GuidIncludeSet: | |
IncludeStatement += "#include <%s>\n" % GuidInclude | |
return IncludeStatement | |
DriverBindingMap = { | |
"gEfiDriverBindingProtocolGuid" : "EFI_DRIVER_BINDING_PROTOCOL", | |
"gEfiComponentNameProtocolGuid" : "EFI_COMPONENT_NAME_PROTOCOL", | |
"gEfiDriverConfigurationProtocolGuid" : "EFI_DRIVER_CONFIGURATION_PROTOCOL", | |
"gEfiDriverDiagnosticProtocolGuid" : "EFI_DRIVER_CONFIGURATION_PROTOCOL" | |
} | |
def AddDriverBindingProtocolStatement(AutoGenDriverModel): | |
InstallStatement = "\n" | |
DBindingHandle = "ImageHandle" | |
GlobalDeclaration = "\n" | |
for DriverModelItem in AutoGenDriverModel: | |
if DriverModelItem[1] == "NULL" and DriverModelItem[2] == "NULL" and DriverModelItem[3] == "NULL": | |
InstallStatement += " Status = EfiLibInstallDriverBinding (\n" | |
InstallStatement += " ImageHandle,\n" | |
InstallStatement += " SystemTable,\n" | |
InstallStatement += " %s,\n" % DriverModelItem[0] | |
InstallStatement += " %s\n" % DBindingHandle | |
InstallStatement += " );\n" | |
else: | |
InstallStatement += " Status = EfiLibInstallAllDriverProtocols (\n" | |
InstallStatement += " ImageHandle,\n" | |
InstallStatement += " SystemTable,\n" | |
InstallStatement += " %s,\n" % DriverModelItem[0] | |
InstallStatement += " %s,\n" % DBindingHandle | |
InstallStatement += " %s,\n" % DriverModelItem[1] | |
InstallStatement += " %s,\n" % DriverModelItem[2] | |
InstallStatement += " %s\n" % DriverModelItem[3] | |
InstallStatement += " );\n" | |
InstallStatement += " ASSERT_EFI_ERROR (Status);\n\n" | |
GlobalDeclaration += "extern EFI_DRIVER_BINDING_PROTOCOL %s;\n" % DriverModelItem[0][1:] | |
if (DriverModelItem[1] != "NULL"): | |
GlobalDeclaration += "extern EFI_COMPONENT_NAME_PROTOCOL %s;\n" % DriverModelItem[1][1:] | |
if (DriverModelItem[2] != "NULL"): | |
GlobalDeclaration += "extern EFI_DRIVER_CONFIGURATION_PROTOCOL %s;\n" % DriverModelItem[2][1:] | |
if (DriverModelItem[3] != "NULL"): | |
GlobalDeclaration += "extern EFI_DRIVER_CONFIGURATION_PROTOCOL %s;\n" % DriverModelItem[3][1:] | |
DBindingHandle = "NULL" | |
return (InstallStatement, "", "", GlobalDeclaration) | |
EventDeclarationTemplate = """ | |
// | |
// Declaration for callback Event. | |
// | |
VOID | |
EFIAPI | |
%s ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
); | |
""" | |
def AddBootServiceEventStatement(EventList): | |
FinalEvent = "" | |
if len(EventList) > 1: | |
print "Current prototype does not support multi boot service event" | |
else: | |
FinalEvent = EventList[0] | |
CreateStatement = "\n" | |
CreateStatement += " Status = gBS->CreateEvent (\n" | |
CreateStatement += " EVT_SIGNAL_EXIT_BOOT_SERVICES,\n" | |
CreateStatement += " EFI_TPL_NOTIFY,\n" | |
CreateStatement += " " + FinalEvent + ",\n" | |
CreateStatement += " NULL,\n" | |
CreateStatement += " &mExitBootServicesEvent\n" | |
CreateStatement += " );\n" | |
CreateStatement += " ASSERT_EFI_ERROR (Status);\n" | |
GlobalDefinition = "\n" | |
GlobalDefinition += "STATIC EFI_EVENT mExitBootServicesEvent = NULL;\n" | |
GlobalDeclaration = EventDeclarationTemplate % FinalEvent | |
DestroyStatement = "\n" | |
DestroyStatement += " Status = gBS->CloseEvent (mExitBootServicesEvent);\n" | |
DestroyStatement += " ASSERT_EFI_ERROR (Status);\n" | |
return (CreateStatement, "", GlobalDefinition, GlobalDeclaration) | |
def AddVirtualAddressEventStatement(EventList): | |
FinalEvent = "" | |
if len(EventList) > 1: | |
print "Current prototype does not support multi virtual address change event" | |
else: | |
FinalEvent = EventList[0] | |
CreateStatement = "\n" | |
CreateStatement += " Status = gBS->CreateEvent (\n" | |
CreateStatement += " EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\n" | |
CreateStatement += " TPL_NOTIFY,\n" | |
CreateStatement += " " + FinalEvent + ",\n" | |
CreateStatement += " NULL,\n" | |
CreateStatement += " &mVirtualAddressChangedEvent\n" | |
CreateStatement += " );\n" | |
CreateStatement += " ASSERT_EFI_ERROR (Status);\n" | |
GlobalDefinition = "\n" | |
GlobalDefinition += "STATIC EFI_EVENT mVirtualAddressChangedEvent = NULL;\n" | |
GlobalDeclaration = EventDeclarationTemplate % FinalEvent | |
DestroyStatement = "\n" | |
DestroyStatement += " Status = gBS->CloseEvent (mVirtualAddressChangedEvent);\n" | |
DestroyStatement += " ASSERT_EFI_ERROR (Status);\n" | |
return (CreateStatement, "", GlobalDefinition, GlobalDeclaration) | |
EntryPointDeclarationTemplate = """ | |
// | |
// Declaration for original Entry Point. | |
// | |
EFI_STATUS | |
EFIAPI | |
%s ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
); | |
""" | |
EntryPointHeader = r""" | |
/** | |
The user Entry Point for module %s. The user code starts with this function. | |
@param[in] ImageHandle The firmware allocated handle for the EFI image. | |
@param[in] SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The entry point is executed successfully. | |
@retval other Some error occurs when executing this entry point. | |
**/ | |
""" | |
def AddNewEntryPointContentsStatement (moduleName, EntryPoint, InstallStatement = ""): | |
if EntryPoint != "Initialize%s" % moduleName: | |
NewEntryPoint = "Initialize%s" % moduleName | |
else: | |
NewEntryPoint = "NewInitialize%s" % moduleName | |
EntryPointContents = EntryPointHeader % moduleName | |
EntryPointContents += "EFI_STATUS\n" | |
EntryPointContents += "EFIAPI\n" | |
EntryPointContents += NewEntryPoint + "(\n" | |
EntryPointContents += " IN EFI_HANDLE ImageHandle,\n" | |
EntryPointContents += " IN EFI_SYSTEM_TABLE *SystemTable\n" | |
EntryPointContents += " )\n" | |
EntryPointContents += "{\n" | |
EntryPointContents += " EFI_STATUS Status;\n" | |
EntryPointContents += InstallStatement + "\n" | |
GlobalDeclaration = "" | |
if EntryPoint != "": | |
EntryPointContents += " //\n // Call the original Entry Point\n //\n" | |
EntryPointContents += " Status = %s (ImageHandle, SystemTable);\n\n" % EntryPoint | |
GlobalDeclaration += EntryPointDeclarationTemplate % EntryPoint | |
EntryPointContents += " return Status;\n" | |
EntryPointContents += "}\n" | |
return (NewEntryPoint, EntryPointContents, GlobalDeclaration) | |
reFileHeader = re.compile(r"^\s*/\*.*?\*/\s*", re.DOTALL) | |
reNext = re.compile(r"#ifndef\s*(\w+)\s*#define\s*\1\s*") | |
def AddCommonInclusionStatement(fileContents, includeStatement): | |
if includeStatement in fileContents: | |
return fileContents | |
insertPos = 0 | |
matchFileHeader = reFileHeader.search(fileContents) | |
if matchFileHeader: | |
insertPos = matchFileHeader.end() | |
matchFileHeader = reNext.search(fileContents, insertPos) | |
if matchFileHeader: | |
insertPos = matchFileHeader.end() | |
includeStatement = "\n%s\n\n" % includeStatement | |
fileContents = fileContents[0:insertPos] + includeStatement + fileContents[insertPos:] | |
return fileContents | |
# This acts like the main() function for the script, unless it is 'import'ed into another | |
# script. | |
if __name__ == '__main__': | |
pass | |