CN1957328A - 展示方案组件的逻辑视图、便于其选择以及在编译之前的信号遗漏链接的软件开发系统 - Google Patents
展示方案组件的逻辑视图、便于其选择以及在编译之前的信号遗漏链接的软件开发系统 Download PDFInfo
- Publication number
- CN1957328A CN1957328A CNA018094716A CN01809471A CN1957328A CN 1957328 A CN1957328 A CN 1957328A CN A018094716 A CNA018094716 A CN A018094716A CN 01809471 A CN01809471 A CN 01809471A CN 1957328 A CN1957328 A CN 1957328A
- Authority
- CN
- China
- Prior art keywords
- name
- file
- software development
- development system
- product
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Pending
Links
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/30—Creation or generation of source code
- G06F8/34—Graphical or visual programming
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/70—Software maintenance or management
- G06F8/71—Version control; Configuration management
Landscapes
- Engineering & Computer Science (AREA)
- Software Systems (AREA)
- General Engineering & Computer Science (AREA)
- Theoretical Computer Science (AREA)
- Physics & Mathematics (AREA)
- General Physics & Mathematics (AREA)
- Computer Security & Cryptography (AREA)
- Stored Programmes (AREA)
Abstract
一种软件开发系统(100)从源代码单元(900)的核心库开发一个产品,核心库被分类成具有一个或多个特征的组件。配置程序(700)根据一个指定平台类型和源代码单元开发配置状态数据。图形用户界面(200)根据配置状态数据显示产品(1000)的一个可视逻辑表示,包括任何未解析的相关性的可视指示。产品make(800)例程然后根据配置状态数据从源代码单元产生产品。
Description
与相关申请的交叉参考
本申请是l998年9月24日提出的申请No.09/404,298的部分继续申请。
发明背景
1.发明领域/概述
本发明一般地涉及用于通过定制和合并源代码库并将其集成以形成软件产品来开发和集成一个软件产品的方法和系统。更具体地和例示地,本发明涉及一种用于维护和再使用个人计算机(PC)的基本输入/输出系统(BIOS)的核心组件的软件系统,该软件系统简化BIOS部署并提供一个允许快速的产品开发、增强和修改的用于可扩充且可维护的核心库的结构。
2.背景及技术发展水平
BIOS产品是在PC启动或“引导”时执行并在以后在PC运行时被调用以提供各种服务的一段软件代码。用于BIOS产品的开发系统必须支持可以安装在从低端基本PC到第一流的高度定制的高端服务器或便携式产品的任何类型的PC上的所有外设。下面将描述建立BIOS的各个方面,以显示一个用于维护和使用核心BIOS软件组件的库的软件系统所应该提供的性能。
希望为一特定机器建立一个BIOS的用户从一个组件库来选择核心BIOS软件组件来支持安装在该机器上的外设。每个软件组件可以包括一个或多个特征,并且可以通过从可用特征集添加或去除特征代码并通过指定用于这个代码的可选参数(“选项”)的值来配置。用户可能希望为由用户加工定制的、BIOS厂商所不提供的外设添加专用BIOS代码。
将可配置特征实现为核心BIOS组件库中的分离代码,其在以名字和以目录/子目录或以库名来寻址其他代码组件的代码中具有外部引用和定义,这样,每个特征的代码可以只在它被正确地配置和寻址时才链接到最终产品。目前的技术水平是用一个仅仅返回其调用程序的占位例程(stub routine)来代替用于一个未选择的被调用、命名和寻址的可选特征的代码。如果特征被去除,另一个可能性是通过一个可以被设置成空的指针来间接地引用可选特征;然而,这需要每个调用程序确定该指针是有效的。理想地,当建立组件时应该从代码中去除用于调用一个可选特征的代码,以便实现节省执行时间以及程序占据的存储空间。
目前的技术水平将软件组件的可选参数(下面称为“选项”)定义为明显常数,例如“BUFFER_SIZE EQU 256”。在定义明显常数时,将明显常数的名(BUFFER_SIZE)和它代表的值(256)相关联。在编译源代码时,对明显常数名、例如阵列长度或变量值的每次引用被相关的常数值所代替。这使得每个选项被给出一个描述性的名字,并且有可能通过改变一个定义可以在它被引用的所有地方改变选项值。诸如这些的选项典型地通过以手工定义或修改一个“include”文件来设置或调整。然后通过引用将“include”文件合并进其他源代码文件中。容易遗漏一个包含对选项名的引用的文件,或者容易混淆在不同的系统组件具有相同名字的选项。
核心BIOS组件库的制造商和销售商需要迅速地响应进入市场的新设备。一个行之有效的方法是对类似的已有设备的代码进行拷贝并只在需要支持新设备的地方进行修改。原始代码可能支持几个现在也可用于新设备的可配置特征。从另一个核心组件拷贝代码将导致在同一个库中的两个组件不仅具有相同的特征,还具有用于引用它们的相同的外部名。在编译和链接时这种不明确将引起进一步的混淆。
用户可以销售包含旧设备或新设备的机器。因此,用户可以创建一个既包含支持旧设备的旧软件组件又包含通过修改旧组件产生的、具有相同外部名的支持新设备的新组件的BIOS。这个BIOS将包含另外的代码来截取对旧组件和新组件中的每个过程的调用程序。用户然后将增加用于每个被截取过程的判决代码,判定是应该调用新组件还是旧组件中的过程。这产生一个包含具有相同外部名的两个组件和用于每个必须不被截取地调用具有相同名字的两个过程中的一个的被截取调用的判决代码的BIOS。这两个软件组件都必须被单独地编译和链接,以使得每个组件中的相同的外部名不会冲突。它们还必须与调用它们的判决代码链接在一起。
假设旧组件和通过修改旧组件而产生的、具有相同外部名的新组件都具有一个名为INIT的初始化特征。可以调用上述附加的判决代码来代替INIT过程,这样可以确定是应该调用旧组件还是新组件中的INIT过程。现有技术需要对INIT的每个调用通过一个指针表间接地进行,以使得指针可以被改变以便截取、或异常分支每个这样的调用。贯穿BIOS的对INIT的所有调用将被以这种方式截取或异常分支。截取这种调用的能力对于调试目的也是非常重要的。
核心BIOS组件库的制造商通过迅速地发布库的新版本来响应进入市场的新设备。在维护和增强库的过程中,他们可以修改一些接口来增加功能或解决故障。具有现有BIOS的用户希望在包含新支持设备的同时还包含这些新功能和故障解决。用户必须验证已经改变了的对现有接口的调用仍然是兼容的,并迅速识别出那些现在不兼容的以及必须改变的接口。现有技术通过匹配参数数目、每个参数的类型和值的范围来确认接口。
用于一特定设备的BIOS代码典型地由在PC启动时执行的初始化代码和在被调用时提供服务的支持代码组成。在支持代码中可以没有对初始化代码的引用,反之亦然,这将使得两段代码都包括在BIOS构件中;然而,支持代码无疑地依赖于初始化代码。现有技术需要手工干涉以确保这两段代码都包括在构件中。
最后测试源代码模块的一致性的常规方式是编译和/或汇编单独的源代码文件,识别和校正所有错误并重复这个过程;链接目标代码文件,识别和校正所有错误并重复这两个过程;以及,最后,将单独链接的系统部件合并成一个相互链接图象,识别和校正所有错误并重复地和循环地重复这三个过程,直至再找不到错误。尽管那样,由于相同的名字被用于表示不同的源文件集合中的不同事物、由于对两个非常相近的源文件集合的错误集合的选择、或由于编译程序和汇编程序不能检测出的版本不兼容性,可能会产生不正确的链接。所有这些问题在一起使得软件系统开发和集成比理想状态下更费时间。
因此,本发明的首要目标是实现一个软件开发系统,可以在任何汇编、编译或链接之前识别并帮助校正上述类型的错误;允许容易地查看和选择组件、特征和变化而不考虑相应的源代码所存储的地方;允许全局地指定该产品是一个“服务器”或是“便携式的”,并从而实现完全不同的系统配置;以及,解决上述选择几个组件变化中的正确的一个、调整和控制选项的值和范围以及根据源代码相关性自动选择所需系统组件的问题。
发明概述
简要地说,以及依据这些和其他目的和优点,本发明实现为一个用于创建使用源代码库的软件产品的目的来管理源代码库的软件开发系统。本发明从一个源代码文件系统汇集丰富的信息,该源代码文件系统被构造为便于和允许系统设计者支持这个汇集。汇集的信息具有多种用途,一种用途是配置正在开发的产品。产品配置包括选择要被集成到最终产品图象中的源代码库部分。为要创建的产品的类型自动进行配置,并且通过产生子例程以创建一个完全的且相关的产品来满足代码相关性。向系统设计者展示适用于并且将构造进正在开发的产品中的源代码的一个视图,并且,给予他或她由本发明所支持的简化的定制性能。所提供的定制技术对经过升级和维护的产品的生存期都是可维护的。
将产品配置转到产品建立进程,从而允许编译和目标创建利用已获得的产品知识。通过在增加到代码树中的动态创建的文件中定义的等式(equate)将配置数据转到编译进程。预处理器宏指令扩展到利用这些等式,或者用于尺寸优化,或者用于流程控制。例如,根据在创建的文件中提供的等式的值,可以将一个可选过程调用程序编译进来或编译出去。这个等式的值是基于所调用的过程是否是产品配置的一部分。产品配置确定要编译进最终产品图象的具体文件。在本发明的最佳实施例中,根据产品配置动态创建Unix形式的Makefile。这个进程代替了使用搜索目标库;创建的所有目标库都是装入库。
本发明还将编译进程中的信息转到本发明的一个产品链接程序。在正常地址链接之外,这个产品链接程序能够支持另外的定制支持、资源优化、执行布局管理以及产品确认。
作为本发明的一部分,将源代码文件放在一个目录分层结构中。不同的子目录对应不同的软件“组件”。目录分层结构中的每个“组件”,不论它是意味着支持一特定硬件设备的需要的软件的一个真正的软件组件还是一个“硬件组件”,都可以进一步由存储在较低层子目录中的一个或多个“特征”来定义,以便一个或多个特征可以包括每个组件并且在更低层的子目录中还可以存储“子特征”。一个或多个源代码文件可以驻留在每个特征子目录中。每个组件和每个特征进一步由一个放在其相应的子目录中的信息文件描述,信息文件定义设计的特征的平台的类型(服务器,笔记本,等等),其所分配的类,等等。
在本发明的最佳实施例中,源代码文件调用专用的预处理器宏,以定义每个外部过程,并将其分为公共(可在组件之间调用)或私人(只能由一个组件内的父或同层结点调用)。对这样一个外部过程的每次调用还以一个专用的宏例程进行,并且,包含这样一个调用的每个源文件以对另一个专用宏例程的调用说明该过程正被公共或私人引用。这些专用宏例程尤其可以传送程序修订号和程序类名称(designation)。专用宏还用于定义公共和私人“include”文件,并说明对它们的引用。另外,专用宏可以用于创建一个列表、定义要形成这样一个列表并从单独的源代码组件绘出的入口、以及为列表入口指定排序条件。
扫描组件信息文件和特征信息文件,并将其内容存储在一专用数据库中。这些文件使一个组件或特征与一个特定类相关,并且可以指定组件对其是适用的或必要的平台的类型(桌面,便携式,服务器,等等)。分配给每个特征的源代码文件也被扫描,并且,与专用宏相关联的参数、例如类和版本号也与每个特征的目录地址一起被输入进数据库。这个数据库则保存了源代码库的一个完整的描述,包括可用组件、每个组件提供的特征、特征被一起分类以使其在以后被一起链接的方式、以及用于选择组件和特征以包含在一特定平台类型(便携式,服务器,等等)中的规则。用于每个特征的信息包括必须被编译以提供每个特征的源文件、对每个特征的外部接口、每个特征对外部定义的子例程和选项的相关性、以及防止不同类中的相同名字被混淆和交叉链接的类分配。
一旦使用本发明的系统设计者已经指定了平台的类型,则从数据库提取出指定用于这样一个平台的配置所需的最少信息,包括所指定类型的平台所需的所有组件和所有特征。这个平台指定识别出必须被编译和链接以提供所希望的系统配置的源代码文件的一个初步集合。有来自本发明的宏的参数的足够多的信息来将每个过程调用和选项与其正确的定义联系起来。
本发明以一个链接程序的方式操作,在于它将每个过程调用与其定义联系起来,并识别出所有遗漏的过程;然而,这个测试“链接”进程远在编译或汇编和链接之前进行,利用从在库中找到的所有专用宏的参数可用的所有信息。这允许本发明采用除仅仅匹配过程名和变元计数以外的标准将一个过程调用与其定义联系起来,并识别和通知采用一个不兼容接口、例如不兼容的程序版本的任何过程调用,以及用类名称在过程调用之间进行区别。
本发明在编译或汇编之前快速识别出当前配置中的问题和错误,并提供一个可视界面,设计者可以通过这个可视界面通过选择和编辑源代码文件来快速定位和改正问题。同一个可视界面还允许设计者通过点击鼠标按钮来添加或去除组件和特征以及添加或超覆源文件选择以便根据需要调整配置。
一旦设计者已经选择了一个有效配置,他或她可以指导本发明来建立所配置产品。本发明然后只编译或汇编由配置数据指定的那些源文件,并单独地链接每个特征以解析组件内的私人外部引用,将类名称变换成具体地址以解析公共外部引用中的模糊点,并因而为每个组件产生一个链接的可执行文件。最后,调用一个专用产品组件链接程序,作为可以将单独的组件可执行文件一起链接成最终集成产品的第二级链接程序。每个公共过程调用用其引用的公共过程的地址来修正。由本发明的列表宏定义的列表被集中、排序并存储在将其限定在的代码段中。
产品组件链接程序由与宏相联系的数据控制和定向,并且,在最佳实施例中,将其转到专用代码段中的组件链接程序,专用代码段被读出,然后由组件链接程序舍弃。过程调用之间的各种选项和链接的分辨以及过程入口点在最佳实施例中也由自动产生的专用“include”文件来控制,“include”文件将信息传到每个源代码文件,以使得每个宏来重新定义、重新定向或甚至完全省略任何给定的过程调用语句、控制每个选项的范围以及允许设计者通过可视界面调整选项值。在没有RAM的环境中作出的程序调用也可以通过自动使用一个寄存器来用于返回地址存储和以ROM代码自动提供假堆栈和寄存器控制的返回跳转以截取过程“返回”指令的宏来实现。
本发明的其他目的、特征和优点在下面的附图和最佳实施例的详细说明中变得明显。体现本发明特点的新颖性特征在附带的并形成说明书的一部分的权利要求书中着重指出。
附图简要说明
图1展示依据本发明的教导设计的程序开发系统100的总体方框图,着重于各个软件单元之间的关系;
图2展示可视用户界面系统的总体概要,列出用户可执行功能,还列出显示功能;
图3是显示执行用户启动的命令的例程的方框图;
图4是数据库更新例程的方框图;
图5A是显示修改一个文件、更新数据库、确定修订产品配置以及向用户或系统设计者显示新修订的配置的进程的流程图;
图5B是显示创建一个最终产品的进程的流程图,包括扫描所有文件、更新数据库、修订配置(如果需要的话)、向系统设计者显示任何配置修订以及建立完成的产品;
图6是数据库访问例程的方框图;
图7是配置程序例程的方框图;
图8是显示产品make过程的概观的流程图;
图9A是为每个特征创建“feature.inc”文件的构件准备例程的流程图;
图9B是创建组件makefile和调用图9A中的例程以创建“feature.inc”文件的构件准备例程的流程图;
图10是在执行产品和组件makefile时由make应用实现的步骤的流程图,使得由产品组件链接程序进行源代码选择、修改、编译、汇编、链接和最终组件链接;
图11是显示程序开发系统100的概观的流程图,着重于本发明的数据流方面;
图12显示了组件源代码库(图11中的1200)的内容的提纲;
图13显示了一个占据了图11所示的组件源代码库1200的典型的IBM PC兼容汇编语言源代码文件1300的内容;
图14显示了一个占据了图11所示的组件源代码库1200的典型的组件信息文件“compnent.inf”1400的内容;
图15显示了哪些可以放在组件信息文件中的一个例子;
图16显示了一个占据了图11所示的组件源代码库1200的典型的特征信息文件“feature.inf”1600的内容;
图17显示了哪些可以放在特征信息文件中的一个例子;
图18显示了图11所示的组件数据库1800的内容的概观;
图19显示了图11所示的配置状态数据1900的内容的概观;
图20显示了图19所示数据的被选择并送入图8和34所示的产品make例程900以支配所完成产品的建立的部分的概观;
图21显示了在图11所示的产品配置数据文件“platform.cfg”2100中包含的产品配置命令的一个例示集合;
图22显示了哪些可以放在这个“platform.cfg”文件中的概观;
图23显示了一个例示特征include文件“feature.inc”2300(图11)的内容,这些内容由产品make例程900(图11)自动产生,更具体地,由构件特征include文件例程950(图9A和35)产生;
图24显示了一个例示组件makefile2400(图11)的内容,这些内容由产品make例程800(图8和34)自动产生,更具体地,由组件构件准备例程900(图9B和34)产生;
图25显示了一个例示产品makefile2500(图11)的内容,这些内容由产品make例程800(图8和34)自动产生;
图26是也在图4中显示的数据库更新例程400的方框图;
图27是图26中所示的(由图4、11和26中的步骤调用的)展现特征和组件文件扫描例程2700的细节的方框图;
图28是也在图7中显示的图11中所示的配置过程2800的方框图;
图29是配置程序过程2800(图28)的初始激活例程2900部分的方框图;
图30是配置程序过程2800(图28)的产品配置例程3000部分的方框图;
图31是配置程序过程2800(图28)的产品配置例程3000(图30)内的解析外部引用例程3100的方框图;
图32显示了也在图19中显示的基于RAM的产品配置数据1900(图11)的内部结构;
图33A向系统设计者展示了本发明的图形用户界面的视图;包括一个方案的逻辑视图和具体文件的窗口视图;
图33B显示了在用户界面中如何向系统设计者展现错误;
图33C显示了系统设计者如何从图形用户界面打开、去除或超覆一个源代码文件或学习其特性;
图33D显示了系统设计者如何用图形用户界面打开和选择或取消选择一个组件;
图33E显示了系统设计者如何利用图形用户界面调整一个选项;
图33F显示了在图形用户界面中的图标及其含义;
图34是也在图8中显示的产品make例程800的概观方框图;
图35是也在图9A中显示的构件特征include文件例程950的方框图;
图36展示了产品组件链接程序例程3600(图11)的方框图概观;
图37展示了列表创建和管理进程3700的方框图概观;
图38展示了显示控制信息在系统100中的流程以指导软件开发进程的方框图;
图39展示了显示非易失RAM的分配(allocation)和管理的方框图;
图40展示了显示串的分配和管理的方框图;
图41展示了显示本发明的公共、私人和“ShieldPrivates”相关性访问特征的方框图;以及
图42展示了显示使用产品组件链接程序3600以定制从表中取出的单个项目的方框图。
发明详细描述
本发明的最佳实施例被优化用在一个IBM兼容PC ROM代码图象软件开发环境中,在该环境中,由许多厂商使用一个共享的代码库来开发用于具有大量不同的处理器、总线和外设的便携式设备、桌面设备和服务器的ROM BIOS代码图象。本发明是采用常规的、未修改的汇编程序、编译程序和链接程序以及标准的UNIX-式样的make实用程序开发的。另外,开发了一个专用产品组件链接程序3600(图36)来用于本发明。组件链接程序3600在许多方面是一个常规的链接程序,用于将单独编译和链接的*.exe文件合并成一个适合于ROM存储的单个集成代码图象。其不同于用于此目的的常规工具的方面将在下面指出。
本发明预期,在ROM BIOS图象开发之外,本发明还可应用于所有类型的嵌入式系统以及通常的软件开发。在其更普遍的特征中,本发明可应用于软件组件和特征需要被管理、选择和改变以满足具体客户的专门需求的任何软件开发环境。
因为常规的编译程序、汇编程序和链接程序在没有任何专用文件预处理器的情况下被用在本发明的最佳实施例中,并且因为将本发明的一些步骤(在其最佳实施例中)从这样的编译程序和汇编程序内部执行是所希望的并且是便利的和有效的,所以需要一些改变这些标准组件的性能的方式。因此,本发明的最佳实施例期望在常规程序设计命令、例如“CALL”或“PROC”或“INCLUDE”等将正常出现的许多点将专门定义的宏插入源代码。将在这个说明书的最后、在本发明的更一般的总体解释之后非常详细地描述这些专用宏。但也可以利用预处理器或利用可以实现本发明的功能的修改的编译程序和汇编程序,而不需要也不使用一些或所有这些专用宏。实际上,通过仅仅使一个预处理器或编译程序和汇编程序以本发明使其响应替代这些命令的宏的方式相同的方式响应诸如“CALL”和“PROC”和“INCLUDE”的命令,也可以实现通过使用专用宏在本发明的最佳实施例中实现的结果,而不需要源代码文件的作者必须使用专用宏。本发明将设计中的这种变化包含在其范围内。
另外,本发明的最佳实施例将用于控制产品组件链接程序的数据放在由专用宏定义和创建的专用代码段中,这是在IBM PC环境中特别倾向的一种技术,在该环境中,程序分段也被大量地用于其他目的。其他等效方式可以容易地被用来例如在进程中早得多的级上从许多源代码文件采集这个数据(例如列表的定义和内容),并用于将这个数据传到组件链接程序或其等效程序,从而实现本发明的目标。
在图1中展示了本发明的最佳实施例的程序开发系统100的概观。图1着重于形成系统的各部分的主要软件例程以及它们如何相互调用和联系。
在系统100的中心是一个集成的开发环境102,包括用户界面200,其功能在图2中进行了阐述。用户界面本身在图33A到33F中出现。参看图33A,向设计者展示一个第一窗口(左边),在其中,他或她可以查看源代码库的逻辑(如图所示)或目录-子目录视图。“逻辑视图”是被组织的代码库的用户视图,代码库的组件和特征被分层显示,首先是类,然后是组件,然后是特征,然后是子特征,等等,每个单个源代码文件与一个相应的组件、特征和子特征相联系。
如图33A所示,逻辑视图包括根节点3308,显示为Platform-Desktop-IA32。在根节点3308下面的第一层中是一系列组件,例如Fdisk 3310、Intel371ab(PIIx4)3314、POST services 3306等。在每个组件下面的层中,有一个或多个特征。例如,在图33A中,POSTservices组件3306包括几个特征,例如Decompress Manager 3304、Memory Manager3307和POST Dispatcher3309。除了直接在一个组件下面的层中之外,在更低一层中还可以看到作为子特征的特征,子特征是一个到父特征的子特征。在图33A中,LZINT特征3311是Decompress Manager特征3304的子特征。
此后,术语“目标”将一般地用于表示“组件”、“特征”或“子特征”。(术语“目标”在这个专利中的这个专门用法不会与面向目标的程序设计领域中的术语“目标”所指定的完全不同的意思相混淆。)然而,带有由类(注意,图33A中的组件3306的类名称“post”3321和特征Decompress Manager 3304的“decompmgr”3323)细分的代码的“逻辑视图”不仅仅是用户视图。在源代码文件中,当对外部名、例如include文件、过程和选项进行引用时,类名称可以代替这些精确的目录/子目录地址来用在常规软件开发系统中,并因此程序员不需要精确地关注一个外部过程或所包括的文件所在的位置-只关注分配给包含外部过程的源代码文件的类。
图2列出了由用户界面200执行的主要功能和提供的视图。设计者可以使用键盘或鼠标202来修改文件或目录302(图3),从一个有效配置建立产品306,通过将其强行放入或拿出构件来定制特征304,除来自组件源代码库的代码之外还指定自定义代码或指定定义代码(文件超覆)来代替该代码304,以及定制或改变选项值304。作为这些改变的结果,更新的用户视图204则显示组件和特征树(图33A的左边):将组件和特征清楚地标记为在构件内(粗体)或构件外(淡色)(图33A);超覆缺省配置,将组件和特征清楚地标记为设计者将其强行放入构件(用一个方格标记)或强行拿出构件(用一个“禁止”斜线圈标记)(图33D);清楚地标记所示的初始源文件加自定义3332和超覆文件3326(图33C);单独列出相关性3325、3327,并可折叠成一个图标(图33B);界面声明3329(图33B)、选项声明3336(图33E)可查看;以及,清楚地显示特征/文件错误和警告3318、3320、3322、3324和3325(图33B)。
用户界面200允许设计者通过一个命令执行程序例程300发出命令,在图3中显示了该例程的概观。在图3以及后面所有类似的图中,放在包围例程300的组件的大矩形的边框上面的任何矩形包含对例程的一个或多个入口点一可以由设计者或由调用例程发出的一个或多个命令。
如果设计者希望更新或修改一个源代码文件,或将文件移到一个新的目录中,或改变系统的目录结构,设计者利用图33A所示的用户界面完成这些。例如,为了修订一个源代码文件,设计者用鼠标和指示器点击文件名3326(图33C)并选择“Open(打开)”。文件出现在一个可编辑窗口中(图33A的右半边),在这里,设计者可以检查并可选地修改源代码文件(图5A中的步骤502)。当设计者完成时,设计者关闭该窗口并以常规方式“保存”任何修改。然后自动调用命令执行程序300以执行图3中所示的从302开始的并以流程形式在图5A中显示的步骤。首先,在图3、4和5A中的步骤402,调用数据库更新例程400(图4)以扫描文件,假设文件已经被改变(图4中的步骤404、406和408)。例程400采集来自源代码驻留的专用宏的和来自在组件和特征信息文件中找到的命令的、定义每个源代码文件的内部名、入口点和出口的信息(图4和27中的步骤2700),如图18(源库数据库1800)中的1826至1830所指示。收集的信息包括分配给每个过程调用的“类”,以便例如将“TIMER”类过程与“DMA”类过程区别开来,使得相同的过程名不会被混淆(例如,“TIMER.RESET”不会与“DMA.RESET”混淆);版本号、例如“3.2”,供以后使用,以检查不相容版本;以及类似信息。所有这些信息都由数据访问例程600写API例程602(图6)存储在数据库1800内(图6和18)。
接着,在入口704调用维护RAM中的配置状态数据1900(图19和32)的配置程序例程700(图7),以便通过重新确定要包括哪些目标(部件和特征)、要排除哪些、哪些目标使设计者选项带有哪些缺省值、已经根据什么平台类型(服务器,桌面设备,等等)进行了选择、需要满足何种相关性(选项,对函数的调用,文件包含,等等)等等,使用数据库1800更新产品配置状态数据1900并然后配置3000(图30)要建立的产品。最后,在步骤204(在图3、5A和7中),调用例程UI UPDATE VIEW(图2),以便在图33A的左边窗口内重新产生软件系统的逻辑视图,以便与设计者共享系统的新状态,并允许设计者改变缺省目标选择(参见图33D中的菜单3334)或调整选项值(参见图33E中的菜单3338)。以这种快速且不引人注目的方式,由设计者作出的所有改变都被快速准确地记录,因而重新配置了要建立的产品,并且立即向设计者展示所有这些活动的结果。
如果设计者例如做了由于不能满足相关性而可能使常规系统中的最终链接程序失败的事情,例如通过一个“call”语句可以链接到的任何外部过程的库内的缺失(例如,这可以仅仅由过程名的拼写错误引起),则如图33B所示,小“X”将出现在引起问题的项的旁边。设计者则可以通过仅仅向下点击过所显示的树来快速地找到例如,引起问题的特定的“相关性”(例如,在图33B的3324,类“pic”中的子例程名“SendEOI”显示为“pic.SendEOI”)。“find”实用程序使得包含这个引用的文件被迅速找到、打开、校正和关闭,包括系统在内再次被自动更新和校正以反映该校正(“X”则将消失)。
现在参看图3和5B,当要建立最终产品时,由用户界面200响应一个用户键盘/鼠标命令202调用命令执行程序例程300中的入口306“全产品构件”。再次调用数据库更新例程400(图4)入口402,以执行一个扫描,这次是扫描整个库:源代码文件;组件信息文件;以及特征信息文件。简要地参考图15和17,“component.inf”和“feature.inf”组件和特征信息文件包含定义选项值的构件命令(例如,行1528),还包含形式规则,以便在逻辑上确定何时选择一个特定目标(组件或特征)(例如,图15中的行1514、1516和1518)。这些文件还为相应的组件和/或特征提供类名称(例如,行1504)。这样一个类名称被自动加到存储在与包含这样一个类名称的“component.inf”或“feature.inf”文件相同的子目录中的任何源代码文件内的过程和标号(label)上。这例如使得对指定一个类、好像它是一个“路径”(“类路径”名称,例如“TIMER.RESET”,其中“TIMER”是类,“RESET”是过程名)的过程的外部调用可以被找到并正确地链接,而不需要单个调用源代码文件必须指定通过源代码库树到被调用的过程源代码文件的实际路径。这个类名称还确定如何在库内容的与“目录/子目录”相对的用户“逻辑”视图中组织目标(图33A)。由于相关性总是按照其类被标明的,除了确定哪一子例程或过程调用链接到哪些源代码文件中的哪些子例程或过程的类以外,只要满足以相关性进行的任何类型的外部引用,类名称还确定其他类似的链接。相同的函数和过程名以及其他名字(例如,包括文件名)因此可以用在分配给不同类的特征和目标中,而不会引起任何混淆或错误链接。类名称使得include文件和过程能被找到,而不考虑它们在组件源代码库文件目录树中实际存储的位置。例如,在汇编或编译之前,在没有用户干预或知道include文件实际存储的地方的情况下,自动产生include文件路径(或地址)并插入。
接着,更新数据库1800(图6)(图4、5B和6中的步骤602)。然后,再次调用配置程序700以修订产品配置状态数据(步骤706);如果作出任何改变,则调用例程UI UPDATE VIEW 204(图2)以更新用户视图;如果出现任何红色的“X”,则取消产品构件。
注意,在图7中,配置程序以从文件“platform.cfg”取出的产品配置数据2100开始配置。参看图22,这个产品配置文件标明诸如PLATFORMTYPE 2201(服务器,桌面设备,等等,以及具体结构)、系统选项值2202、要包括的或不包括的特征2212、要包括的附加文件2215、要替换的文件2216(超覆)、选项值2218-2220等信息。所有这些信息都来自用户界面,并且所有这些信息都在用户指导下创建。通过询问设计者简单的问题以确定平台类型、系统结构以及其他这样的基本事情,可以使用一个简单的问题询问例程(未显示)来创建一个新配置。只要设计者再次通过与用户界面的交互运用他或她的选项来超覆缺省目标选择和选项值,就累积在这个文件中包含的数据的剩余部分。(当然,这个文件还可以手控编辑;整个程序开发系统可以在没有用户界面的情况下运行,其中一次一步地手控执行图1的右边所示的例程;但本发明的功能的很大一部分在于该交互式用户界面。)
配置程序700接着进行到数据库1800,并使其本身装满数据库包含的所有数据,既包括从源代码文件的扫描获得的数据,更尤其包括程序员提供到专用宏调用语句的参数(例如,从每种类型的宏取出的类、名字、版本号等),以及从与相应的类和特征源代码文件占据相同的子目录的专用类和特征文件收集的数据。所有这些信息一起被称为产品配置状态数据1900。如图19所示,这个数据包括组件名1902、1904、1906、组件描述1908、特征名1910和1912以及与每个特征相联系的信息、例如类1914、文件1916、定义1917和引用1919等。这是管理用户显示性质的信息。注意,每个目标(特征或组件)的“in”1922、1926和“out”1924、1928状态由配置状态数据中的一个标志位或数清楚地标记(如图19中的X的有或无所指示的)。
程序控制接着以对图8所示的产品make例程800的调用继续(图3和5B中的步骤800)。产品make例程在步骤802通过调用配置程序700开始,以提供所有活动(或选定)组件的一个列表。产品make例程800最后将检索出图19中所示的所有选定(或“X”)信息。这个选定信息显示在图20中的2000。
现在返回图8所示的产品make例程800,在步骤900,对于每个单独的组件,产品make例程调用组件构件准备例程900,如图9B所示。在步骤902,这个例程调用配置程序700及其RAM配置状态数据2100,以提供该组件的源代码文件和文件相关性信息。接着,在步骤950,调用构件准备—特征include文件例程(图9A),以经过组件的每个特征子目录。在步骤952,再次调用配置程序700,这次是为了获得关于一特定特征的信息。在步骤954,将提供的信息与在特征的“feature.inc”文件中找到的现有信息进行比较,如果存在的话。如果信息已经改变(步骤956),则产生一个新的“feature.inc”文件2300并写入。接着,在步骤960,如果有更多的特征,则重复这个进程,直到在步骤962已经检验了所有特征。程序控制然后返回到步骤904,在这里,将组件信息与任何现有的组件makefile的内容进行比较。在步骤906,如果有任何改变,则在步骤908创建一个新的组件makefile2400(图24)来管理组件及其所有特征的正确编译和/或汇编和链接,形成一个“*.obj”目标文件。以这种方式重复地调用构件准备—组件makefile例程900,对已经选择包含在最终产品中的每个组件调用一次。
通过简单地解释,下面将进行补充,将“feature.inc”文件与实际定义每个特征的源代码文件一起放在每个特征子目录中。每个特征源代码文件包含命令“INCLUDE feature.inc”。这使得编译程序或汇编程序将一个特征的“feature.inc”文件插入该特征的所有源代码文件,在这里,它们可以执行诸如改变对文件路径引用的类引用的任务、定义选项以及设置开关,该开关使得过程调用被从源代码删除,如果它们调用了未选择的组件(例如,参见图23,将值TRUE赋给“D_TIMER_DELAY”,使得一个对“TIMER_DELAY”函数的子例程调用包括在源代码中),或使得过程调用被例如以一个具体组件名来标记(以便要求链接到一个调用语句的过程驻留在所命名组件的一个特征内)。同样,一个过程入口点可以被标记为“最优先”,以使其优先于在其他一些源代码文件中的相同的过程名被选择。通过自动产生的“feature.inc”文件的机制,所有这种用户选项机制都可以由系统设计者从图形用户界面调整,而不需要编辑或改变源代码文件本身。这给予系统设计者以最小的努力对于所完成产品的配置进行的空前的控制。
在已经处理了所有组件之后,程序控制返回产品make例程(图8)步骤908,在此创建一个产品makefile2500。这个产品makefile2500包含将计算机的注意力切换到各个组件子目录并且然后使计算机执行在每个这样的子目录中找到的组件makefile2400的指示,从而为每个目标建立一个目标代码模块。然后,它调用产品组件链接程序3600,以便将所有组件目标代码文件1104(图11)一起链接成完成的产品1106(图11)。
接着,在图8中的步骤1000,调用标准Unix“make”实用程序,以便在刚刚描述的组件和产品makefile2400和2500的控制下建立产品。这个过程在图10中进行了概述。在步骤1002,从主makefile读出一个选择组件的子目录的命令(步骤1006)。由产品makefile2500管理的make实用程序然后调用其自身,以处理在该组件子目录内找到的组件makefile2400,实现步骤1008到1016。在步骤1008从组件makefile2400读出一个命令,该命令要求编译1010、汇编1012或链接1014一个特征源代码文件,并继续重复这个进程,直到已经执行了所有命令(步骤1016),从而产生一个也包含“修正”数据的专用段的建立的产品组件文件1104,产品组件链接程序3600将在以后使用该“修正”数据来将一个或多个单独链接的可执行目标代码文件拼凑成一个完成的统一的产品(其他专用段可以包含列表单元等)。在1018,读出产品makefile2500中的更多命令的make实用程序继续从这个文件2500读取命令,以选择另外的组件子目录,并调用其自身以执行在与每个另外的组件相联系的makefile中找到的组件make命令,如刚刚所描述的,直到最后所有的组件源代码文件都已经被编译或汇编和链接。
在步骤1004,make实用程序最后到达产品组件链接程序指令(图25中的2528和2530),该指令使得产品组件链接程序3600组合所有单独链接的组件可执行文件合并成一单个代码图象,修正地址,使得类和名引用都被绝对图象地址替代,准备合并到一个基于ROM的完成产品1106中。
参看图2,有多个其他用户命令可用。在入口304,设计者可以通过调用配置程序700来强行放入或拿出一个特征,以改变产品配置,并将这些改变反映和存储在方案配置数据文件2100“project.cfg”中。可以以相同的方式改变选项值,并且,被指定包含在所完成产品的制造中的文件可以被超覆并用设计者设计的其他文件替代。
另一个选项是在入口308的快速产品构件或单个组件或单个文件构件,其绕过树扫描和配置程序步骤402和706。当源代码库树在以前从未被处理过时,使用新的源树入口312,从而不必执行诸如图9A和9B中的步骤956和904的检查现有专用文件是否需要被校正的步骤(因为很可能没有这样的文件存在)。步骤402要求扫描整个树(图4)。然后取得进入配置程序700的配置产品入口702,该配置程序700在步骤604要求访问数据库1800(图6)中的数据,然后在步骤3000配置该产品(详情参见图30)。在步骤204(图2),为设计者产生一个报告,并将产品配置状态数据1900写出到磁盘存储器。
在这个说明书的最后详细描述了宏。在这里将概述其功能。
程序开发系统100在解析引用和声明之间的相关性方面很有用。程序开发系统100可以解析这些相关性的一种方式是采用宏。例如,宏可以用来解析在带有同一名字的两个例程存在并且这个相同名字的例程正在被引用的情况中的相关性。这样一种情况可能出现在两个或多个相同组件被用在一个系统中并且每个组件具有相同的例程名时。
为了克服这个问题,使用用于分支代码执行的宏EXTJMP和EXTCALL。这些宏必须由一个PBUEXT公共外部声明宏放在文件中的前面。EXTJMP和EXTCALL是用于从一个组件中的例程分支到另一个组件中的例程的宏。这两个宏都产生为产品组件链接程序预定(并放入图38所示的外部段3802中)的修正数据,列出EXTJMP或EXTCALL宏的地址和要分支到的例程的名字(类加过程名)。将修正数据存储在驻留在外部段3802中的中间库中,从这里可访问实际执行修正的产品组件链接程序3600。由EXTJMP或EXTCALL宏产生的名字和类可以是缺省名字和类;如果调用或跳转被PUBEXT声明具有一个备选名字和类,它可以是一个备选名字和类;或者,如果调用或跳转被PUBEXT声明是可选的,调用或跳转可以被完全删除,并且不产生修正数据。根据缺省过程是否存在由产品make实用程序计算的、作为“feature.inc”文件的一部分通过的数据切换将宏在缺省名和类和其他两个选项之间切换。这样,如果缺省目的地不存在,可以实现可选的调用目的地,或者,如果缺省目的地不存在,可以自动删除调用或跳转。
PUBEXT、EXTCALL和EXTJMP宏都可以用名字指明一个组件。然后,如果两个组件包含相同的过程名,则由EXTJMP和EXTCALL宏产生的修正数据将包含一个组件名名称,然后产品组件链接程序3600将该调用或跳转只链接到一个驻留在所命名组件内的过程。这样,可以解决上面讨论的名字含糊问题。
PUBLIC_RPOC宏指示一个组件内的过程的位置。这个宏可以接受的一个变元是关键字INTERCEPT,将其添加到由这个过程产生的“修正”数据。每个公共过程宏产生修正数据,包括过程名(类加名字)加上其在目标代码中的绝对地址,这个修正数据还标识出包含该过程的组件。将这个修正数据放在公共段3804中,从这里它可以由对数据进行实际修正的产品组件链接程序3600访问。
如果关键字INTERCEPT出现在一给定过程的修正数据中,并且如果有具有相同名(名字加类)的其他过程,则产品组件链接程序3600将(由其在外部段3802中的修正数据标识的)所有过程调用链接到标明INTERCEPT过程的过程,来取代例如分配给相同类并可能具有相同组件名的其他相同名字的过程。
下面是对宏和系统开发以及如何使用宏以及如何设计系统的更一般的讨论。该讨论并不完全依据本发明的最佳实施例,特别是不总是假设“修正”步骤是由一个产品组件链接程序执行的。当然,修正数据可以存储在一些形式的中间库中,并且代码的修正可以以其他方式完成。(最佳实施例的描述将以在下面的一些段落开始的图11的详细描述重新开始。)
PUBLIC_PROC宏可以用于声明一个调度例程。调度例程是一个用作分支到两个不同例程的调度程序的例程。例程的名字和地址可以作为修正数据存储。这个修正数据也存储在中间库中。构件工具在产生最终二进制图象之前舍弃由这些宏产生的修正数据。
除了EXTCALL和EXTJMP宏中的标明例程名的变元之外,在这些宏中的另一个变元标明用于解析具体分支的组件库的名字。用于解析具体分支的组件库的名字可以由设计者通过用户界面200标明。设计者可以从用户界面获得信息来确定可以标明哪些组件库。或者,一个自动控制实用程序(一个范例)可以分析在其中找到公用例程的组件,并用一个调度例程为组件之间的每个公用例程产生一个源代码模板。这个范例将自动控制对公用例程的搜索,并简化对调度例程的编码,并提供一种自动控制组件之间的调试的方法。
与每个分支的地址、要被分支到的例程的名字以及调度例程的名字和地址一样,将关于所标明组件库的信息作为修正数据存储在中间库中,构件工具在产生最终二进制图象之前舍弃该信息。二进制链接程序使用存储在中间库中的所有这些修正数据,以便以来自校正组件库的校正例程的地址修补分支指令,从而解析相关性。
通过使用这些宏来解析这样一种相关性,现有的组件例程不需要它所属的组件的先验知识,因为例程由组件自动区别,在组件中,它们被编译和链接成组件库。现有的组件例程也不需要再编译。此外,所有组件例程都可以封装在一单个组件库内,通过组件进行区别,这增强了代码的密封性。
不需要这些用于解析对存在于至少两个组件中的共同命名的例程的引用的宏。可以使用用于跟踪外部引用(即,分支)的任何方法。可以被使用的其他跟踪机制例如包括预处理器、汇编程序或编译程序关键字以及自定义链接程序。同样,本发明可以利用跟踪公共声明的任何方法。可以使用允许跟踪公共声明和声明类型(即,截取或非截取)的任何方法。
可以使用宏的另一种方式是选择在一个构件的目标中的对未解析的编译引用的可能的解析。目标名及其位置保存在一个数据库中。每个文件系统目录可以只有一个目标,每个目标目录包含COMPNENT.INF或FEATURE.INF文件。可以通过扫描用于这种INF文件的文件系统或通过采用API管理数据库来更新数据库。
目标可以被明确地指定。可以指定一个目录或目录列表,然后其搜索目标,不确定顺序,而是确定有或无。检测以及时的方式进行,可以被自动处理。可以使用数据库或其他一些存储装置。
INF文件包括包含用于浏览软件方案和控制编译过程的属性的ASCII文本。另外,基类(BaseClass)用于标识两个特征具有相同的界面并提供相同的基本功能。通常,没有一个最终软件产品包含两个具有相同基类的特征。
由于构件可以用于很多类型的目标硬件平台,因此将这些平台分类成一般类别、例如基本PC、笔记本或嵌入式是很有用的。对于这些平台类型中的每一种,可以指定缺省行为,缺省行为然后可以由设计者手控地改变。这些缺省行为中的一个是“OnDemand”属性,该属性表明,如果有另一个目标对它的引用,该目标将被包括在最终软件产品中,带有相同基类的另一个目标未被系统设计者明确地包括,系统设计者已经指定,硬件平台落入在平台类型命令中列出的一般类别。
OnDemand属性可以放在一个源文件(而不是一个单独文件)中。该属性还可以在一些种类的主数据库中而不是在树中。或者,该属性可以用于一个或多个平台类型或者在确定是否应该使用OnDemand属性时完全不使用平台类型。OnDemand属性可以被链接到任何数目的用户指定软件方案属性(不仅仅是平台类型)或不链接到任何一个。OnDemand属性还可以移到接口函数本身(用于函数级排除(exclusion))。
采用宏PUBLIC_PROC和PRIVATE_PROC来声明接口函数(即,可以在目标之间调用的函数)。这些宏指定函数的范围和其他属性信息。使用接口函数的目标必须与该函数在同一文件中要么采用PUBEXT或PRVEXT宏来声明其原型。实际的函数调用采用EXTCALL宏。在正常编译过程开始之前,配置程序700扫描源文件,以便确定所有接口函数的位置和对这种函数的所有引用。然后,根据平台类型和来自系统设计者的明确命令,将对接口函数的引用的列表与接口函数声明的列表进行比较。当有不带声明的非可选引用时,认为是未解析的。
可以在不使用宏的情况下完成对未解析的引用的检测。可以使用标准方法,包括直到编译的链接级留下的这种检测。利用一个库列表及其属性,还可以用在与动态装载库的后期联编中。
在这一点,检查列为OnDemand的所有目标,以查看包括它们是否解析一个或多个未解析的引用。如果是这样,则包括该目标。对目标将被包括在最终软件产品中的确定是在正常编译开始之前确定的。这通过从编译过程包括或排除目标中的文件来完成。对于一些目标,其中所有的文件都被包括或排除。对于另一些目标,这在逐个文件的基础上完成。在这两种情况下,修改make file。当带有相同基类的两个组件被标记为OnDemand并且这两个中的一个或两个将解析一个未解析的引用时,检测一个错误条件。虽然最好在编译之前完成,但将一个目标包括在最终make产品中的判决也可以采用链接级联编或运行时联编来交替地完成。
这个用于在编译之前解析引用的方法允许目标的开发者确定哪一目标应该被缺省包括。这降低了出错机会并提高了生产率。还允许更快的构件,因为所有目标和所有相关性的编译前的知识把要汇编的文件数目限制到最最小。
宏还可以用于根据所引用和声明的目标的版本(versioning)来解析相关性。PUBLIC_PROC宏被用于声明公共函数接口。在这个宏中的一个参数是x.y形式的版本号,其中,x是大版本号,y是小版本号。
增加大版本号表明接口的新近修订,其关于输入、输出和/或副作用不向后兼容。增加小版本号表明接口的新近修订,其向后与具有同一大版本号和较低小版本号的接口版本相兼容。这表明由较低小版本号期望的所有输入和输出都被支持,并带有类似的副作用。然而,新的输入可以产生新的输出和不同的副作用。这个版本方案只是许多可能的、包括非数字的、单版本数字和双版本数字方案中的一个,在双版本数字中,一个是当前版本,一个是向后兼容版本。
PUBEXT宏用于声明对一个是函数或阵列的公共接口的引用。参数之一包括由调用程序期望的版本号。版本号与PUBLIC-PROC和LIST_CREATE宏具有类似的格式。如果调用程序和被调用程序在大版本号上不同或者如果调用程序具有比被调用程序高的版本号,则产生一个警告。
访问数据库以确定“被调用程序”的位置及其版本。数据库中的信息用DBUPDATE(数据库更新)实用程序来更新,该实用程序在被调用时扫描在每个目标中的所有源代码文件中的前面描述的宏,并将接口的名字及其版本放在数据库中。它还通过扫描PUBEXT并将调用程序的位置和版本记录在数据库中来找到对这些接口的引用。
然后,为每个调用程序搜索数据库,以查看版本是否与被调用程序兼容。如果调用程序和被调用程序的大版本号相同并且被调用程序的小版本号大于或等于调用程序的版本号,则认为版本是兼容的。这个信息可以被显示、输出到一个文件等,以便告知设计者任何潜在的不兼容性。
不需要数据库,并且扫描过程根本不需要使用数据库。而是可以将版本信息作为一个由预处理器或专用版本的编译程序处理的专用关键字添加到数据原型。例如,在C中,函数的版本号可以编码为函数原型中的_-style关键字。
另外,将版本号加到调用程序和被调用程序的确切方式可以随程序设计语言的不同而变化。例如,在C中,如果使用MASM宏,可以将其加到函数原型上。对于其他实施例,版本可以用一个外部文件附上。版本也可以加到静态变量或数据结构上。
通过跟踪输入参数中的语义变化(修改了故障改正的参数定义),版本的这种使用使得大软件方案可以被更独立地建立。还可以在编译和运行时间之前给出关于软件方案是否会工作的改进反馈。版本方法还可以减少错误,因为通过检查版本号可以容易地识别出函数改变。
宏的另一种用途是截取对第一例程的调用,并使对第一例程的调用由是截取例程的第二例程代替。首先,使用两个用于分支代码执行的宏EXTJMP和EXTCALL。EXTJMP和EXTCALL是用于在组件之间跳转或调用例程的宏。这两个宏都产生列出每个调用和跳转的地址和要调用的例程的名字的修正数据。将修正数据存储在中间库中,并在构件工具产生最终二进制图象之前舍弃。
一个截取到另一个例程的调用的例程必须与要被截取的例程具有相同的名字。截取例程使用PUBLIC_PROC宏来将其自身声明为一个接口例程,将INTERCEPT关键字指定为一个宏变元。PUBLIC_PROC宏产生修正信息,修正信息列出截取例程的地址、截取例程的名字(与初始例程相同)以及该例程被用于截取另一个例程的属性。同样,将修正数据存储在中间库中,并在构件工具产生最终二进制图象之前舍弃。
采用产生的存储在中间库中的修正数据,一个链接实用程序被用来正确地链接每个分支,并产生最终二进制图象。如果例程未被截取,为启动分支的组件中的分支指令直接修补所调用例程的地址。然而,只要截取例程存在,将修补截取例程的地址来代替初始调用的例程。
虽然修补截取例程的地址来代替初始调用的例程,但也可以采用EXTJMP和EXTCALL宏从截取例程内可选地转移到初始调用的例程。链接实用程序将采用中间库中的修正信息执行这一点,以便将分支指令正确地链接到初始例程。另外,如果截取例程不再调用它并且最终二进制图象中的其他码段也不引用它,则可以可选地去除初始调用的例程。
可以将这个截取过程扩展到用引用的变量代替所调用的例程。还可以扩展到允许在同一组件内的例程之间的调用也可以被截取。该过程可以被修改为允许截取例程名不同于所截取的例程、即初始调用的例程。这将仅仅需要一个备用的单独的机制来将截取例程与调用程序的例程联系起来。
采用这个截取过程,可以将调用直接链接到其例程,而不需要间接链接。此外,调用程序不需要预料或知道截取一个调用的任何潜在例程。调用程序仅仅将其自身声明为任何其他过程。如果该初始调用的例程不再被调用或引用,则该过程也不需要该初始调用的例程在最终图象中。
通过消除不使用的代码,被截取的例程从最终二进制图象的消除允许更有效的空间使用。这个有效性可以扩展到消除作出不必要的调用的代码。当组成一个方案的所有源文件都存在时,一个扫描和更新实用程序扫描对引用其他文件中的声明的具体宏的每个方案源文件。两个分支宏EXTCALL和EXTJMP使用宏PUBEXT和PRVEXT来声明所有引用。扫描实用程序将扫描PUBEXT和PRVEXT宏。然后通过扫描实用程序将分支指令引用(通过PUBEXT和PRVEXT)的声明的名字与源文件名和位置一起记录在一个数据库中。
两个分支宏EXTCALL和EXTJMP需要两个BIOS外部声明宏:PUBEXT或PRVEXT中的一个。这些宏具有一个允许宏将对分支声明的引用声明为“可选”的属性字段。为了从最终二进制图象消除不必要的代码,如果一个分支指令引用的声明是可选的并且定义该声明的源文件不在构件中,则不编译该分支指令。
将每个分支与其在不同文件中的公共声明相协调。对于每个声明引用,一个标志指示在构件中是否有一个具体声明。对于不在一个方案源文件中的所引用的任何声明则不产生标志。将该标志存储在一个要由宏在编译期间采集的include文件中。
两个分支宏EXTCALL和EXTJMP将解释由扫描实用程序产生(并通过include文件传送)的数据,并可选地产生用于编译的所需分支指令。如果声明不在方案中,则不产生分支代码,用PUBEXT或PRVEXT宏将分支标记为可选的。如果分支指令的声明被解析,EXTCALL和EXTJMP宏还提供一个机制来插入要编译的附加代码。相反地,如果分支指令的声明未解析,则除了分支指令之外还可以去除附加代码。
这个进程可以扩展到用引用的数据类型来代替所分支的例程。所采用的机制与用于代码分支的相同。此外,不需要在这个进程的实施中讨论的宏来用于其实施。如果与在编译之前相反,通过在将方案拼在一起时动态地扫描声明而取代宏来实施该进程。用于声明和记录声明引用的宏可以替代地为由编译程序或其他实用程序、例如预处理器解释的关键字。同样如上所述的,可以使用一个不同于形式数据库的方法来记录声明及其引用。除了记录数据的其他方法之外,还可以采用一个为信息分析的单片文件。另外,一个不同于include文件的机制可以用于传送标志。
这个去除可选分支代码的进程允许在源编译之前利用系统的先验知识去除代码,这减少了编译时间。除了声明本身之外对声明引用的去除也在没有占位程序的情况下完成。该进程的操作也经过多个翻译单元。
声明和引用的解析以及版本的使用也可以运用到标号上。与过程、即例程类似,使用PUBLIC_PROC和PRIVATE_PROC宏来声明每个标号定义。由PUBLIC_PROC或PRIVATE_PROC宏定义的标号可用于解析公共的或私人的标号引用。每个标号定义包括标号名、标号位置以及所定义标号的版本。PUBEXT和PRVEXT宏用于声明每个标号引用。每个标号引用包括标号名、标号位置以及所引用标号的版本。
将一个确认实用程序用于确认每个标号引用。确认实用程序的功能可以与另一个实用程序、例如编译程序或集成开发环境相集成。该实用程序确保每个标号引用具有一个相应的标号定义。该实用程序然后比较每个标号的版本信息。如果一个被引用的标号不存在或被引用的标号是一个不正确的版本,则该实用程序报告一个错误。一旦所有标号引用都被解析,确认实用程序报告每个标号引用的解析状态。可以报告每个标号的解析状态,以便在构件进程的调试中进行帮助。
通过在执行耗时的构件进程之前迅速地检测和校正所有与构件有关的标号解析错误,这个进程允许设计者执行构件进程以节省时间。也不需要为了检测与构件有关的标号解析错误而预先建立在软件产品的代码之外的库或组件。
在程序开发系统100中,将主数据结构称为一个“列表”。列表是固定尺寸的单元阵列,其入口可以由任一个源代码文件增加。列表必须采用LIST_CREATE宏创建一次。这指定列表的名字和每个列表入口的尺寸。列表入口被成组增加。该组以一个LIST_START宏开始,以一个LIST_END宏结束。每个列表入口被分配一个名字。
对于包含替换列表入口的组,LIST_START宏上的一个额外参数指定超覆优先权。将超覆优先权加到组内的所有列表入口上。如果软件方案包含具有相同名字但不同的超覆优先权的两个列表入口,则保留具有较高优先权的列表入口,舍弃另一个入口。具有相同名字和优先权的两个入口是一个错误条件。
二进制链接程序创建包含所有列表入口的最终列表。二进制链接程序找到所有列表入口。对于具有相同名字的列表入口,比较其超覆优先权。保留最高优先权的入口,并舍弃其他入口。顺序地放置一特定列表的列表入口,给定地址和对列表及其入口的所有引用都被解析。
这个列表进程可以用于任何静态初始化的数据结构。列表可以使用不同的关键字来创建和初始化数据结构或根本不使用关键字,只要可以识别出替换数据结构。超覆层的数目可以从仅仅一层到n层变化,n是大于1的整数。列表的合并可以由正常的链接程序甚至编译程序来执行。
采用列表进程,可以正常地创建数据结构。另外,考虑到“核心”、“产品系列”和“平台”区别,可以完成不止一层的替换。
程序开发系统100还提供一个根据构件内其他库的存在将库包括在构件中的机制。加载库是一个与现有技术的加载库类似的动态触发的加载库,因为库的整个代码集都包括在构件中。搜索库是一个动态触发的加载库,提供一个与现有技术的搜索库类似的用于有条件地将代码包括在构件内的机制。这两种类型的库之间的不同在于所用的引用类型。
搜索库使用一个“前向”引用来将库代码包括在一个构件中。例如,如果库A依赖于搜索库B中的一个目标,则来自搜索库B的目标代码将包括在构件中。另一方面,动态触发的加载库使用一个“后向”引用来将库代码包括在一个构件中。例如,当库A在一个构件中时,库B将声明它应该被包括在构件中-即使库A不依赖于库B。
需要三个事情来实现动态触发的加载库:配置脚本、触发命令和构件脚本发生程序。需要配置脚本来识别哪些模块要被包括在最终产品中。这可以是一个简单的MAKEFILE,或者可以是一个仅仅列出模块名的自定义文件。
“外部触发”命令根据外部标准与要被加载的库相联系。例如,一个专用文件(ModuleY.INF)可以与触发组件相联系。INF文件包括一个外部触发命令,指示如果例如“ModuleX”已经被包括则“ModuleY”应该被包括在最终产品中。虽然在这个例子中触发声明是在一个.INF文件中作出的,但触发声明也可以被包括在库的代码内的任何位置。脚本发生程序的职责仅仅是定位这些声明并正确地使用这些声明。
构件脚本发生程序的主要任务是产生一个用于建立可执行产品的MAKEFILE(或适当的编译程序/链接程序脚本)。发生程序使用所有潜在的库的INF文件和配置脚本作为输入。在脚本产生阶段期间,发生程序根据外部触发确定是否应该将库包括在最终构件中。MAKEFILE的使用假定利用这样一个脚本的工具的使用。然而,这不是一个必要条件,可以用任何制造商的构件工具来替代以获得相同的效果。
动态触发的加载库的使用提供了在不需要直接修改触发模块代码或构件脚本的情况下将库包括在产品中的能力。随着库的数目和模块之间的互相依赖性增大,还可以发现动态触发的加载库的好处。例如,当设计者从400个可能的选择中选择将20个模块包括在一个软件方案构件中时,难以知道什么“后向”引用的库可能存在。外部触发的加载库解决了这个问题,因为后向引用的库将其自身带入最终产品中。
在程序开发系统100中,一个实用程序可以扫描系统的源代码文件,以检测和记录公共声明和外部引用。公共声明和外部引用是源代码文件中的可扫描的关键字。创建一个将用作源代码库的源文件的列表(与假定在构件中的那些文件相对)。
如上所述,一个实用程序可以解析对在源代码中检测的公共声明的外部引用。与一个链接程序类似,实用程序首先在假定在构件中的文件中找到对外部声明的引用。它尝试以假定在构件中的、其后跟着库中的文件的文件解析这些引用。这是一个递归进程;将一个文件或模块带入构件将引用其他文件或模块。这个解析进程需要输出将作为构件一部分的生成的源代码文件的列表。随后可以进行正常编译和链接,不需要创建目标库。
在产生的列表中,可以将文件列在一个makefile、批处理文件或命令行应用程序中,就象为目标库的创建所完成的一样。一个集中的列表可列成方案的库文件表。对公共声明的外部引用的解析可以在开发和构件的交替阶段完成。可以在源代码文件的编辑期间动态地完成以便实时地反馈给设计者,或者可以在单个文件编译之后完成,利用编译输出来提供公共和引用信息。另外,可以从一个批处理文件或对命令行链接执行的列表输入来完成要编译和链接的目标模块的列表。
列表和解析帮助节省开发时间。首先,它们帮助防止开发者在调试故障涌出期间错误地看到错误的源代码,因为实际的文件及其位置将被列出并且可以看到。用在构件中的具体文件的知识也帮助开发者检测问题特征遗漏或增加的不想要的特征的位置。其次,开发者还在建立系统之前得到未解析引用的直接反馈。这节省了开发时间,因为当链接完成时未解析的外部引用通常只在建立进程的末尾处报告。
程序开发系统100还通过消除指定include文件所在位置的需要来提供对包括一个具体特征类的文件的源代码的适应性。在程序开发系统100中所用的源代码文件中,可以有一个include文件的宏类和文件名。include文件列出其在一个宏内的类信息。在编译之前,扫描源代码文件,并由一个系统实用程序确定适当的include文件的位置。
系统实用程序源代码文件包括一个静态系统确定名字的局部include文件。这个所包括的文件由系统在源代码的编译之前动态地创建。源代码文件在列出这个宏之前列出一个局部固定名字include文件。
使用系统扫描实用程序,将在编译前对上述定义的宏扫描软件系统的源代码树。系统配置实用程序使用从扫描该系统检索到的信息并用所找到的include文件调解文件的类信息。系统实用程序产生一个对于源代码文件是局部的include文件。所产生的局部include文件提供宏扩展来指定所包括文件的物理位置。系统实用程序还用include相关性的正确位置来动态地创建makefile。
为了保持对位于不同位置的include文件的改变的控制,可以使用一个版本方案(scheme),这里源代码文件和include文件都把所包括的文件的版本列为其宏的参数。系统实用程序确认它们是兼容的。
使用这个系统,源代码不需要知道将使用哪一个include文件,并且系统的部署不需要手控地指定它。这在带有include文件的多形特征中或不同位置中的特征的多个版本(升级…)中是有利的。系统实用程序自动地把include文件解析为恰当的文件。类信息防止相同名字的include文件的多个例子成为问题。
下面的描述提供一个对程序开发系统100的更详细的描述。图11展示了程序开发系统100的概观,着重于至、自和在例程(图的中间)与管理图形用户界面200的设计者之间、进入完成的产品1106(图的左下角)的信息流(图的右侧)。数据流由双线箭头指示,例程命令路径由单线箭头指示。在图11下面的描述将主要重点放在本发明的数据、数据结构和数据流方面。
最初,在诸如一个固定磁盘驱动器的介质上的一个目录内设置组件源代码库1200。在该库目录内,将子目录分配给软件产品的每个组件。在每个组件的子目录下,为特征设置子子目录,每个子子目录包含对应于该特征的一个或多个源代码文件,在特征子目录的第一层下面的进一步的子目录可以定义子特征,等等。每个组件子目录还包含一个“component.inf”文件1400,该文件定义一特定组件如何被编译和链接、它可以、必须或必须不用于何种类型的平台等。每个特征子目录还包含一个“feature.inf”文件1600,该文件其中定义一特定组件如何被编译和链接、它可以、必须或必须不用于何种类型的平台等等。由这些文件支持的选项将在下面结合图14到17的描述中更详细地描述。
数据库更新例程400扫描所有这些文件,并建立数据库1800,则数据库1800包含从传送到将宏插入源代码文件的所有专用宏调用的变元提取出的信息,并加上从“feature.inf”和“compnent.inf”收集的所有信息。这个数据然后可以由配置程序过程700访问。特别地,将数据库系统设计和构造为使得它可以回答下面的问题二什么是组件?什么是特征?对于一个目标(组件或特征),什么是其相关性、包括函数相关性(跳转,调用,等等)、选项和include文件相关性?什么是其接口、包括过程、标号和列表?什么是其选项?什么是其文件?什么是其细节?它可以展示组件和/或特征的一个列表,其在最终产品中的内含由一专用触发类型所触发,例如:外部触发(如果Y在内,X必须在内);推荐触发(对服务器使用推荐的);以及,“随选”触发(因为组件Z要求其存在,所以它必须在内)。它可以确保一个(由名字、路径、数据和时间标记识别的)文件存在。它还可以展示关于一个由名字识别的具体选项的信息。最后,它可以展示一个指定选项的“Enums”(或列举的数据名和值)的列表。
配置程序过程700利用从数据库1800取出的信息和从产品配置文件“platform.cfg”2100取出的信息来创建用于定义所完成产品的配置的配置状态数据。在最佳实施例中配置程序700是用C++写的,配置程序700将这个信息保存在类的C++RAM数据结构中(在字类的C程序设计的意义上),如图32所示。如图所示,可以将任何数目的产品配置3202存储在这个RAM数据结构中。每个这样的产品配置可以链接到任何数目的类3204(在本发明的意义上)、组件3206和特征3208。类3204也可以链接到任何数目的组件3206和特征3208(注意,如果组件不与一般都不相联系的源代码文件相联系,则组件不需要被分配一个类)。每个特征3208可以链接到任何数目的子特征3208。组件3206和特征3208可以与文件3214(源代码文件和include文件)相联系,也可以与选项3210(例如,在常规“include”文件中在形式上例如表示为“START_DELAY EQU 12”的类型的等式或明显常数)相联系。在源代码文件3214的情况下,每个可以链接到任何数目的相关性3216(“include”,“选项”,宏和函数,其中,函数包括列表、标号、函数调用和串)以及任何数目的接口3218(可以被公共(在组件之间)或私人(将访问限制到父和同层)引用的东西,例如过程)。这样,源代码文件中的名字的“可视性”首先由类来限制,然后如果名字没有声明为公共的,则由组件/函数(父/同层)关系来限制。在选项的情况下,任意的选项可以象在Pascal计算机程序中一样可选地被分配一组列举3212,每个列举被分配一个数值,例如“Fast=3;Slow=2;Off=l”,来展示一个简单的例子。然后可以将列举菜单通过用户界面展示给设计者(当“修改”选择由图33E中显示的菜单3338作出时)。
图11中的图形用户界面200将在别处更详细地描述。简要地概括,设计者在206可以双击代表源代码文件“feature.inf”和“compnent.inf”的图标,从而可以编辑任何文件,然后将自动调用放在数据库更新例程400、配置程序例程700和图形配置显示212以更新数据库1800、配置状态数据1900和用户显示(图33A)。在208上,设计者可以使用所提供的工具来引用并搜索各种命名的系统组件,引用它们并在库中导航来寻找它们可能被定义的地方,然后其定义可以如刚刚所述的被查看和修订。在210,设计者可以调用配置程序过程700以修改所完成产品配置,并将改变忠实地记录在配置状态数据1900中(如图19中所示的“X”中)和磁盘驻留(disk-resident)产品配置数据文件2100“platform.cfg”中。再次在图形配置显示212上显示所有这样的改变。
最终用户命令是图11中的用户建立的请求命令214。如先前结合图7解释的,这个命令使用户选择的和系统选择的配置状态数据(如图20中显示的(与图19比较))被提供给产品make例程800(在图8中概述并在图34中更详细地描述的)来首先构造组件make文件2400和产品make文件2500,它们一同控制编译和链接的所有方面,并且也使对应于每一个特征以及特征相关性的打开和关闭(包括或排除“调用”等)的特征include文件2300“feature.inc”被构造或更新。
当已经完成了其工作时,图11中的产品make例程900简单地调用一个标准Unix make实用程序来执行产品make文件2500,并且由此放入执行在图10中的概述中描述的产品构件例程1000,该例程1000调用编译程序、汇编程序和链接程序,以便在单个组件make文件的控制下为每个和所有组件创建构件产品组件文件1104,并根据需要由特征include文件2300为每个单个特征修改源代码。
最后,调用图11中的产品组件链接程序3600,以接受所建立产品组件文件1104,从中去除包含在专用宏产生的段中的打算在其执行目标代码图象的最终“修订”时控制产品组件链接程序的数据,将它们一起缝合成一个完全链接的单一ROM图象,将以名字和类进行的调用用对ROM图象中的绝对地址的正确调用来替代,将列表组件从其专用段中检索出来、组织成独立列表、根据命令排序,并在所指示的位置插入正确的代码段,将选项完全解析,并完全地完成链接的所有其他最终步骤。这样,产品组件链接程序产生准备安装到EEPROM或闪速ROM等中的所完成产品1106。
图l2显示了组件源代码库1200的总体结构。这个库在计算机或服务器的硬盘驱动器上在任何常规的根目录中构造。在最佳实施例中,所有系统单元必须驻留在这个根目录的范围内,该根目录是由数据库更新例程400扫描的磁盘驱动器的唯一部分。
可以有任何数目的系统组件。每个组件驻留在分配给该库的根目录内的其自己的子目录中。在图12中,文本行的框线结构象征性地代表存储东西的目录和子目录的级别,矩形围绕着单个子目录及其内容。
因此,图12中的根目录是源库A 1202。由数据库更新例程400扫描这个源库内的每个内容。在这个根目录内显示了两个子目录,一个分配给组件A 1202,一个分配给组件B 1206。每个组件子目录包含一个组件信息文件。组件A的子目录包含一个组件A信息文件1400(其细节在图14中显示),组件B的子目录同样包含一个组件B信息文件1210。每个组件子目录还包含一个或多个特征子子目录。在图12,组件A子目录包含两个特征子目录1212和1214。如图所示,每个特征子子目录包含特征源代码文件1300、1220、1224和1226及特征信息文件1600和1222。参考特征1子子目录,它包含其细节在图16中显示的特征1信息文件1600和其细节在图13中显示的特征1源代码文件A。
图13展示了源代码文件“BEEP.ASM”,着重于带有本发明的宏调用的汇编语言源文件。该文件被用于显示配置显示(图33A)并且它在组件源代码库1200的位置显示在附录A中。
用于本发明的所有源文件应该包括“SYSTEM.INC”1306,它包括本发明使用的其它include文件。尤其是,这些include文件包含可以用来实现本发明的许多方面的专用宏。用于本发明的所有源文件还应该包括“FEATURE.INC”1308,由产品构件准备(图9)产生的特征include文件,为每个特征建立一个特征include文件(图35构件A特征Include文件)。由本发明为特征BEEP建立的、包含在BEEP.ASM中的特征include文件在图23中显示。如将要解释的,“FEATURE.INC”include文件包含控制由宏PUBEXT 1312和EXTCALL1318产生的代码的宏变量,它允许设计者直接控制过程的链接而不需要改变源代码。
PUBEXT宏1312利用接口版本1.0在类TIMER中声明一个外部过程DELAY。宏名字本身声明该过程是一个由包含在单独链接的组件中的PUBLIC_PROC宏来定义的过程。这些引用将由产品组件链接程序修正(图36)。PUBEXT宏将在下面展示的宏的逐行描述的节2.1中描述。
PUBLIC_PROC宏1316用接口版本1.0在类BEEP中定义一个外部过程ERRORBEEP。宏名字本身将该过程定义为能够在用PUBEXT宏声明它的单独链接的组件中引用。PUBLIC_PROC宏在宏的逐行描述的节3.1中描述。如将要解释的,在编译和汇编之前由该宏将类名称替换为绝对库地址。
EXTCALL宏1318使用它在PUBEXT宏1312中声明来调用分配给类TIMER的外部过程DELAY。因为这个过程在一个单独链接的组件中定义,所以对它的引用将由产品组件链接程序修正(图36)。EXTCALL宏在宏的逐行描述的节1.1中被描述。
END_PROC宏1320结束由PUBLIC_PROC宏1316打开的过程。它在宏的逐行描述的节3.3中被描述。
每个目标、即一个组件或特征具有一个相应的信息文件,可以表示为.INF文件。这些信息文件的目的是包括不能从树结构或汇编文件扫描导出的、由BIOS工具或由为其使用所开发的软件产品的任何工具所需的信息。一个数据库更新进程扫描这些.INF文件和汇编文件以收集信息并将其放进一个中央数据库。
在每个组件尖端包括一个组件信息文件(COMPNENT.INF)。将一个特征信息文件(FEATURE.INF)包含在一个组件或特征目录的每个子目录内。由于COMPNENT.INF和FEATURE.INF在视觉上看是相同的,因此下面的描述仅仅将其作为INF文件,只在存在不同时才区别这两种类型。一般地,INF文件中的信息包括目标名和相关的库或二进制、关于目标的自由流动(free flowing)的描述信息、目标所属的类或子类以及选项声明。
每个INF文件可以包括一个或多个命令。这些命令最好不是敏感的情况并且不超过一行。另外,最好每行只有一个命令。注释可以通过在前面放一个标识符、例如“//”来单独放在任何行上或放在任何命令行的末尾。
可以用在INF文件本身内的命令可以是可选的、必需的或条件必需的。另外,一些命令可以只用于组件信息文件或特征信息文件。在可选命令中有BringUp(培养)命令。这个命令用于识别出,目标应该包括在在PLATFORM.CFG文件中识别为“BringUp”的平台BIOS中。它用于帮助以引导一个母板所需的最少目标来迅速地配置一个BIOS。当这个命令被添加到PLATFORM.CFG文件时,只有将系统引导到DOS所需的目标被安装在BIOS中。
Class(类)命令是一个条件必需的命令。它提供目标所属的类的名字。每个INF文件只允许有一个类或子类。一个目标的公共过程由其前缀有其类.子类[.子类…]路径的函数名引用。不需要一个组件来声明一个类。然而,如果其父目标声明一个类或子类,则需要一个特征来声明一个类或子类。换句话说,特征信息文件中的Class命令是条件必需的,这取决于其父目标是否声明一个类或子类。
Classification(分类)命令只运用到组件信息文件上,但对所有组件信息文件都是必需的。这个命令用于指定允许例如利用BIOS工具对组件排序和分类的信息。Classification命令可以包括一个或多个字段名,例如ComponentType(组件类型)、DeviceVendor(设备厂商)、DeviceAlias(设备别名)、PartNumber(零件号)和Category(类别)。
ComponentType字段名的值是硬件或软件,并且在Classification命令中总是必需的。DeviceVendor字段名定义厂商,只对硬件组件类型是必需的和可用的。DeviceAlias字段名定义该组件类型的一个公知别名,只对硬件组件类型是可选的和可用的。PartNumber字段名定义组件零件号,只对硬件组件类型是必需的和可用的。Category字段名用于定义设备或软件组件所适合的类别,对于软件和硬件组件类型都是可选的。
CompileUsing(编译使用)命令是一个可选命令,对于指定扩展名识别要用在组件的MAKEFILE中的自定义编译命令,来代替由COMPMAKE产生的缺省命令。这个命令包括三个字段:Command(命令)、SourceExtension(源扩展名)和DestinationExtension(目的扩展名)。例如,Command字段是一个具有识别具体文件信息应该位于哪里的参数和用于其它控制信息的参数的自定义DOS命令。SourceExtension字段提供一个应该受自定义命令作用的源代码文件的文件扩展名。DestinationExtension提供一个由自定义命令创建的目的文件的文件扩展名。
CoreVersion(核心版本)命令是一个必需的命令,识别使目标是兼容的核心版本。这个命令可以包括一个或多个值,每个值代表一个兼容的核心版本。
Description(描述)命令是一个必需的命令,提供可以由高级接口使用的文本注释以提供关于被描述的组件、特征或选项的细节。例46 如,描述在长度上最大可以到512个字符。
LinkUsing(链接使用)命令是一个可选命令,识别在组件的MAKEFILE中使用的自定义Link(链接)命令,来代替由COMPMAKE产生的缺省命令。与CompileUsing命令一样,LinkUsing命令包括提供与上述相同的功能的Command字段、SourceExtension字段和DestinationExtension字段。
Name(名字)命令是一个必需的命令,提供目标的名字。Name命令中的指定目标名字的标识符可以是长度例如为40个字符的字母数字串,并且最好不要以数字开头或包含空格。
Option(选项)命令是一个可选命令,它声明一个可配置选项并给它一个缺省值。设计者可以使用PLATFORM.CFG文件改变选项的设置。这个命令支持用于提供选项的所支持值的描述性名字的“主体”部分。这些名字可以用来替代用于声明缺省值或改变PLATFORM.CFG文件中的值的数值。值名字应该在一个单独的行上定义。主体部分的排除(exclusion)表明只有数值可以用于设置该值。
除了定义选项名的名字字段之外,在Option命令中还有几个其他字段。DefaultValueName(缺省值名)字段提供一个如在主体部分定义的有效“值名”,该字段在值名已经在命令的主体部分中定义时是必需的。Default_numeric_value(缺省数值)字段提供一个最好不超过指定长度的有效数值。当列举名存在时,可以不使用数值来作为缺省。Size(尺寸)字段指定选项空间的尺寸。RomEditDescription(Rom编辑描述)字段是一个如果由设计者在PLATFORM.CFG文件中选择“Romedit”则保存在ROM中的选项描述串。ValueName(值名)字段是一个在设置选项值时可以用来替换一个数值的描述性名字。Value(值)字段代表与ValueName相联系的具体数值。ValueDescription(值描述)字段提供了对值的含义的文本描述。
Owner(所有者)命令是一个必需的命令,提供目标所有者的公司名字。这个命令在将核心树释放或复制到客户处时用于过滤客户的组件。
PlatformType(平台类型)命令是一个可选命令,根据PLATFORM.CFG文件的平台类型标识描述一个目标何时应该被缺省包括在一个构件中。这个命令包括一个或多个PlatformType(平台类型)字段,每个字段具有一个相应的Usage(使用)字段。PlatformType字段例如可以是基本PC、桌面设备、服务器、笔记本、PICO或其他。
Usage(使用)字段用于描述在构件中包括一个目标的条件。如果是“推荐”,则缺省带入一个目标,但设计者可以手动地从构件中去除该推荐的目标。如果是“测试”,则将一个目标用缺省包括在构件中来用于测试目的,但将从产品版本中排除。“随选”,在需要时将一个目标自动带入以解析硬外部引用。对于“明确”,则对于相关的平台类型,防止一个目标被包括在构件中,除非将其明确增加在PLATFORM.CFG文件中。“外部触发”识别一个将触发一个目标被包括在构件中的类.子类的名字。
对于一单个平台类型,一个类可以将“外部触发”与“随选”或“推荐”合并。然而,对于一单个平台类型,Usage字段的其他任何合并都是不允许的,将产生一个确认失败。此外,对于一单个类只有一个目标可以在核心文件内声明其自身随选、推荐或外部触发。否则,对相关性有不止一个缺省解析将导致一个确认失败。在一单个组件内,只有一具体子类的一个特征可以声明其自身随选、推荐或外部触发。有不止一个将导致对相关性的多个解析,将产生一个确认失败。
ShieldPrivates(屏蔽私人)命令是一个可选命令,保护一个目标的私人过程不被其同层目标访问。这个命令对用作功能不相关的混杂目标的储存库的目标是有用的。图41显示了ShieldPrivates命令如何进一步将代码访问限制在私人访问层之外。该图显示了如何将函数调用的访问压缩到其适当的层上,即公共、私人或屏蔽在任何特征层。这运用到相关性,包括过程、标号和include。
SubClass(子类)命令是一个条件必需的命令,提供一个特征所属的子类的名字。只允许每个INF文件有一个类或子类。一个目标的公共过程由其前缀有其类.子类路径的函数名引用。如上面相对于Class命令所述的,如果其父目标声明一个类或子类,不需要一个组件来声明一个类,而是需要一个特征来声明一个类或子类。
Target(目标)命令是一个只可应用于组件信息文件的可选命令。这个命令提供应该从建立特定组件产生的库或二进制的名字。Target命令包括一个TargetName(目标名)字段和一个TypeKey(类型关键)字段。TargetName字段定义一个字符文件名。TypeKey字段是一个用于识别非标准类型的文件的四字符代码。这个代码由BIOSMAKE实用程序用于引用这些文件的调度表的修正。
Uses(使用)命令是一个可选命令,用于识别由所描述的目标使用的共享代码的位置。构件工具可以使用这个命令来将文件识别为在为该目标创建的MAKEFILE中的相关性。共享文件的使用受到限制。特别地,目标可以只使用例如利用带有“共享”属性的PRIVATE-PROC或PRIVATE-INCLUDE命令将其自身识别为共享的文件。另外,目标可以只使用在同层目录、或上游目录节点的最接近的子目录中的共享源文件。Uses命令包括一个提供要由目标使用的共享文件的相对路径和文件名的FilePath(文件路径)字段。
图14展示了在附录A中路径C:\BIOS\CORE\COMPNENT.INF所示的类CORE 1406的组件信息文件。这是包含特征BEEP的组件(图16),它包含源代码文件BEEP.ASM(图13)。本发明的这部分包含描述组件的命令和用在组件的配置中的命令(图15)。
BRINGUP命令1412指示,当使用本发明的用户开始建立一个具有最小功能性的新的BIOS以便迅速地启动时,这个组件应该包括为配置的一部分。
PLATFORMTYPE命令1424指示,当建立在IA32体系结构上运行的产品时可以使用这个组件。ALLOTHERS命令1428指示,这个组件对于在PLATFORMTYPE命令1424中没有明确指定的所有平台类型都是RECOMMENDED(推荐的)。这个CORE 1406组件将包括在运行在IA32体系结构上的由本发明产生的全部配置中,除非它被明确地取出。
图15显示了本发明的在组件的配置中使用的一个组件信息文件中的那些命令。粗体的名字是关键字,不是粗体的名字由设计者指定。字符“//”表明该行的剩余部分是注释。位于一个命令的大括号{}之间的所有命令都被认为是在该命令的范围内。
PLATFORMTYPE命令1506指定了规则,在这些规则下组件将被包括在配置中。这些规则应用于一个具体平台类型例如“桌面设备”或“笔记本”的配置或应用于没有明确提到的任何平台类型(ALLOTHERS)。规则1516包括RECOMMENDED(推荐):除非明确地从配置中取出外包括组件,ONDEMAND(随选):当组件中的一个过程由另一个已经在配置中的组件引用时包括组件,EXPLICIT(明确):仅仅当明确地强行放入配置中时包括组件,以及EXTERNALTRIGGER(外部触发):当由ClassPath指定的组件或特征在配置中时包括这个组件。
OPTION命令1522定义了可以在包括一个组件的源代码文件中使用的一个选项的名字和缺省值。它也可以定义可以在产品配置中指定的选项的可接受值的名字(图22)。
图16展示了在附录A中路径C:\BIOS\CORE\BEEP\FEATURE.INF上所示的类BEEP 1602的特征信息文件。这是包含源代码文件BEEP.ASM的特征(图l 3)。本发明的这部分包含描述特征的命令和在特征的配置中使用的命令(图17)。
BRINGUP命令1612指示,当使用本发明的用户开始建立一个具有最小功能性的新BIOS以便迅速地启动时,这个特征应该包括为配置的一部分。
PLATFORMTYPE命令1616指示,当建立在IA32体系结构上运行的产品时可以使用这个特征。ALLOTHERS命令1620指示,这个特征对于在PLATFORMTYPE命令1616中没有明确指定的所有平台类型都是RECOMMENDED(推荐的)。这个BEEP1602特征将包括在运行在IA32体系结构上并且包括CORE组件的由本发明产生的全部的配置中,除非它被明确地取出。
图17显示了本发明的在特征的配置中使用的一个特征信息文件中的那些命令。粗体的名字是关键字,不是粗体的名字由设计者指定。字符“//”指示该行的剩余部分是注释。位于命令的大括号{}之间的所有命令都被认为是在该命令的范围内。
PLATFORMTYPE命令1706指定了规则,在这些规则下特征将被包括在配置中。这些规则应用于一个具体平台类型例如桌面设备或笔记本的配置或应用于没有明确提到的任何平台类型(ALLOTHERS)。规则包括RECOMMENDED(推荐):除非明确地从配置中取出外包括特征,ONDEMAND(随选):当特征中的一个过程由另一个已经在配置中的组件引用时包括特征,EXPLICIT(明确):仅仅当明确地强行放入配置中时包括特征,以及EXTERNALTRIGGER(外部触发):当由ClassPath指定的组件或特征在配置中时包括这个特征。
OPTION命令1721定义了可以在特征的源代码文件中使用的明显常数的名字和缺省值。它也可以定义可以在产品配置中指定的选项的可接受值的名字(图22)。
PLATFORM.CFG文件是一个文本文件,指定对一个构件的定制,并包含引导构件的语句。在PLATFORM.CFG文件中,OEM可以包括信息以识别OEM特征、OEM异常分支和OEM文件超覆。并且,虽然PLATFORM.CFG文件由用户界面200保存,但它是一个可编辑文件,允许设计者明确地指定配置参数。
PLATFORM.CFG文件包括BIOS的一个最少描述。根据这个信息,配置程序700可以导出对BIOS配置的一个更全面的描述。例如,如果设计者明确地声明一个组件应该被包括在构件中,则配置程序700可以确定另一个组件或特征应该也被包括在BIOS中,即使在PLATFORM.CFG文件中没有明确声明。
有几个与PLATFORM.CFG文件相关的命令。BuildOption(构件选项)命令指定专用于一特定软件产品的构件的信息。在BuildOption命令主体内的命令指定要存储的信息的细节。这些命令包括指定构件选项的类型的Type、指定构件选项正运用到的项目的名字的Name以及指定项目被设置的值的Value。
BringUpBios命令用于指示一专用配置超覆。这个专用超覆指导配置程序700建立一个只包含提出最小BIOS所需的单元的最小集合的最小BIOS。BringUpBios命令可以在PLATFORM.CFG文件中只出现一次。
Classfication命令指定平台具体信息。这个信息可以将一个名字或值定义到一系列平台具体数据,包括厂商名、别名、平台号、修订或版本号以及类别。
Component命令指定任何组件由构件中的增加、配置或去除,而不考虑所想要的平台类型。组件的配置由在Component命令中指定的Feature(特征)、Options(选项)、SystemOptions(系统选项)、Files(文件)和OverrideFiles(超覆文件)来定义。当根据标明的平台类型引入缺省时,组件不列在PLATFORM.CFG文件中。
Component命令最好包括一个ForceFlag(强迫标志)。这个标志指定是否将一个组件强行放入构件、从构件强行拿出或设置为使用缺省构件包含相关性和触发。当该标志设置为ForceIn(强行放入)时,将其与组件的任何现有的缺省定义相合并。当组件被设置为NoForce(不强迫)时,将还原其缺省状态,表明它依赖于其他相关性和触发选择。当组件被设置为ForceOut(强行拿出)时,表示不包括在构件内。
每个Component命令还包括一个要被带入系统的组件的名字。用在该命令中的名字是从所命名组件的.INF文件导出的。由于每个组件最好具有一个唯一的名字,所以在组件命令中命名的组件中应该没有含糊。
在一个Component命令的大括号内的描绘Component命令内所包括的内容的所有命令都被认为是在所命名组件的范围内。这些命令的例子包括Feature、Options和SystemOptions命令。组件本身可以不放在其他组件内。另外,Component命令对于每个唯一的组件可以只出现一次。换句话说,不能有两个或更多的Component命令来描述同一个组件。
Feature命令允许一个特征在一给定组件内的增加、配置或去除。在该命令中命名的特征对于其位于的组件必须是有效的。类似于一个组件,特征的配置由在Feature命令内指定的Features、Options、SystemOptions、Files和OverrideFiles来定义。此外,类似于Component命令,Feature命令包括一个ForceFlag,指定是否将一个特征强行放入构件、从构件强行拿出或设置为使用缺省构件包含相关性和触发。
虽然所有特征必须位于一个组件定义内,也可以在另一个特征的定义内定义特征。当一个特征在另一个特征内被指定时,内部特征变成子特征,外部特征变成父特征。一个特征内的所有命令被认为是在该特征的范围内,同时也在定义特征的组件的范围内。可以放在一个特征的大括号内的描绘Feature命令中所包括的内容的命令或语句的例子包括Feature、Options、SystemOptions、Files和OverrideFile。
File命令允许一个附加文件被包括在一个构件内。这个命令可以只用在一个组件或特征的范围内。在File命令中包括的参数包括FileName(文件名)和FilePath(文件路径)。FileName定义要带入构件中的文件的名字。Filepath提供要带入构件中的文件的相对物理位置。
Option命令指定一个将用于产生组件和特征include文件的选项的设置。Option命令可以只用在一个组件或特征的范围内。在Option命令中包括的参数包括Name(名字)、Value(值)、RomEditFlag(ROM编辑标志)和Description(描述)。Name参数定义要改变的选项的名字。Value参数列出由.INF文件中的选项定义的任何有效值。RomEditFlag参数是一个布尔值,列出对该选项是否允许RomEdit(ROM编辑)。Description参数是一个选项参数,提供可以在RomEdit实用程序中显示的对选项的描述。
OverrideFile(超覆文件)命令超覆一个组件文件。如果超覆失时效的,一个文件版本允许向设计者显示一个警告。这个命令可以只用在一个组件或特征的范围内。新超覆文件的名字必须与被超覆的文件相同。OverrideFile命令中的参数包括提供超覆文件的名字的FileName(文件名)、提供超覆文件的相对物理路径的NewPath(新路径)以及提供初始文件的版本的OriginalVersion(初始版本)。
PlatformType命令指定构件的平台类型。这个命令用于根据指定的平台类型带入缺省组件和特征。只有一个PlatformType命令可以用在PLATFORM.CFG文件中。PlatformType命令中的参数包括定义平台名字的Name(名字)和由CPU和指令集确定的、指定将执行相同代码的一组系统的Architecture(体系结构)。Architecture参数例如可以是用于IA-32指令集体系结构的IA32或用于IA-64指令集体系结构的IA64。
SystemOption命令用于建立一个在构件描述的整个范围内可见的选项。预定义的选项可以在处理的不同级、例如全局级、组件级或特征级被设置或重新设置。SystemOption命令中的参数包括Name(名字)和Value(值)。Name参数给出要与构件描述相联系的SystemOption的名字。该名字必须是一个预定义选项集合中的一个。Value参数列出与所命名的SystemOption相联系的值。
图18示意性地展示了用于源库A的组件数据库1800的代表。用于每个组件的数据被显示为包含在一个方框内。显示了两个组件、组件A 1802和组件B 1804,假设其他组件也存在但为了清楚和简单起见省略了。只显示了用于组件A 1802的数据的细节。
每个组件具有一个名字和一个描述(行1806)。每个组件具有一个数据选项表,该表列出影响这个组件内的源代码文件的所有用户可设置的选项1808。这些选项通过使用用户界面调整(例如,参见图33E),选项值在链接程序3600建立所完成的产品1106时由产品组件链接程序3600(图36)作为“修正”进程的一部分来实际加载进二进制图象。存在为一个组件指定的任何编译、汇编和链接选项1810。
如果其目录包含源代码文件,可以用其“component.inf”文件将一个组件分配到一个类,但最佳实施例的实践是将源代码文件放进特征子目录中,并用其“feature.inf”文件将每个特征分配到一个类。因此,所有特征都被明确地分配到一个类。因此,如图所示,几个特征可以由数据库内的类进行组织。显示了两个类、类A 1812和类B1814。在类A 1812内有两个特征,特征1 1816和特征2 1818(未显示特征2的细节)。推测起来,任何正常系统可能具有许多特征以及子特征等。特征1 1816具有一个名字和描述1820、一个数据选项表1822(与用于组件的实质上相同,但可应用于特征源代码文件)、编译程序和链接选项1824(如果特征源代码文件被单独编译、汇编和/或链接)、特征源代码文件的名字1826以及进入1828和退出1830这些源代码文件的入口和出口的完全列表—在别处,更准确地称为接口和相关性。
图19和20是在配置状态数据1900内包含的数据结构的示意代表,其组织与图18所示的数据库类似。显示了三个组件—组件A 1902、组件B 1904和组件C 1906,每个组件带有一个以带有或不带有“X”的投票框来象征性地表示的“选择”或“未选择”标志,以指示一给定组件是被选择还是未被选择包含在所完成的产品1106中。用于组件A和B的标志1922和1930被显示为带有“X”,表明这些组件是所完成产品1106的当前部分。用于组件B的标志1928被显示为不带有“X”,表明或者是缺省,或者是因为系统设计者的干预,这个组件未被选择。组件A具有一个名字和描述1908,它具有两个特征,其标志1924指示它还未被选择的特征1 1910和其标志1926(以“X”)指示它已经被选择的特征2 1912。特征1 1910显示为具有一个类分配1914、分配给它的源代码文件1916、选项定义1917和引用1919一相关性和接口。(RAM内的这个数据的结构的更详细的视图将展示在下面的图32中,这已经在上面描述过。)
图19仅仅显示了在创建一完成产品1106时所选择的组件和特征数据2000被从配置状态数据中取出并传送到产品make例程900。如图所示,选项的全局常数被传送以便用作由产品组件链接程序3600加到所完成产品1106上的“修正”数据的一部分。将所选择的组件A 2002和C 2004与作为被选择的组件的一部分的被选择的每个特征的特征数据一起传送。所选择特征2 2006对应于图19中的设置了其选择标志1926的特征2 1912。这个特征2 2006附带有其源代码文件的名字2998以及从这些源代码文件和其他相关性和接口的退出2008以及要分配给特征专用选项的特征专用常数2012。
图21展示了在附录A中路径C:\BIOS\DEVREF\INTEL\440BX\PLATFORM.CFG上显示的桌面平台2102的产品配置数据。这是包含组件CORE(图14)的配置。本发明的这部分包含在产品的配置中使用的命令(图22)。
PLATFORMTYPE命令2102指示该配置是针对运行在IA32体系结构上的平台类型“桌面”的。在其指定了桌面(规则)或所有其它(规则)的组件信息文件中包含PlatformType(平台类型)(IA32)命令的所有组件将被认为是依据其规则包含在配置中的。类似地,在其指定了桌面(规则)或所有其它(规则)的特征信息文件中包含PlatformType(IA32)命令的被认为包含的组件的所有特征将被认为是依据其规则包含在配置中的。
COMPONENT命令2104允许一个附加的源文件被配置给组件PNP。
FILE命令2108允许一个附加的源代码文件、来自当前组件源代码库中的目录\DEVREF\INTEL\440BX的MYFILE.ASM被作为组件PNP的一部分包括在配置中。
图22显示了本发明的平台配置文件中的可能的命令的列表。粗体的名字是关键字,不是粗体的名字由设计者指定。字符“//”指示行的剩余部分是注释。位于命令的大括号{}之间的所有命令被认为在该命令的范围内。
SYSTEMOPTION命令2202被用于建立一个可在产品配置中的任何源代码文件中使用的选项名字和值。FEATURE命令2216允许在一给定组件中的特征的添加、去除或配置。特征配置2212由本发明定义为在该特征的开和闭大括号{}中定义的那些Feature、Options、SystemOptions、Files和OverrideFile命令。
OVERRIDEFILE命令2216在组件或特征命令中用来超覆该组件或特征的文件而不是使用指定的新路径。OPTION命令2218在组件或特征命令中用于指定在该组件或特征信息文件中定义的选项的名字和新值。选项的新值将出现在为该组件或特征产生的特征include文件中。
图23展示了在附录A中路径C:\BIOS\CORE\BEEP\FEATURE.INC上显示的特征Include文件。这是当源代码文件BEEP.ASM(图13)被汇编时包括的特征Include文件。D_TIMER_DELAY变量是图13中的宏PUBEXT 1312(宏的逐行描述的节2.1)和EXTCALL 1318(宏的逐行描述的节1.1)所期望的定义名字(defineName)。
图24展示了本发明产生的附录A中的路径C:\BIOS\CORE\MAKEFILE上显示的组件CORE的组件makefile。组件CORE(图14)包含了包含源代码文件BEEP.ASM(图13)的特征BEEP(图16)。因为make程序在历史上已经在当前工作目录中寻找缺省命名MAKEFILE的文件,所以称为makefile,makefile包含由make程序解释的命令。
EXTASMS2404被定义为包含要被汇编的每一个外部汇编源文件的路径的宏。每一行末端的反斜杠\指示持续(continuation)。类属规则(generic rule)2436指定对把具有.ASM扩展名的任意文件转换成具有.OBJ扩展名的同名文件所需要的汇编程序命令行。COMPONENT_NAME规则2440指定链接来自从由宏EXTASMS和ASMS定义的所有汇编源文件产生的目标文件的组件的链接程序命令行。其副作用是,它使不存在的目标文件从使用类属规则2436的汇编源产生。CLEAN规则2456必须明确地在make程序命令行上指定(图25)。它删除由CORE组件makefile产生的文件,使得在下一次解释CORE组件makefile时,所有文件将被重新产生。
图25展示了由本发明产生的用于建立包含组件CORE(图24)的产品的产品makefile。BIOS.ROM规则2502转到包含配置中的每个组件的目录,并运行NMAKER make实用程序,以解释由本发明在该目录中产生的组件makefile。这将为每个组件产生目标文件“*.exe”文件的一个链接集合。这个格式允许组件作为一个统计工具来执行,被设计为显示所声明的公共接口、相关性和资源利用。然后可以由产品组件链接程序“BINLINK”3600(图36)将这些链接文件合并成一单个ROM图象可执行文件。
CLEAN规则2532转到包含配置中的每个组件的目录,并运行每个组件makefile的CLEAN规则(图24),然后转到包含平台配置文件的目录,并清除在构件过程中产生的文件,这样所有的文件将由下一个构件重新产生。
图26显示了扫描组件源代码库1200的数据库更新例程400。搜索在组件源代码库1200的根目录中开始2602以寻找组件,组件是包含一个命名为“COMPNENT.INF”2604的组件信息文件的根目录的子目录。对于每个组件2606,调用文件扫描例程2700以扫描组件信息文件2610和可能在组件目录中的任何源文件或include文件2612。搜索然后在组件目录中继续以寻找组件的特征,特征是从属于组件目录的包含一个名字为“FEATURE.INF”2614的特征信息文件的目录。对于每个特征2616,调用文件扫描例程2700以扫描特征信息文件2620和特征目录中的源文件和include文件2622。
图27显示了文件扫描例程2700。在由数据库更新例程(图26)调用以扫描一个文件时,文件扫描例程从数据库2716获得要被扫描的文件最后一次被修改的日期和时间,并将其与来自文件本身的最后一次修改的日期和时间进行比较2702。如果文件未改变,则不更新数据库2704。如果文件已经改变或文件扫描例程由改变输入例程206(图11)调用,则扫描文件2706。如果文件是一个名字为“COMPNENT.INF”的组件信息文件2708,将组件信息2709加5数据库2716中。如果文件是一个名字为“FEATURE.INF”的特征信息文件2710,将特征信息2711加到数据库2716中。否则,文件是一个源或include文件。将来自文件2714中的任何退出声明宏、入口宏、include宏和列表宏的参数的增加信息加到数据库2716中。
图28显示了配置程序过程2800的总体流程,从初始激活2900(图29)开始,通过产品配置3000(图30)继续,以指示有效配置(图33A)或不兼容接口、遗漏组件等等(图33B)的配置状态的报告2806结束。
配置程序过程2800的初始激活2900l;4从平台类型2102的产品配置数据2100检索开始。然后从数据库1800读出604在指定平台类型上允许的或必须遵循的与组件有关的所有组件信息,并在随机存取存储器中创建产品配置程序状态数据1900。产品配置程序状态数据1900包括每个特征的源文件和在这些源文件中的每个PUBLIC_PROC宏和PUBEXT宏的参数。由于每个特征由产品配置例程3000激活(3004,3008,3010,3014),由其源文件中的每个PUBEXT宏引用的过程被添加到未解析引用的列表。产品配置例程3000以下列步骤继续,注意3002不激活已经被指定强行拿出的任何目标(3335,2204,2210,2208)。
在步骤A3004,在产品配置程序状态数据1900中已经被指定强行放入的所有目标(组件或特征)(3333,2204,2210,2208)和它们的父目标被设置为激活状态。在步骤B3006,所有推荐的组件目标(1510,1514,1516)在产品配置程序状态数据1900中被设置为激活状态。在步骤C 3008,对于产品配置程序状态数据1900中的所有的激活的目标,所有推荐的子目标(1710,1714,1716)被设置为激活状态并重复。在步骤D 3010,对于具有指定为外部触发(1518,1718)的类的激活目标的每个组件目标或子目标,如果该类的一个目标在产品配置程序状态数据1900中是激活的,则外部触发的目标被设置为激活状态。在步骤E 3100,外部引用(图31)被解析并且保存未解析的引用和解析引用的不匹配版本的一个列表。在步骤F 3014,如果一个特征解析一个未解析的引用并且是随选的(1716)并且所有父目标是激活的或随选的(1516,1716),则产品配置程序状态数据1900中的目标和所有父目标被设置为激活状态,并重复步骤C、D和E,直到没有进一步的目标可以被设置激活或没有遗留未解析的引用。
解析(RESDUE)外部引用例程3100从一个未解析引用的列表取出一个由PUBEXT宏(宏的逐行描述的节2.1)声明的过程引用,并找到由PUBLIC_PROC宏(宏的逐行描述的节3.1)定义3102的具有一个匹配名字的所有过程。PUBEXT宏的名字参数和匹配的PUBLIC_PROC宏的过程名参数都是类路径,类路径包括类名、零或多个子类名和由句点分开的实际过程名。类路径用于识别在一个与包含其定义的源文件在组件源代码库1200内的位置无关的组件、特征和子特征的分层结构中的一个具体过程。类路径不与具有相同名字的其他组件中的过程相冲突,因为它们具有一个不同的类路径。如果有具有相同类路径的多个定义3104,则如果定义的PUBEXT宏指定一个组件名字3106,则选择所命名组件中的定义3108。并且,如果定义的PUBLIC_PROC宏指定INTERCEPT关键字3110,则选择该定义3112。否则,从未解析引用的列表中去除该引用,并返回一个找到多个定义的指示3114。如果找到一个匹配定义3116并且该定义在一个激活特征3118或随选(1716)标明的未激活特征3122的源文件中,则从未解析引用的列表中去除该引用,并返回成功3120。如果引用的PUBEXT宏指定ALTERNATE关键字3124,则使用由备用名(altname)参数3126指定的类路径并再次尝试3128。如果引用的PUBEXT宏指定OPTIONAL关键字3130,则不需要定义,从未解析引用的列表中去除该引用,并返回无定义3132。否则,从未解析引用的列表中去除该引用,并返回不匹配3134。
刚刚描述的图30和31展示了决定产品的激活特征的配置进程的一般算法。配置进程的详细说明在附录J和K中阐述。
图32在上面图11的上下文中进行了讨论。
图33A展示了在使用本发明来修改IA32体系结构3308的“桌面”平台的“POST services”组件3306的“Decompress Manager”特征3304中的源文件WORKADDR.ASM 3302时设计者将看到的视图。与显示目录分层结构的组件源代码库的物理视图相对,这是组件源代码库(图12)的逻辑视图,采用在图33F中所述的图标来显示组件和特征。图标显示出,“Fdisk”3310和“kcManager”3312组件已经被从构件强行拿出,而组件“Intel371ab”3314和“Intel440BX”3316已经被强行放入构件中。
图33B展示了设计者在使用本发明时看到的与图33A相同的组件源代码库的逻辑视图,其中组件“Fdisk”3310不再被从构件中强行拿出。(图33F中所述的)图标指示,组件“Fdisk”3310、特征“ata”3318和文件“FDSKINIT.ASM”3320具有错误,类“fdisk”3322中的函数“protocolTable”和类“pic”3324中的函数“SendE01”的公共函数相关性有错误。
图33C展示了使用图33F中所述的图标的在图33A和33B中所示的组件源代码库的另一个部分的逻辑视图。这个逻辑视图显示了使用本发明的系统设计者通过右击组件“Intel440BX”3330的特征“MemoryConfiguration”3328中的超覆文件“EARLYCFG.ASM”3326所看到的情况。它还显示出文件“oemfile.asm”3332是一个采用在图33D中所示的本发明的窗口的“增加自定义文件”行添加的自定义文件。
图33D展示了采用图33F中所述的图标的图33A所示的组件源代码库的部分的逻辑视图。这个逻辑视图显示出使用本发明的系统设计者通过右击已经被从构件强行拿出的组件“Fdisk”3310所看到的情况。
图33E展示了采用图33F中所述的图标的图33B所示的组件源代码库的一个不同部分的逻辑视图。这个逻辑视图显示出使用本发明的系统设计者通过右击组件“Intel440BX”3330的“CacheLineSize”选项3336所看到的情况。“CacheLineSize”选项目前具有值04hex。这个窗口允许系统设计者修改当前值或将其复位到在组件信息文件中指定的缺省值。
图33F展示了出现在如图33A到33D所示的本发明的组件源代码库的逻辑视图中的图标。每个图标代表逻辑视图的一个不同的单元,当该单元未包括在BIOS配置中时,其图标具有较淡的颜色。用于被强行放入配置的组件和特征的图标显示一个方格标记,而用于被从配置强行拿出的组件和特征的图标具有较淡的颜色,并显示一个贯穿它带有斜杠的圆圈。具有错误的单元显示一个带有x的图标,具有警告的单元显示一个带有包含感叹号的三角形的图标。
图34显示了产品make例程800。对于产品配置程序状态数据1900中的每个激活的组件3402,对于激活组件的每个激活特征3404,该例程建立一个特征include文件950(图35),然后,对于当前特征中的每个源代码文件3406,向当前组件的组件“make”文件增加一个解释要如何编译该源代码文件的命令3408。当已经处理了当前组件的所有激活特征时,向当前组件的组件“make”文件增加一个解释要如何完成链接以形成一个BIOS组件的命令3410。当已经处理了所有激活组件时,创建一个包含要执行每个组件“make”文件的命令加上一个要执行产品组件链接程序的命令的产品“make”文件908(图10)。然后,调用make实用程序来执行产品“make”文件中的命令1000。
图35显示了构件特征include文件例程950。对于特征的每个文件中的每个PUBINC宏(宏的逐行描述中的节6.2)3502,该例程从其类路径参数产生一个I_CLASSPATH符号3504,然后增加一个将I_CLASSPATH符号定义为包含include文件的目录的路径的汇编程序语句3506。如果PUBINC宏的类路径参数例如是“post.dispatcher”,则PUBINC宏将预期要定义名字为I_POST_DISPATCHER的I_CLASSPATH符号。当所有PUBINC宏都已经被处理时,对于特征的每个文件中的每个PUBEXT宏3508,该例程从名字参数产生一个D_NAME符号。如果由该名字参数指定的公共过程被包括在构件中,则例程增加一个将D_NAME符号定义为TRUE的汇编程序语句3514(图23),或者否则增加一个将D_NAME符号定义为FALSE的汇编程序语句,并且,如果PUBEXT宏指定ALTERNATE关键字,该例程从PUBEXT宏的备用名字参数产生一个D_ALTNAME符号,并增加一个将D_ALTNAME符号定义为TYPE_RESERVED_TRUE的汇编程序语句。如果PUBEXT宏的名字(或备用名字)参数例如是“timer.delay”1312,则PUBEXT宏将预期要定义名字为D_TIMER_DELAY的D_NAME(或D_ALTNAME)符号。
图36展示了产品组件链接程序3600的流程图,一个被分配了符号名“bin_link”的例程。它接受在调用正规链接程序以便将由编译程序和汇编程序产生的“*.obj”目标代码文件链接在一起时产生的“*.exe”可执行二进制文件作为输入数据。它还接受也由正规链接程序产生的“*.map”文件作为输入,并从其得知产生的代码段的名字和它们在“*.exe”文件中所位于的位置。它还直接从设计者接收一个或多个脚本命令文件“bios.scr”,该文件包含关于如何以不同的可执行内容进行、这些段按照什么顺序占据最终ROM图象、绝对地址到一些段的分配等等的指示。在最佳实施例中,产品组件链接程序“BINLINK”3600(图36)在安排好在所有可执行图象中的寻址等之后以及在将从可执行内容提取出的各个命名段合并在一起之后,不将可执行内容缝合在一起以形成一个统一的ROM图象并执行诸如压缩可执行图象和在需要时复制图象这样的任务。这些任务由一个名为“rom_image”的例程执行,该例程从“bin_link”接收输出文件“bios.scr”,然后执行这些最终任务以及将声音和图象文件集成进实际最终ROM图象的任务。
流向产品组件链接程序3600的输入控制信息显示在图37中并在下面描述。以将包括在完成的产品中的组件的列表开始,将检查的“*.exe”文件限制为那些对应于设计者选择的组件(典型地在组件子目录中找到)的文件;以及,使用从链接程序产生的“*.map”文件获得的信息来定位和分离在每个“*.exe”文件中的命名的段;以及,通过直接在所选择的组件“*.exe”文件上操作,产品组件链接程序3600能在每个“*.exe”文件中识别所有命名的代码段,此后称为完成的产品1106的“所建立组件”。以包含在所完成产品中的单个段中为目的而指定可执行目标代码和数据将频繁地被发现分散在许多不同的“*.exe”可执行文件中。同样地,打算控制产品组件链接程序的操作并且此后被舍弃、不包括在所完成产品1106中的数据也将典型地被发现分散在许多不同的“*.exe”文件中,但总是放在两个“修正”数据段中:公共段3804(图38)(“publicSegment”),它包含公共过程的名字、表等;以及外部段3802(图38)(“externSegment”),它包含所有调用、跳转、读取等语句的名字,一旦段和偏移地址由产品组件链接程序3600确定和修正,语句的地址必须由产品组件链接程序通过插入公共入口点的地址来修正。
因此,象它的第一步骤3602一样,产品组件链接程序3600收集所有建立的组件并根据段名排序,把这些具有相同名字的段合并到统一的段(可以称为“模块”)中,即使它们单独地被编辑和链接,然后链接对过程的调用等,以创建从由几个不同的组件提供的代码段片段(fragment)汇编的统一的可执行程序模块。例如,在多个不同的组件源文件中创建的但是分配给一个单个段的用以初始化各种组件的调用可以一起放入一个单个的模块中以形成一个统一的初始化例程,并且甚至可以自动地排序为一命令执行的特定顺序。
用于构造模块的多数段仅仅从各个组件文件读取。但是,一些段可以由产品组件链接程序3600创建以包含直到链接程序3600执行后才存在的最终的二进制图象的部分。
在由链接程序3600创建的附加内容通过“near(近)”寻址方法来访问的情况中,内容必须驻留在与引用相同的段中。这意味着链接程序3600必须增加一个现有段的尺寸来为附加内容创造空间。注意,当处理新的段尺寸时现有的排列需求必须被保存。
当把段收集在一起来创建模块时,可能出现间隙。这些间隙是保留单个的段的排列特性的结果。为了减小这些间隙的影响,链接程序3600检查其中段可以被合并的各种顺序,选择使段间间隙空间的数量最小化的顺序。并且,可以指定放置在那些间隙中的二进制数据,它们可以允许在要被压缩的模块的压缩比上的改进。
在一些情况中,模块放置的目的地不可以由单个的、单片的地址范围组成。当目的地范围中的具体地址为专用目的而保留时可能出现这种情况。这可以导致没有单个的子范围足够大以保存整个模块的情况。链接程序3600可以被指示构造足够小的能够适合可用的子范围的多个段组,从而产生一个分段的模块。
有多个相同的编码必须出现在最终二进制图象中的不止一个位置的时候。产品组件链接程序3600具有对一个构造的模块进行拷贝并且将所述拷贝置于与原来不同的地址的能力。这消除了不止一次地汇编/编译源代码的需要。
模块可以放在具体地址,或者它们可以仅仅被装入一个地址范围。这通过指定模块要位于的区域(或地址范围)来完成。使用区域还允许在不同的执行阶段期间不止一次地指定地址范围以供使用。并且,可以将一个模块放在不止一个区域中,允许在不止一个执行阶段期间使用该模块。
为了允许模块在不止一个执行阶段期间出现,并且位于相同的地址,(在BIOS.SCR文件3812中)对进入所希望区域的映出放置标记模块。链接程序3600将选择一个位于这些区域内的同一地址的位置。
这是通过创建一个“池(pool)”区域目标来作为一个只包含可用在所有目标区域中的那些地址范围的临时数据结构(未显示)来完成的。换句话说,如果一个地址范围已经占据了任何一个目标区域,则该范围不可用在池区域。一旦模块已经放在池区域中,则将它占据的地址范围标记为占据在所有目标区域中。
当需要一个模块在不同的执行阶段期间位于不同的地址时,(在文件3812中)对拷贝放置标记模块。产品组件链接程序3600将确定在每个指定区域内模块将被放置的位置。
有多个一个区域内的具体地址范围需要为专用目的而被保留的时候。这些地址范围可以被指定(在公共扇区3804)为禁止块,通知产品组件链接程序3600它们不可用于放置模块。
接着,链接程序3600从外部段3802读入(步骤3604)外部段3802内容,它为组件包含的过程和/或标号定义命名;并且,链接程序3600把它们的位置存储在一个表中,供以后在从其它建立的组件到这些过程、表等的调用和访问将被修正并分配这些相同的绝对地址时使用。
在步骤3606,产品组件链接程序3600从公共段3804读入对刚刚描述的过程等的外部定义的所有相关引用,包括调用、跳转、表查找访问等;并且,它存储这些引用的地址,以供以后作为代码中的绝对地址将需要被插入的地方被引用。
所有这些地址,包含在外部段3802中的外部的地址和包含在公共段3804中的相关性的地址,都通过把绝对地址放在外部或公共段中的专用宏恰当地标记在源代码中,使得在外部和公共代码中的准确位置被传递到将修正实际调用和跳转的产品组件链接程序。如可以在下面解释的宏代码中看到的,作为一个额外错误检查,每个宏除了将偏移地址放在这些专用外部和公共段中之外,还将这些相同的地址插入到实际代码中,以便在实际检查所链接目标代码内的一个入口点时,产品组件链接程序在每个偏移处找到一个等于偏移地址的数。
接着,在步骤3608,链接程序3600产生执行时间信息可能会需要的定义和引用的复制实例,其中,一段可执行代码将一式两份地出现在ROM图象中或将在运行时间时被重新定位。例如,代码可以被动来动去、或复制在不同的地方、或重写,并且这可能需要既复制定义也复制引用。
这使处理进行到步骤3610,在此,将引用和定义实际地联系并最终链接在一起。参看图38,在本发明的环境下,这是作出最终选择以便例如将一给定调用链接到一个过程或到另一个过程的地方;并且,因为该进程是由产品组件链接程序3600在宏3806的直接控制下(通过外部和公共扇区3802和3804的中介)完成的。但这些宏本身通过特征include文件2300的中介行为被命令在编译或汇编之前编辑源代码(例如,消除对未选择的组件的不想要的“调用”,并用这些include文件的绝对地址来代替include文件类标识符),并控制由配置状态数据1900将什么信号发送给产品组件链接程序,该信号反映在产品配置数据2100和组件和特征信息文件中包含的命令。由于这些文件被创建,并且是通过用户界面200在设计者的直接控制下,从而如上所述给予设计者对确定选择哪些组件和特征的整个进程的一个不寻常的详细控制量。
以下面的特定顺序实现引用与定义的联系:
首先,将指向一指定组件的引用(相关性:例如,“调用”语句)与在所命名的组件中找到的定义(外部过程(externals):例如,“proc”语句)相联系。如果两个不同的组件包含具有相同名字的过程,那么组件名字确定哪一个被挑选为一个给定调用语句的目的。
第二,由宏产生的“调用”信息照这样识别为系统设计者标明的“截取”外部过程(一个将“截取”并取代由源代码调用的一个过程的功能的替代过程)被链接到胜过否则将被利用的任何引用的截取引用。
第三,对于所完成产品将包含复制出的代码或由产品组件链接程序3600产生的代码(例如排序的表等)的范围,这些链接引用接着被建立。
最后,将所有剩余的引用以其范围为将链接限制到一给定组件内的父和同层的全部私人引用链接到定义。
在步骤3612,产品组件链接程序3600接着采集和处理需要专门处理的所有段,例如需要排序和插入段中的列表引用、必须被汇编并放在代码中的串(string)段、也必须被专门处理的非易失RAM代码、指示在系统引导期间的不同时间可以找到一给定过程的不同位置的再定位表、以及在无RAM的子例程调用期间需要用作子例程“返回”点的ROM堆栈。
在这些中,ROM堆栈需要解释:一个ROM堆栈如下地出现在汇编程序源代码中,并由宏CREATE_ROM_STACK产生:
returnAddr:
DW returnAddr+4
DW SEGMENT returnAddr
jmp bx
宏 INIT_ROM_STACK产生下面的堆栈指针和堆栈段指针缺省值:
…
mov ss,SEGMENT returnAddr
mov sp,OFFSET returnAddr
产生无RAM的CALL函数的宏ROMCALL在CALL语句处产生下列代码:
…
mov bx,returnOffset
jmp FAR xyz
returnOffset:
[该宏以外的下一指令]
可以看到,ROM堆栈仅仅是一个任何标准的被调用过程可以对其执行一个RET指令的假堆栈帧。在程序控制返回后,RET指令将包含在堆栈帧内的地址加载进微处理器的程序代码地址和段,该地址是刚好在假堆栈帧之外的地址“returnAddr+4”。因此,微处理器执行假堆栈帧之后的指令“jmp[bx]”并在由bx寄存器指定的偏移跳转回调用程序。
这是返回过程,如上所述,显然创建无RAM的其他段子例程调用的专用宏必须以跟在调用点之后的下一指令的返回偏移地址,地址“returnOffset”预先加载bx寄存器。然后,以一个远程“跳转”命令执行该“调用”,当执行该调用时该命令在假堆栈帧中不尝试和保存任何东西,因为假堆栈帧已经以要由RET指令执行使用的返回地址预先加载。
以这种简单的方式,运行在无RAM环境中的ROM BIOS系统初始化例程(例如,在PC的存储器控制器设置之前)可以调用在其设计中常规的子例程。注意,产品组件链接程序3600只需要将一个假堆栈帧插入需要一个假堆栈帧的每个代码段,因为对过程的许多不同的调用(实际上是跳转)可以共享一单个假堆栈帧,在每种情况下,寄存器bx控制返回并将其指向代码内的正确的偏移。
在RAM可用之前实现远程子例程调用的另一种方法涉及创建一个用于在子例程完成时返回到调用代码的返回地址表。调用程序在跳转到子例程之前以进入该表的索引加载一预定寄存器。在完成时,子例程跳转到一个使用索引值来访问返回地址的公用调度例程,并跳转回调用代码。链接程序3600创建该表并分配索引值。
链接程序3600根据从组件获得的并通过公共段3804传送的内务处理信息创建返回地址表。
接着,在步骤3614,现在包括列表、假ROM堆栈、串、非易失RAM块和代码和再定位表的代码模块可以被映射到整个合并的代码块的最终地址空间,在这之前则不能完成这一点。在IBM PC和Intel 386类计算机(奔腾,486,等)上找到的兼容“实址方式”内,所有段内寻址必须基于实的、绝对段地址和这些段内的偏移。因此,这时,产品组件链接程序3600最终定下所有外部过程的地址一所有引用地址。最后,链接程序3600实际修正代码中的地址,从而最终解析并满足所有代码相关性。代码现在完全准备好用于最终图象中的安装。
由产品组件链接程序执行的最后一个步骤、步骤3616是写出ROM模块、符号图和与列表、串和非易失RAM有关的记录信息,以供系统设计者检查并传递到单独的(在最佳实施例中)“ROM_IMAGE”例程,其中“ROM_IMAGE”例程与BIOS.SCR和关于要被复制的图象部分的信息一起输入ROM模块,并执行ROM代码图象的最终汇编,包括压缩某些部分、增加声音和图象的压缩代码以及创建最终ROM目录。
图37显示了列表创建和管理进程3700。在源代码文件A 3702的一个代码片段中显示的LIST_CREATE宏3704(宏的逐行描述中的节5.1)通过保存列表名和由其参数指定的入口尺寸并在其被调用时识别当前段来在当前段中创建一个列表。源代码文件B 3706的代码片段包含一个指定和保存与LIST_CREATE宏3704相同的列表名和入口尺寸以及列表入口优先顺序的LIST_START宏3708(宏的逐行描述中的节5.3)。在这个代码片段3710中的LIST_ENTRY宏(宏的逐行描述中的节5.5)指定和保存用于一个列表入口、入口名、其排序优先级(用于以相同的排序键对列表入口排序的号)和排序键的数据。LIST_END宏3712(宏的逐行描述中的节5.4)结束以LIST_START宏3708开始的列表入口,并允许指定多个列表入口。源代码文件C 3714的代码片段显示出多个列表入口可以在可以是不同组件的一部分的不同的源代码文件中指定。组件构件进程1000使用由LIST_CREATE宏3704保存的信息来识别一个列表名、合并由LIST_START宏3708和LIST_ENTRY宏3710保存的信息、对入口数据排序并将排序的入口数据放入在由LIST_CREATE宏3704识别的段中的所完成产品3716中。参见附录B对列表的进一步的描述。
每个列表入口声明指定一个可以被用于确定列表中入口的顺序的排序“键”串3711。当提供一个主排序列表(未显示)时,对实际列表中的入口排序以匹配排序列表顺序。主排序列表可以包含在实际列表中没有匹配入口的入口。每个实际列表入口必须具有一个出现在主排序列表中的排序键(如果主排序列表存在),以确定列表入口的位置。如果不止一个列表入口具有相同的排序键串,则采用入口排序优先级值3713对其进一步排序。
产品组件链接程序3600读取(包括在图38的公共段3804中的)包含主排序列表的内务处理段,从要排序的列表名开始。然后顺序地读取每个排序键,并放在一个作为列表目标的容器中,其中列表目标(未显示)是一个临时数据结构。通过将一个索引值分配给每个入口来完成列表入口的实际排序。首先,将索引值初始化为零。然后,从主列表中检索出第一排序键串。入口目标的容器搜索具有一个匹配排序键串3711的入口。如果找到一个或多个,则将当前索引值分配给具有最高排序优先权值3713的一个,并递增索引值。这一直持续到再没有可用的匹配入口。对于来自主列表的每个排序键串重复这个进程。
当多个列表入口具有相同的排序键串或者当未提供主排序列表时,列表入口的排序优先权值3713被用来确定列表入口的顺序。排序优先权值3713实际上是数字,产品组件链接程序3600对入口进行排序,使得较小的值在列表中出现在较大的值的前面。当试图以优先权对入口排序而优先权值相等时,报告一个错误。
列表和列表入口宏产生找到其进入公共段3804的方式和由产品组件链接程序3600用来确定列表布局和入口顺序的内务处理信息。这些参数控制实际的排序进程。一旦已经执行了排序,这个内务处理信息可以被舍弃,从而减小最终可执行代码的尺寸。
当一个列表入口数据3709包括“公共声明”时,则对它的引用、例如对它的“调用”可以以名字作出。由于列表的最终定位以及这个入口在列表中的位置直到由产品组件链接程序确定以后才知道,所以必须在列表位置和列表入口位置是已知的并最终确定之后这些引用才被解析。
这以两个步骤完成,一个用于入口的偏移,一个用于段。入口的偏移可以在列表被排序之后通过将入口索引乘以入口尺寸3707来确定。这导出入口距段开始的距离。将计算出的偏移值与指向列表段目标的指针一起使用。入口的段值对于列表中的所有入口是相同的,在将列表段放进目的区域时确定。
列表入口可以在其数据区域内包含一个需要由产品组件链接程序3600解析到一个外部引用的公共定义。直到已经进行了段汇编和布局时才能解析这些引用,并且直到已经创建了所有列表时才能完成段布局。为了解决这个问题,创建并临时存储一个包含列表入口的初始位置(在公共段中)和列表入口的新位置(在指定目的段中)的关联目标。在解析了每个引用之后,进行检查以查看公共定义的位置是否位于公共段内。如果是,找到包含该定义的列表入口的关联目标,并将引用解析到列表入口内的定义的新位置。
作为列表处理的一部分,产品组件链接程序3600导出所得列表结构的一个“源列表”,用户可以将其存为组件源代码库的一部分。这个列表(未显示)可以用在产品组件链接程序3600的后续启用上,作为定义列表的宏和数据3704、3708、3714的替代和超覆,以‘锁定’一个实际列表的内容和结构。当提供锁定的列表时,在所有列表声明上实施一个一对一的对应(即,每个列表声明(3704,3708,3714等)必须匹配锁定列表中的一个并且只能匹配一个入口)。
为了减小对列表入口声明作出改变所需的努力,可以将原始声明留在原处,并且可以以一个超覆修改程序标志附在其宏上来创建一个新的声明。当希望对列表入口作出简单改变时,这消除了修改一个现有文件(该文件可能包含在一个核心目录中)的需要。当检测到多个列表入口具有相同名字时,在列表的创建中只使用具有最高数字超覆优先权值3705的声明。具有相同超覆优先权值的(具有相同名字的)多个入口产生一个错误。
产品组件链接程序3600的一个“精确适合段”特征消除了使用单独的“开始”和“结束”段来仅仅确定入口列表的尺寸和位置的需要。通过包括带有每个列表定义以及每个列表入口定义的额外的标识信息,可以将源级列表声明语句编译进公共段3804。链接程序3600然后可以创建所需精确尺寸的新段。
在已经读取了所有列表入口定义之后,从列表中的入口数目和入口尺寸可以确定列表段的所需尺寸。然后创建一个段目标,并增加到用于适当模块的段目标的容器。
产品组件链接程序3600能够以范围从1位直至16字节邻接的(紧密压缩的)尺寸分配非易失RAM空间、例如电池备用C-MOS空间。对准8位或更少位的内容以便不穿过一个字节边界。将超过16位的内容上舍入到字节的一个整数倍(参见图39)。
提供一个NVRAM_MEDIA宏3902来定义一特定介质,例如电池备用CMOS。这个宏向该介质分配一个名字,指定其尺寸,并以名字声明要用于读和写该非易失介质的读程序和写程序子例程。
NVRAM_ITEM宏3904通过指定其名字、尺寸、缺省值、标志、介质和地址来定义非易失RAM字段。例如,标志指示该字段是否包括在校验和中以及在校验和失败或NV-RAM被清零时它是否需要初始化。介质参数将其分配给由NVRAM_MEDIA宏定义的几个可能的介质中的一个特定介质。地址和介质都是可选的。但如果指定一个地址,则介质也必须被指定。
NVRAM_RESERVED宏类似,但仅仅例如为实时时钟保留空间。
NVRAM_STRUCTURE START和NVRAM_STRUCTURE END宏可以将几个NVRAM_STRUCTURE_ITEM宏归类在一起,来定义一系列项,这些项是用于检索和存储目的的单个的较大的数据结构项。
READNV宏3906产生代码以便读取名字为NVRAM的数据项,WRITENV宏3908产生代码以便写入一个所命名的数据项。
“READNV<name>”宏产生下列代码:
MOV AX,<16位空间>
Call read.sub
它使得一些索引(后来由产品组件链接程序3600插入的)调用适当的子例程(也是后来由产品组件链接程序插入的)以取出所命名的值。这个宏还在公共段3804产生这个调用的位置的一个记录、它是一个“读”调用的指示、加上NV_RAM字段的名字,使得产品组件链接程序3600能够正确地调整插入的代码。“WRITE NV<name>”宏的工作类似。
产品组件链接程序3600将NV_RAM分配到由NVRAM_ITEM宏定义的字段,并将一个使每个名字与一个偏移相关的临时表保存在NV_RAM中。这个表则可以如刚刚所解释的用于调整程序段中的读和写代码。
STR_DEFINE和STR_DEFINE_END宏4002接受一个串并为该串分配一个名字。串还具有由STR_LANGUAGE宏指定的“语言”属性(例如,“US”或“IT”)以及由STR_TEXT宏指定的ASCII值。
链接程序采集由这个宏的实例定义的所有串,并将每个串与其名字和语言相联系。用于一给定PC的“现用”语言参数通常存储在NV_RAM中,并且可以由系统设计者改变。
“LOADSTR<名字>”宏4004在一个程序段内产生串写准备代码:
MOV_SI,<16位空间>
给予程序一个指向串数据的“源索引(source index)”指针(这将在下面解释)。与在NV_RAM宏的情况一样,包括串名字、16位空间的地址以及这个指令的性质的数据被放进公共段3804,从而使产品组件链接程序3600能完成这个引用。
产品组件链接程序3600为每种语言建立一个单独的表,包括一个串值指针阵列和每种语言的实际串值。在每种不同的语言中具有相同意思的串在每个表内由存储在值指针阵列内的相应位置的值指针指向。因此,“源索引”值si、例如“18”在每个语言表的串值指针阵列内标识出一个对文本的相应串的开始的索引值。因此,在“movsi”<ptr>”代码之后的代码可以容易地利用标识出一特定消息的“si”值以及标识出语言的NV_RAM国家值,以找到并检索出以正确的语言写出的正确的消息。
图38在一个视图中展示了在别处描述的参与使系统设计者能够维持对将特征和组件汇编进一个最终完成产品1106的详细控制的本发明的单元。
如上面所解释的,设计者通过用户界面查看配置状态数据(图33A)并作出关于组件、特征和相关性的选择。这个用户信息被保存在产品配置数据文件2100中,并反馈进配置状态数据。组件源代码库1200也被扫描,并将关于调用、过程、includes等的详细信息收集进数据库1800,包括诸如组件名称、类名称、版本名称和其他有用信息。并且,从组件和特征信息文件收集关于组件和特征的信息,例如它们与什么平台兼容、或被什么平台所需要,并放进数据库1800。数据库1800的内容也被传送到配置状态数据1900。
包含在配置状态数据1900中的所有这些信息则确定产品的配置,该产品配置在用户界面以逻辑形式展示给系统设计者。设计者可以通过采用用户界面编辑组件源代码库1200中的文件或通过选择和取消选择特征和组件(图33D)和相对于相关性和外部过程调整选项(图33E)来修改配置。当然,在系统组合在一起的过程中的所有错误通过用户界面上的红X来直接地通知给设计者(图33B)。
一旦进行了所述配置,则调用产品make例程800来创建完成的产品1106。首先,产生组件和产品make文件2400和2500以命令它们任务中的汇编程序、编译程序和链接程序。接着,产生特征include文件2300,这样编译程序和汇编程序将在编译和汇编前把它们插入到源代码文件中。特征include文件应该被认为是从系统设计者和配置状态数据引导直接进入源代码文件的信号通道,以便在编译和汇编之前实际控制源代码文件的预先编辑,包括删除对已经被取消选择的组件和特征的所有调用;用其在组件源代码库1200内的绝对地址替代include文件的“类”名称;以及,将控制值传送给宏以改变宏通知产品组件链接程序关于什么要最终连接到什么的方式。
专用宏在由编译程序和汇编程序执行时为被标明放入一个专用外部段3802、即第一假代码段的每个过程、标号和表(外部过程)产生数据。它们为被标明放入一个专用外部段3804、即第二假段的每个调用、跳转、选项和全局(相关性)产生数据。这些假段应该被认为是在单个源代码文件位置和产品组件链接程序之间的通信路径,通过它可以传送定义最终地址修正操作将如何实现的信息。注意,这个信息起源于系统设计者。组件和特征信息和源代码文件都包含在配置状态数据中,通过特征include文件2300部分地传送到编译/汇编进程,并最终由专用的宏3806收集、改变和转送到产品组件链接程序3600。
接着实现编译、汇编和链接进程,产生可执行文件1104,该文件由链接程序映射文件3808索引进单独的段内。因此,产品组件链接程序3600在进行操作时可以筛查可执行文件、以代码段对其内容排序,使得所有段的内容都被连接在一起。这样,公共和外部段数据3802和3804被连接在一起,使得它可以与所选择组件3810的列表和指定绝对扇区地址、扇区顺序和其他类似事物的BIOS.SCR文件一起控制和指导产品组件链接程序的操作。如上面所解释的,所有这些使得系统设计者能够保持对将组件和特征一起链接进一个集成产品的进程的罕见程度的控制。
如上所述,开发系统依赖于从源代码文件和信息文件(INF文件)的数据采集。在开发环境的整个执行期间扫描INF文件和源代码文件。具体地,只要文件被添加到工作目录或工作目录中的现有文件被修改,就扫描这两种中的任一种文件并将数据放在数据库中。如果从工作目录删除一个文件,则从数据库中去除相联系的数据。这个进程确保数据库总是最新的。下面的段落描述从源和INF文件采集的具体数据,并展示这个数据的具体使用。
需要利用开发系统的程序源文件来使用先前展示和描述的宏的一个标准集合。附录C展示了被扫描的宏的列表并识别来自这些宏的数据。
INF文件代表用于存储未存储在源代码宏中但需要用于促进系统的许多功能的各种组件和特征信息的最佳实施例。注意,包含在INF文件内的数据可以采用许多其他的方法存储,包括数据表、源文件、PLATFORM.CFG文件或专门为该目的创建的一些其他文件,但不限于这些。在最佳实施例中,所有组件和特征在其相应的目录内必须具有一个INF文件。INF文件使用严格的命令语言,在用于数据库的存储的扫描进程期间有助于简单的数据采集。附录D展示了INF文件命令并指定从这些命令采集的数据。附录E展示了最佳实施例的平台类型声明。
在扫描进程期间,在树中可以识别出多个错误。这是很有用的,因为在开发进程中在尝试使用源代码、建立系统之前或更重要地在一个编译的BIOS的分布之前较早地识别出错误。可以被识别的错误包括:1)通过分析每个命令以确保与命令说明一致,对不适当地命名的组件、特征和选项的识别,2)通过在添加一个记录到数据库时要求唯一的组件名,对具有相同组件名的多个组件或特征的识别,3)在触发解析期间可以潜在地导致不确定状态的无效触发组合(附录F),4)包括在建立进程期间可以最终导致汇编错误或运行时错误的语法错误或无效数据错误的不正确的宏使用的识别。
另外,在初始扫描进程之后,采用数据库来用于在开发进程期间出现的错误条件的实时估计。目前技术水平的开发系统只在建立进程期间进行类似的错误检查。本发明在建立进程之前在一个有效的实时的环境下完成这些任务,在该环境下,如果出现一个错误,用户在标准的个人计算机系统(奔腾400MHz)上接收立即反馈(在大多数情况下<1秒)。可以被识别的错误包括:1)未解析的相关性,2)违反访问级别的调用,例如从一个组件对另一个组件的私人进程的调用,3)对在适当的程序段之外的过程的调用(附录G),4)在没有首先声明PUBEXT或PRVEXT的情况下EXTCALL语句的使用,5)对远过程的近调用,6)对近过程的远调用,7)未解析的相关性,8)对无效版本号的调用,9)旧文件超覆,10)基于工作树中的用户改变的不确定触发条件的识别(参见附录F)。
各种统计信息可从数据库得到。这个信息包括:1)未使用接口、标号或变量的确定,2)代码流分析,3)为一个过程声明的公共和私人接口的数目,4)基于组件或特征的类等的关于不满足最小功能接口要求的组件和特征的报告。图55显示了可以如何使用功能跟踪。
信息也可从配置中得到,以提供滤波搜索,以便只包括作为一个产品的一部分的源代码库的子集。例如,为了搜索所显示的串,查看源代码库中该串的所有实例不如查看由该产品实际使用的实例有用。可以产生给予开发者信息的报告,信息例如有1)没有硬相关性的特征(可选特征),2)可用的公共接口,3)选项和设置值和缺省值,4)使用指定代码段的特征,以及许多其他信息。
定制技术
本发明支持从预先编译配置和二进制链接程序的最终图象创建级定制的方法。预先编译配置定制允许源代码库的“点击(point andclick)”定制。上述的选项允许用户在不修改代码的情况下改变值。这个方法可以扩展到表。在BIOS的情况下,可以不进行代码修改就定制寄存器和CMOS表。源代码库文件可以被超覆,其中原始文件在物理上保持完整,而超覆内容位于自定义文件夹中,但被建立进组件图象。可以将自定义文件添加到一个特征上,该自定义文件在物理上位于自定义文件夹中但也可以建立进组件图象中。图42显示了在这些技术中所涉及的步骤,显示出来自一个表的单个项的定制,其中使用产品组件链接程序3600来以定制的版本代替原始入口并调整链接引用。
定制由产品组件链接程序3600支持,并允许表顺序锁定以及表入口超覆。表中的完全入口可以被超覆,并且代码段中的原始数据可以被超覆内容所代替。附录H显示了这个方法。当截取参数在公共过程声明上声明时,产品组件链接程序3600还通过截取任何调用程序对公共被调用程序的链接来支持定制。这个方法对于使自定义代码在一个公共过程之前或之后执行是有用的。
档案
开发系统定义一个用于与变化管理系统(例如PVCS,Dimensions,Visual Sourcesafe等)交互的应用程序接口。这个接口包括将来自组件或特征的INF文件的专有信息直接转到变化管理系统数据库的能力,从而摒弃了使一个用户在检查新的组件或特征时再将这个数据放入变化管理系统中的需要。被传送的信息包括在INF文件中包含的所有分类信息(附录D)。然而,注意,任何附加信息可以象添加适当的接口这样容易地被传送。一旦在变化管理系统中,这个信息可以被用于各种报告目的以及用于根据具体标准定位组件或特征。例如,变化管理系统的用户可以查询变化管理数据以定位支持设备号“371AB”的组件或特征。
数据库扫描进程还扩展到在信息归档和检索领域提供支持。在软件开发系统被用于描述可互换组件和特征的一个大的核心集合的环境中,需要挑选出这些组件和特征的一个子集来用在一具体方案中。当前技术水平需要用户从标准目录文件夹列表简单地挑选和选择软件部分以累积所希望的部分,或者一个更先进的系统可以提供用于简化这个进程的脚本。在本发明中,将前面描述的相同的扫描进程运用到该组件和特征的核心集合,以便获得可用软件核心集合的一个完整的数据库。图形用户界面(GUI)然后使用这个数据库来向用户提供选择一个新产品中所需的组件或特征的能力。用户界面只需要数据库来帮助这个选择进程。数据库可以是本地的,或者它可以位于一个远程服务器上(参见附录I)。另外,如果该部分依赖于其他组件或特征,则GUI在选择了一特定组件或特征之后能够立即通知用户。在理论上,用户具有在从档案下载一单个代码位之前无错误地全部选择新软件产品所需的所有组件和特征的能力。
产品发行(release)典型地尤其需要创建一个识别被发行的产品的所有部分的基线标号。这个加标号进程允许产品在以后的可再现性。采用目前发展水平的开发和变化管理系统,如果感兴趣的一方想要关于所发行产品的统计信息,可以仅仅通过重新下载建立所发行产品所需的所有原始文件并且然后使用这些文件来编译所需的信息来获得信息。或者,变化管理系统可以包含对特定细节的发行注释。由本发明提供的开发系统通过允许用户只下载用于产品发行的PLATFORM.CFG文件和归档数据库(来自一个典型的大文件集合的两个文件)以获得否则不能在今天的目前水平的系统中得到的相当大量的信息,比目前发展水平有了提高。这个信息包括所有安装的组件、特征、相关性、接口、其版本号以及可以从标准数据库获得的其他任何信息的完整的报告。
除了向使用这个系统的开发者提供控制之外,从代码库采集的信息的数据库可以被用于各种目的,包括源库质量管理。系统中的许多错误在文件被编译之前是可查看的。代码库和相应版本的所有相关性和定义被捕获,考虑代码库相干性的确定。所有未引用的功能的报告防止死代码存在于代码库中。带有可兼容版本号的库中没有的相关性的报告是一个有价值的工具。
在本发明的最佳实施例中使用的系统宏的描述
过程和标号声明宏由PUBLIC_PROC、PRIVATE_PROC、END_PROC、PUBLIC_LABEL、PRIVATE_LABEL和FBM_LABEL组成。
PUBLIC_PROC宏标记一个可以从其他组件调用的过程的开始。它必须与END_PROC宏相匹配。其参数是名字、版本和一个可选的INTERCEPT关键字。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。版本参数由以句点分隔的大和小版本号组成。具有不同大版本号的调用程序是不兼容的。具有相同大版本号但较大的小版本号的调用程序是不兼容的。增大的小版本号表明向后兼容性。可选的INTERCEPT参数表明,如果有多个定义,产品组件链接程序将修正调用程序来调用这个过程。
PRIVATE_PROC宏标记一个只能从组件内调用的过程的开始。它必须与END_PROC宏相匹配。其参数是名字、范围关键字和一个可选的版本。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。范围关键字参数必须是NEAR或FAR。可选的版本参数只在私人过程被定义在组件外面、例如一个共享文件或oem hook时需要。如果被指定,它与上述PUBLIC_PROC宏的版本参数相同。
END_PROC宏标记一个过程的结束,没有参数。它必须与前面的PUBLIC_PROC宏或PRIVATE_PROC宏相匹配。
PUBLIC_LABEL宏创建一个可以从其他组件使用来用于代码执行、例如创建固定入口点的标号。其参数是名字、版本和一个可选的INTERCEPT关键字。名字参数由以句点分隔的类名、零或多个子类名和实际入口点名组成。版本参数与上述PUBLIC_PROC宏的版本参数相同。可选的INTERCEPT参数表明,如果有多个定义,产品组件链接程序将修正调用程序来调用这个入口点。
PRIVATE_LABEL宏创建一个只能从组件内使用来用于代码执行、例如创建固定入口点的标号。其参数是名字和一个可选的版本。名字参数由以句点分隔的类名、零或多个子类名和实际入口点名组成。可选的版本参数只在私人入口点被定义在组件外面、例如一个共享文件或oem hook时需要。如果被指定,它与上述PUBLIC_PROC宏的版本参数相同。
FBL_LABEL宏指定由产品组件链接程序进行的未来二进制操纵(FBM)并且不产生任何代码。它告知扫描实用程序和产品组件链接程序该标号代表在建立时间由二进制链接程序产生的数据。单个名字参数由以句点分隔的类名、零或多个子类名和实际入口点名组成。
外部引用宏由PUBEXT、PRVEXT、EXTCALL、EXTJMP、EXTPTR、LOADADDR、LOADOFF、LOADSEG、EXTREF和EVALREF宏组成。
PUBEXT宏声明对一个公共过程、公共标号、公共列表或公共列表入口的外部引用。其参数是名字、版本和可选的参数属性关键字或组件名、备用名和备用版本。名字参数由以句点分隔的类名、零或多个子类名和实际入口点名组成。版本参数与上述PUBLIC_PROC宏的版本参数相同。当可选的第三个参数是关键字0PTIONAL时,如果指定的标号不存在,则去除对标号的引用。当可选的第三个参数是关键字SUBSTITUTE时,如果指定的标号不存在,则使用十六进制值FFFFFFFF(远)或FFFF(近)。当可选的第三个参数是关键字ALTERNATE时,如果名字未定义则第四个参数是备用名以供使用,第五个参数是备用名过程的版本号。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望调用原始过程时,将原始组件的名字指定为可选的第三个参数。
PRVEXT宏声明对一个私人过程或标号的外部调用。其参数是名字、范围关键字、版本和可选的参数属性关键字、备用名和备用版本。名字参数由以句点分隔的类名、零或多个子类名和实际入口点名组成。范围参数由关键字NEAR或FAR组成。版本参数与上述PUBLIC_PROC宏的版本参数相同或是关键字NO-VER。只在标号被定义在组件的外部、例如一个共享文件或超覆时才指定版本。当可选的第四个参数是关键字OPTIONAL时,如果指定的标号不存在,则去除对标号的引用。当可选的第四个参数是关键字SUBSTITUTE时,如果指定的标号不存在,则使用十六进制值FFFFFFFF(远)或FFFF(近)。当可选的第四个参数是关键字ALTERNATE时,如果名字未定义则第五个参数是备用名以供使用,第六个参数是备用名过程的版本号。
EXTCALL宏用于调用一个公共或私人过程,必须与前面的PUBEXT或PRVEXT宏一起使用。其参数是名字、可选的代码文本串和可选的组件名。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。可选的代码文本串包含在调用返回后要执行的一个指令。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望调用原始过程时,将原始组件的名字指定为可选的第三个参数。
EXTJMP宏跳转到一个公共或私人过程,必须与前面的PUBEXT或PRVEXT宏结合使用。其参数是名字、可选的寄存器名、可选的代码文本串和可选的组件名。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。可选的寄存器名指定将保存返回地址的16位寄存器。可选的代码文本串包含在调用返回后要执行的一个指令。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望调用原始过程时,将原始组件的名字指定为可选的第四个参数。
EXTPTR宏将一个指针分配给一个过程或标号,必须与前面的PUBEXT或PRVEXT宏结合使用。其参数是名字和可选的组件名。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望指向原始过程时,将原始组件的名字指定为可选的第二个参数。
LOADADDR宏将一个过程或标号的地址加载进寄存器,必须与前面的PUBEXT或PRVEXT宏结合使用。其参数是名字、可选的段寄存器、可选的偏移寄存器和可选的组件名。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。可选的段寄存器参数指定将保存地址的段部分的16位寄存器(缺省为ES)。可选的偏移寄存器参数指定将保存地址的偏移部分的16位寄存器(缺省为DI)。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望加载原始过程的地址时,将原始组件的名字指定为可选的第四个参数。
LOADOFF宏将一个公共或私人标号的偏移加载进一个16位寄存器,必须与前面的PUBEXT或PRVEXT宏结合使用。其参数是偏移寄存器、名字和可选的组件名。偏移寄存器参数对将保存偏移的16位寄存器命名(缺省DI)。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望加载原始过程的地址时,将原始组件的名字指定为可选的第四个参数。
LOADSEG宏将一个公共或私人标号的段加载进一个16位寄存器,必须与前面的PUBEXT或PRVEXT宏结合使用。其参数是段寄存器、名字和可选的组件名。段寄存器参数对将保存段的16位寄存器命名(缺省DI)。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望加载原始过程的地址时,将原始组件的名字指定为可选的第四个参数。
EXTREF宏用于修正一个结构成员以包含一个公共或私人标号的地址,必须与前面的PUBEXT或PRVEXT宏结合使用。其参数是名字、可选的StrucMen名、可选的组件名和可选的FORWARD_REFERENCE关键字。名字参数由以句点分隔的类名、零或多个子类名和实际过程名组成。如果修正是远的,可选的StrucMen名标识结构成员以进行修正。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望修正原始过程的地址时,将原始组件的名字指定为可选的第三个参数。可选的FORWARD_REFERENCE关键字使得该宏使用一个前向引用的匿名标号来计算偏移。
EVALREF宏允许在一个指令内使用一个标号的地址。其参数是操作码、目的地和源。操作码参数是要被产生的指令的名字。目的地参数指定一个寄存器、标号或过程,源参数指定一个寄存器、立即值、过程或标号。目的地或源参数中的过程或标号必须用一个在角括号(<>)中括起来的与EVALREF宏成行的EXTREF宏来定义。
Include文件声明宏是PUBLIC_INCLUDE_START、PRIVATE_INCLUDE_START、PRVINC和PUBINC。
PUBLIC_INCLUDE_START宏声明一个可以由其他组件使用的include文件的开始。其参数是类层次和版本。类层次参数是以句点分隔的类名和零或多个子类名。版本参数是以句点分隔的由include文件定义的接口的大和小版本号。
PRIVATE_INCLUDE_START宏声明一个只能在当前组件内使用的include文件的开始。其参数是类层次和一个可选的版本。类层次参数是以句点分隔的类名和零或多个子类名。版本参数是以句点分隔的由include文件定义的接口的大和小版本号,只在include文件位于组件外面、例如一个共享include文件时使用.
PRVINC宏包括一个私人include文件。其参数是类层次、文件名和一个可选的版本。类层次参数是以句点分隔的类名和零或多个子类名。文件名参数是include文件的名字。版本参数是以句点分隔的由include文件定义的接口的大和小版本号,只在include文件位于组件外面、例如一个共享include文件时使用。
PUBINC宏包括一个公共include文件。其参数是类层次、文件名和版本。类层次参数是以句点分隔的类名和零或多个子类名。文件名参数是include文件的名字。版本参数是以句点分隔的由include文件定义的接口的大和小版本号。
过程标题宏是DESCRIPTION、INPUT:、OUTPUT:、MODIFIED:、MEM、REG、NONE和OEM_HOOK。这些宏都不产生任何代码,其目的是在扫描源文件时标识用于描述由前面的PUBLIC_PROC或PRIVATE_PROC宏定义的过程的信息的位置和类型。
段宏是CODE_SEGMENT_OPEN、DATA_SEGMENT_OPEN、ASSUME_CODE_SEGMENT、ASSUME_DATA_SEGMENT和SEGMENT_CLOSE。
CODE_SEGMENT_OPEN宏标记一个代码段的打开,该代码段必须由SEGMENT_CLOS E宏关闭。其参数是用加号(+)合并的属性关键字的表达式,该表达式确定随后的代码的放置和“生存期”。
DATA_SEGMENT_OPEN宏标记一个数据段的打开,该数据段必须由SEGMENT_CLOSE宏关闭。其参数是用加号(+)合并的属性关键字的表达式,该表达式确定随后的数据的放置和“生存期”。
ASSUME_CODE_SEGMENT宏强迫汇编程序假设所指定的段寄存器指向包含所指定属性的代码段。其参数是使假设成立(assumptionabout)的段寄存器和用指定属性的加号(+)合并的属性关键字的表达式。
ASSUME_DATA_SEGMENT宏强迫汇编程序假设所指定的段寄存器指向包含所指定属性的数据段。其参数是使假设成立的段寄存器和用指定属性的加号(+)合并的属性关键字的表达式。
SEGMENT_CLOSE宏标记一个必须由前面的CODE_SEGMENT_OPEN或DATA_SEGMENT_OPEN宏打开的代码或数据段的结束。
选项宏是OPTEXT、OPTCHK、LOADOPT、DB_OPT、DW_OPT和DD_OPT。
OPTEXT宏声明从在组件或特征的信息文件中声明的另一个组件或特征对一个选项的引用。其参数是名字和一个可选的组件名。名字参数由以句点分隔的类名、零或多个子类名和实际选项名组成。当对一个过程的调用由定义为一个具有可选的INTERCEPT参数的PUBLIC_PROC的第二个过程所截取并且这个过程希望引用原始组件或特征的选项时,将原始组件的名字指定为可选的第二个参数。
OPTCHK宏以指定条件和值测试所指定选项(该选项必须已经以前面的OPTEXT宏声明)。如果为真,执行真实代码文本;否则执行虚假代码文本。其参数是选项名、条件关键字、值、真实代码文本和一个可选的虚假代码文本。选项名参数由以句点分隔的类名、零或多个子类名和实际选项名组成。条件关键字是具有通常和惯用意思的LE、LT、GE、GT、NE或EQ中的一个。值参数是一个常数。如果条件为真,真实代码文本参数包含要被执行的代码,如果条件为假,可选的虚假代码文本参数包含要被执行的代码。
LOADOPT宏以指定选项的值加载所指定目的地。该选项必须已经以OPTEXT宏预先声明。其参数是目的地和选项名。目的地参数指定存储器位置或寄存器以保存选项值,必须小于或等于选项尺寸。选项名参数由以句点分隔的类名、零或多个子类名和实际选项名组成。
DB_OPT、DW_OPT和DD_OPT宏将一个字节、字或双字分别放在包含指定选项的值的当前段中,其中该选项必须以OPTEXT宏预先声明。选项名参数由以句点分隔的类名、零或多个子类名和实际选项名组成。
宏的逐行描述
指定在随后的本发明的最佳实施例中的宏的描述中的宏、宏参数和宏变量的标识符可以以大写字母(A-Z)或小写字母(a-z)或问号(?)开始,后面跟着零或多个字母、数字(0-9)、下划线(_)或问号字符。以三个问号(???)开始的宏变量名区别于那些在宏内独自定义和引用的变量。在一个宏语句内引用的宏变量通常由其当前内容替换。当宏语句以一个百分号(%)开始时,通常将宏变量以其当前内容替换;然后,在替换之后,指定一个保留的宏变量的任何标识符由其当前值替换。
串由小于号(<)和大于号(>)来限定。
IF语句指示一个条件,如果为真,使得直至所匹配的ELSE或ENDIF语句的宏语句被估计。如果前面的IF语句为假,ELSE语句使得直至匹配的ENDIF语句的宏语句被估计。ELSE语句可以与一个IF语句合并,指示如果前面的IF语句为假并且ELSEIF语句为真则直至匹配的ENDIF语句的宏语句将被估计。一些IF语句为:IFE表达式—如果表达式等于零,IFNB<串>—如果串不是空格,IFDEF变量—如果变量被定义,IF表达式—如果表达式为真,IFIDN<串1>,<串2>—如果串1与串2相同,以及,IFDIF<串1>,<串2>—如果串1与串2不同。
1.退出(Exit)宏
退出宏是这里描述的EXTCALL和EXTJMP和在节4中描述的ROMCALL。退出宏识别控制流程退出当前过程、转到由退出宏识别的过程并在以后返回的点。
DEFINE_PREFIX TEXTEQU<D_>
PROC_PREFIX TEXTEQU<P_>
这两个原文等式定义了将用在下面的宏中的包含字符串前缀的全局宏变量。
1.1 EXTCALL宏
EXTCALL宏由本发明用来调用在不同组件中的一个公共过程或在当前组件中的一个私人过程。由EXTCALL宏产生的代码依赖于由本发明扫描的用于其过程名的退出声明宏和入口定义宏。来自这些宏的信息随后用于产生一个用于由本发明产生并包括在每个源代码文件中的特征include文件中的过程名的全局宏变量,该源代码文件指示如果有的话应该产生什么代码。
EXTCALL MACRO procedureName:REQ,optionalCode,component
BRANCH_HANDLER procedureName,call,
<optionalCode>,,<component>
ENDM
EXTCALL宏产生一个调用指令、用于构件的修正数据以及如果提供则可选的代码。用法:“EXTCALL pci.oprom.init,<jc exit>”。
其参数是:
procedureName(必需的)-以圆点记法表示的要调用的过程的名字,例如“class.subclass.pfocedure”;
optionalCode-典型地汇编由过程设置的进位标志上的跳转的可选代码;以及
component-当多个组件定义同一过程名时可以用来指定其中定义过程的组件的名字。
EXTCALL宏通过以适当的参数调用BRANCH_HANDLER宏来实现。注意,BRANCH_HANDLER宏的第四个参数被故意省略。
1.2 EXTJMP宏
EXTJMP宏由本发明用来调用在不同组件中的一个公共过程或在当前组件中的一个私人过程。由EXTJMP宏产生的代码依赖于由本发明扫描的用于其过程名的退出声明宏和入口定义宏。来自这些宏的信息随后用于产生一个用于由本发明产生并包括在每个源代码文件中的特征include文件中的过程名的全局宏变量,该源代码文件指示如果有的话应该产生什么代码。
EXTJMP MACRO procedureName:REQ,register,optionalCode,component
BRANCH_HANDLER procedureName,jmp,<optionalCode>,<register>,<component>
ENDM
EXTJMP宏用于调用一个公共或私人过程。它产生一个跳转指令、用于构件的修正数据以及如果提供则可选的代码。用法:“EXTJMPpci.oprom.init,<jc exit>”。其参数是:
procedureName(必需的)-以圆点记法表示的要调用的过程的名字,例如“class.subclass.procedure”;
register-保存返回地址的可选寄存器;
optionalCode-典型地汇编由过程设置的进位标志上的跳转的可选代码;以及
component-当多个组件定义同一过程名时可以用来指定其中定义过程的组件的名字。
EXTJMP宏通过以适当的参数调用BRANCH_HANDLER宏来实现。
1.3 BRANCH_HANDLER宏
BRANCH_HANDLER宏是一个内部宏,向本发明提供一个必需的功能,从不由源代码文件直接调用。
BRANCH_HANDLER MACRO externName:REQ,branchInstruction:REQ,\
ptionalCode,register,component
BRANCH_HANDLER宏用于调用一个公共或私人过程。在第一行最后的反斜杠(\)指定续行。其参数是
externName(必需的)-以圆点记法表示的要调用的外部过程的名字,例如“class.subclass.procedure”;
branchInstruction(必需的)-一个调用或跳转;
optionalCode-典型地汇编由被调用过程设置的进位标志上的跳转的可选代码;
register-包含返回地址偏移的寄存器;以及
component-当多个组件定义同一过程名时可以用来指定其中定义过程的组件的名字。
LOCAL ??? Addr
LOCAL ??? retAddr
LOCAL ??? defineName
LOCAL ??? procedureName
LOCAL ??? extern
这些是由该宏使用的局部变量。
GET_SYMBOL_NAME <externName>,<component>
GET_SYMBOL_NAME宏返回全局变量???symbol中的externName(或component.externName,如果指定的话),其中以下划线(-)代替点(.);例如<pci.oprom.init>被返回为pci_oprom_init。
???defineName CATSTR DEFINE_PREFIX,???symbol
???procedureName CATSTR PROC_PREFIX,???symbol
如果externName是pci.oprom.init;则???defineName是D_pci_oprom_init以及???procedureName是P_pci_oprom_init。
IFNB<component>
IFNB<optionalCode>
.ERR<BRANCH_HANDLER:不能以component指定optionalCode>
ENDIF
ENDIF
如果component和optionalCode参数都被指定,则产生一个错误。
%IFDEF ???defineName
%IF((???defineName EQ TRUE)OR(???defineName EQFALSE))
%.ERR<BRANCH_HANDLER:名字!′externName!′还未被PUBEXT或PRVEXT>
ENDIF
核对externName(pci.oprom.init)已经用一个PUBEXT或PRVEXT宏声明。这将使系统定义一个全局变量(D_pci_oprom_init)并给它一个表明其类型的值,既不是TRUE也不是FALSE。在每行开始的百分号(%)使IF语句引用由???defineName指定的全局变量的值。
%IFE ???defineName AND TYPE_SUBSTITUTE
如果由局部变量???defineName指定的全局变量的值没有设置TYPE_SUBSTITUTE位,则不SUBSTITUTE属性声明externName,并且可以产生代码。
%IFE???defineName AND TYPE_NOT_INSTALLED
如果TYPE_NOT_INSTALLED位未设置,则包含externName的定义的组件或特征被包括在构件中,并且可以产生代码。
IFNB<register>
mov register,???RetAddr
ENDIF
如果指定了一个寄存器,将返回地址偏移加载进寄存器。
%IF???defineName AND TYPE_NEAR
%GET_SYMBOL_NAME ???pfocedureName
%???extern CATSTR <???symbol>
%branchInstruction ???extern
如果设置了TYPE_NEAR位,产生branchInstruction(调用或跳转)作为一个近分支。如果名字参数是pci.oprom.init则???procedureName包含P_pci_oprom_init,由包含这个过程的名字的PUBEXT宏定义的全局变量的名字。向GET_SYMBOL_NAME宏传送这个全局变量的值(典型地为pci.oprom.init),使得PUBEXT宏在需要时可以使用一个备用过程名。GET_SYMBOL_NAME宏返回全局变量???symbol中的???procedufeName,其中以下划线(_)代替点(.);例如<pci.oprom.init>被返回为pci_oprom_init,由PUBLIC_PROC宏定义的过程的名字。
ELSE
IFIDNI <branchInstruction>,<call>
DB 09Ah;用于远程调用的操作码
ELSEIFIDNI <branchInstruction>,<jmp>
DB OEAh;用于远程跳转的操作码
ELSE
% .ERR<BRANCH_HANDLER:不知道的分支指令!′branchInstruction!′>
ENDIF
???addr EQU $
DW $
DW $
产生带有一个将在以后修正的过程地址的远程调用(或跳转)代码。如果branchInstruction参数不包含所期望的内容则产生一个错误。注意,修正位置的物理地址(???addr)将被存储在修正位置本身内。构件工具将所存储的修正地址(参考其自身)用作一个明智检查。
%SAVE_EXT_FIXUP_DATA???procedureName,
TYPE_EXT_FAR,???addr,,component
ENDIF
调用SAVE_EXT_FIXUP_DATA宏来为这个外部引用(见下面)保存修正数据。在该行的开始的百分号(%)使得存储在由???procedureName(P_pci_oprom_init)指定的全局变量中的过程名(pci.oprom.init)被作为分支的目标保存。
???retAddr EQU $
定义加载进上面的一个寄存器中的返回地址
IFNB<optionalCode>
optionalCode
ENDIF
ENDIF
如果存在,产生optionalCode。
ELSE
.ERR<BRANCH_HANDLER:不能使用带有调用/跳转的SUBSTITUTE属性>
ENDIF
如果TYPE_SUBSTITUTE位被设置,产生一个错误。
ELSE
%.ERR<BRANCH_HANDLER:!′extefnName!′未定义>
ENDIF
如果由???defineName(D_pci_oprom_init)指定的全局变量未定义,产生一个错误。
ENDM
结束该宏并返回其调用程序。
1.4 SAVE_EXT_FIXUP_DATA宏
SAVE_EXT_FIXUP_DATA宏是一个内部宏,向本发明提供一个必需的功能,从不由源代码文件直接调用。
SAVE_EXT_FIXUP_DATA MACRO callProcedure:REQ,
fixupType:REQ,addr:REQ,\
addrOffset,
component
SAVE_EXT_FIXUP_DATA宏是一个内部宏,用于在具体命名的段中保存由其参数指定的修正数据。其参数是:
callProcedure(必需的)-过程名字;
fixupType(必需的)-修正类型,例如TYPE_EXT_FAR;
addr(必需的)-修正的地址;
addrOffset-如果将偏移修正从段修正分离出来,偏移地址;以及
component-当多个组件定义同一过程名时可以用来指定其中定义过程的组件的名字。
该宏产生下列结构:
DB procedure name
DB 0
DB component name
DB 0
DB fixup type
DW offset of offset fixup
DW offset of segment fixup
DW segment for fixups
externSegment SEGMENT
DB ′&callProcedure′;过程串
DB 0 ;空值结束该串
IFNB<component>
DB ′&component′ ;要解析的组件
ENDIF
DB 0 ;空值结束该串
DB fixupType ;修正类型
IFNB <addrOffset>
DW OFFSET addrOffset ;偏移修正的偏移
ELSE
DW OFFSET addr
ENDIF
IFB <addrOffset>
DW OFFSET addr+2;段修正的偏移
ELSE
UW OFFSET addr
ENDIF
DW SEG addr ;修正的段
externSegment ENDS
ENDM
将包含外部修正数据的结构放在一个专用段中。将callProcedure存储为一个空值结束串。如果component参数是非空格,也将其存储为一个空值结束串。如果component参数是空格,只存储空值结束符。空值结束符是ASCII符号NUL,其具有零值,用于指示一个字符串的结束。如果addrOffset参数是空格,则将要被修正的偏移和段存储在相邻的分别在addr和addr+2的字中;否则,addrOffset指定要被修正的偏移的地址,addr指定要被修正的段的地址。
当包含调用的源代码文件由产品组件链接程序编译、链接和处理时,由对这个宏的每个调用产生的修正数据被合并成一单个externSegment。当链接目标文件以形成组件.EXE文件时,将每个目标文件中的externSegment合并成一单个externSegment。每个组件.EXE文件的externSegment中的修正数据由BIOS组件链接程序用来修正外部引用的段和偏移。
2.退出声明宏
2.1PUBEXT宏
PUBEXT宏由本发明用来声明将由一个退出宏引用的公共过程的名字。PUBEXT宏名字及其参数由本发明从源文件扫描。来自这个宏和入口定义宏的信息被用来产生一个用于由本发明产生的并包括在每个源代码文件中的特征include文件中的过程名的全局宏变量,该源代码文件指示如果有的话退出宏应该产生什么代码。
PUBEXT MACRO name,version,attribute,altName,altVersion
PUBEXT宏用于声明对一个公共过程或标号的一个外部引用。用法:“PUBEXT memctrl.shadow.set,1.0,OPTIONAL”。其参数是:
name-以圆点记法表示的过程或标号的名字,例如”class.subclass.procedure”;
version-外部接口的大.小版本;
attribute-
OPTIONAL->只在公共过程或标号存在时才产生代码,
ALTERNATE->如果公共过程或标号不存在,使用备用引用,
SUBSTITUTE->如果公共标号是未定义的,存储0FFFFh,或者
component->当多个组件定义相同的过程名时,可以用于其中指定定义过程的组件的名字;
altName-备用公共过程或标号的名字;以及
altVersion-备用接口的大.小版本
LOCAL ???defineName
LOCAL ???attrib
LOCAL ???component
这些是由该宏使用的局部变量。
???attrib CATSTR<attribute>
???component TEXTEQU<>
过载的属性参数包含一个属性关键字或组件名。这两个局部变量用于保存由属性参数指定的属性关键字和组件名。由于该参数被过载,一个或另一个将为空格。最初,假定???attrib包含一个属性关键字,???component因此是空格。
IFNB<attribute>
IFDIF<attribute>,<OPTIONAL>
IFDIF<attribute>,<ALTERNATE>
IFDIF<attribute>,<SUBSTITUTE>
???component CATSTR<attribute>
???attrib TEXTEQU<>
ENDIF
ENDIF
ENDIF
ENDIF
检查过载的属性参数是否真是一个组件名。如果是,则???component包含组件名,???attrib是一个空格。
NAME_VER_CHECKER<name>,<version>
%ATTRIB_CHECKER???attrib,<altName>,<altVersion>
NAME_VER_CHECKER宏核对name和version参数都被指定。ATTRIB_CHECKER宏核对如果ALTERNATE属性被指定则altName和altVersion参数同样被指定,或者如果ALTERNATE属性未被指定则altName和altVersion参数都不存在。如果每个名字都不具有一个相应的大.小版本号,这两个宏调用将产生错误。版本号否则将由产生的代码忽略。
从源文件扫描来自PUBEXT宏的每个调用的所有参数并输入一个数据库。这允许BIOS开发系统比较由过程定义使用的实际过程接口的版本与在PUBEXT宏调用中声明的并在包含宏调用的源代码文件中使用的过程接口的版本。由于过程声明和定义的版本号都存储在数据库中,所以系统可以通过在编译之前比较版本号来确定接口是否兼容。
%GET_EXT_NAME name,???attrib,altName,???component
设置在由???defineName指定的全局变量中的位,以指示公共过程或标号已经由一个PUBEXT宏调用声明并被定义或将要根据指定的属性被处理。参见下面的描述。
GET_SYMBOL_NAME name
???defineName CATSTR DEFINE_PREFIX,???symbol
GET_SYMBOL_NAME宏返回全局变量???symbol中的名字,以下划线(_)代替点(.);例如<memctrl.shadow.set>被返回为memctrl_shadow_set。如果名字是memctrl.shadow.set ;则???defineName是D_memctrl_shadow_set。
%IFDEF???defineName
%???defineName=???defineName OR TYPE_PUBLIC
ENDIF
如果包含用于这个过程的各种类型位的全局变量被定义,则设置TYPE_PUBLIC位以指示它是一个公共过程。
BIOS开发系统产生一个由包含在源库中的每个源代码文件包括的特征include文件。它为由包含各种类型位的PUBEXT宏声明的每个过程定义一个全局变量???defineName,例如D_memctrl_shadow_set。例如,如果该过程被声明是OPTIONAL并且过程定义未包括在构件中,则系统将以一个TYPE_NOT_INSTALLED位定义全局变量,指示对于其调用将没有代码产生(参见上面的BRANCH_HANDLER宏)。
ENDM
结束该宏并返回其调用程序。
2.2 GET_EXT_NAME宏
GET_EXT_NAME宏是一个内部宏,向本发明提供一个必需的功能,从不由源代码文件直接调用。
GET_EXT_NAME MACRO name:REQ,attribute,altName,component
GET_EXT_NAME宏确定由一个PUBEXT宏调用声明的全局变量的名字并设置其中的位来指示公共过程或标号已经被声明并且被定义或要根据指定的属性被处理。其参数是:
Name(必需的)-以圆点记法表示的过程或标号的名字,例如”class.subclass.procedure”;
attribute-
OPTIONAL->只在公共过程或标号存在时才产生代码,
ALTERNATE->如果公共过程或标号不存在,使用备用引用,或者
SUBSTITUTE->如果公共标号是未定义的,存储0FFFFh,
altName-备用公共过程或标号的名字;以及
component->当多个组件定义相同的过程名时,可以用于指定其中定义过程的组件的名字;
LOCAL ???defineName
LOCAL ???publicName
LOCAL ???tempDefineName
这些是由该宏使用的局部变量。
IFNB<attribute>
IFDIF<attribute>,<OPTIONAL>
IFDIF<attribute>,<ALTERNATE>
IFDIF<attribute>,<SUBSTITUTE>
.ERR<GET_EXT_N AME:Invalid!attribute supplied>
ENDIF
ENDIF
ENDIF
ENDIF
确认属性参数是否是非空格。
GET_SYMBOL_NAME<name>,<component>
???defineName CATSTR DEFINE_PREFIX,???symbol
GET_SYMBOL_NAME宏返回全局变量???symbol中的externName(或component.externName,如果指定的话),其中以下划线(_)代替点(.);例如,<pci.oprom.init>被返回为pci_oprom_init。如果name是pci.oprom.init;则???defineName是D_pci_oprom_init。
%IFDEF???defineName
如果其名字由???defineName指定的全局变量由构件工具定义,则设置全局变量中的位以指定所声明的过程的类型。
%IF???defineName EQ TRUE
如果其名字由???defineName指定的全局变量具有值TRUE,则过程被包括在构件中并且可以被调用。
???publicName CATSTR PROC_PREFIX,???symbol
%???publicName TEXTEQU<name>
%???defineName=???defineName OR TYPE_TRUE
构造将包含要被调用的过程的名字的全局变量的名字,并在其中存储串<name>。如果名字是pci.oprom.init;则???publicName是包含串<pci.oprom.init>的P_pci_oprom_init。设置名字由???defineName指定的全局变量中的TYPE_TRUE位。
%ELSEIF???defineName EQ FALSE
如果名字由???defineName指定的全局变量具有值FALSE,该过程不包括在构件中,其类型由它所声明的属性确定。
IFIDN<attribute>,<SUBSTITUTE>
%???defineName=???defineName OR TYPE_SUBSTITUTE
ELSEIFIDN<attribute>,<OPTIONAL>
%???defineName=???defineName OR TYPE_NOT_INSTALLED ORTYPE_OPTIONAL
如果指定了SUBSTITUTE或OPTIONAL属性,设置适当的位。
ELSEIFIDN<attribute>,<ALTERNATE>
???publicName CATSTR PROC_PREFIX,???symbol
GET_SYMBOL_NAME altName
???tempDefineName CATSTR DEFINE_PREFIX,???symbol
如果指定了ALTERNATE属性,构造将包含要被调用的过程的名字的全局变量的名字。
构造包含用于altName的类型位的全局变量的名字。
%IFDEF???tempDefineName
%IFE???t empDefineName AND TYPE_RESERVED_TRUE
.ERR<GET_EXT_NAME:!′altName !′不在构件中>
ENDIF
ELSE
.ERR<GET_EXT_NAME:!′altName!′未定义>
ENDIF
如果包含用于altName的类型位的全局变量未被定义或被定义了但TYPE_RESERVED_TRUE位未设置,产生一个错误。
%???publicName CATSTR<altName>
%???defineName=???defineName OR TYPE_ALTERNATE
ENDIF
将要被调用的过程的名字设置到<altName>,并设置包含类型位的全局变量中的TYPE_ALTERNATE位。
%ELSE
%.ERR<GET_EXT_NAME:!′name!′已经PUBEXT或PRVEXT限定>
ENDIF
包含类型位的全局变量不具有值TRUE或FALSE,因此产生一个错误。
ELSE
.ERR<GET_EXT_NAME:!′name!′未由构件工具获得>
ENDIF
包含类型位的全局变量未定义,因此产生一个错误。
ENDM
结束该宏并返回其调用程序。
3.入口定义宏
3.1 PUBLIC_PROC宏
PUBLIC_PROC宏由本发明用来产生一个定义将由一个退出宏引用的公共过程的PROC语句。由本发明从源文件扫描PUBLIC_PROC宏名字及其参数。来自这个宏和退出声明宏的信息用于产生一个用于由本发明产生并包括在每个源代码文件中的特征include文件中的过程名的全局宏变量,该源代码文件指示如果有的话退出宏应该产生什么代码。
PUBLIC_PROC MACRO procedureName:REQ,version:=<MISSING>,attrib
PUBLIC_PROC宏定义一个可以从其他组件调用的过程。用法:“PUBLIC_PROC pci.oprom.init,1.3”。其参数是:
procedureName(必需的)-以圆点记法表示的过程的名字,例如”class.subclass.procedure”;
version-大.小过程接口版本号,由缺省给出<MISSING>,使得可以检测到一个遗漏版本号;以及
attrib_INTERCEPT,如果在配置中有同一过程名的多个定义,告知BIOS开发系统来调用这个过程。
它留下包含该过程的名字的全局变量???procedureName。
LOCAL ???addr
LOCAL ???procName
LOCAL ???error
LOCAL ???procType
这些是由该宏使用的局部变量。
???error=FALSE
IFDEF???procedureName
IFNB???procedureName
%.ERR<PUBLIC_PROC:过程???procedureName打开>
???error=TRUE
ENDIF
ENDIF
如果一个现有的过程还未关闭,产生一个错误。最初设置了FALSE的局部变量???error被用于指示一个现有的过程还未关闭,以防止产生另一个PROC语句,将引起另外更多的模糊错误。
IFIDNI<version>,<MISSING>
.ERR<PUBLIC_PROC:!Version信息遗漏>
ENDIF
IFNB<attrib>
IFDIF<attrib>,<INTERCEPT>
%.ERR<PUBLICPROC:!′attrib!′是一个无效属性>
ENDIF
ENDIF
核对一个版本参数被指定并确认属性参数。
IFE ???error
如果未检测到错误,定义过程。
GET_SYMBOL_NAME procedureName
???procedureName CATSTR ???symbol
GET_SYMBOL_NAME宏返回全局变量???symbol中的procedureName,其中以下划线(_)代替点(.);例如<pci.oprom.init>被返回为pci_oprom_init。将全局变量???procedureName设置到过程名以供汇编程序解析。如果procedureName是pci.oprom.init;则???procedureName是pci_oprom_init。
% ???procedureName PROC FAR PRIVATE
???addr EQU $
创建公共过程,并得到其位置,这样可以修正从其他组件的调用。
IFIDN<attrib>,<INTERCEPT>
???procType TEXTEQU<TYPE_PUBLIC_INT_PROC>
ELSE
???procType TEXTEQU<TYPE_PUBLIC_PROC>
ENDIF
为修正数据设置???procType,以指示这是一个普通公共(组件间)过程或是一个以相同名字截取对普通过程的调用的专用过程。
%SAVE_PUBLIC_FIXUP_DATA procedureName,???procType,???addr
调用(下述的)SAVE_PUBLIC_FIXUP_DATA宏以保存修正数据。
ENDIF
ENDM
结束该宏并返回其调用程序。
3.2 SAVE_PUBLIC_FIXUP_DATA宏
SAVE_PUBLIC_FIXUP_DATA宏是一个内部宏,向本发明提供一个必需的功能,从不由源代码文件直接调用。
SAVE_PUBLIC_FIXUP_DATA MACRO publicLabel,publicType,addr
SAVE_PUBLIC_FIXUP_DATA宏是一个内部宏,用于保存由其在一个专门命名的段中的参数指定的修正数据。其参数是:
publicLabel-以圆点记法表示的公共符号名字,例如”class.subclass.procedure”;
publicType-公共符号类型(列举的等式);以及
addr-公共符号的地址。
publicSegment SEGMENT
DB ′&publicLabel′;公共串
DB 0 ;空值结束该串
DB publicType ;公共类型
DW OFFSET addr ;修正偏移
DW SEG addr ;修正段
publicSegment ENDS
当包含调用的源代码文件被产品组件链接程序编译、链接和处理时,由对这个宏的每个调用产生的修正数据被合并成一单个publicSegment。当目标文件被链接以形成组件.EXE文件时,每个目标文件中的publicSegment被合并成一单个publicSegment。每个组件.EXE文件的publicSegment中的修正数据由BIOS组件链接程序用来修正每个外部引用的段和偏移。
ENDM
结束该宏并返回其调用程序。
3.3END_PRO宏
END_PROC宏由本发明用来在标记由前面的PUBLIC_PROC宏开始的过程的结束之前以一个汇编程序所需的ENDP指令(即,命令)进行一些错误检查。
END_PRO MACRO
END_PRO宏定义一个公共过程的结束。
IFNDEF???procedureName
.ERR<PROC_END:未定义过程>
ELSE
.ERRB???procedureName,<END_PRO:没有过程在当前打开>
全局变量???procedureName包含当前过程的名字。如果未定义过程或没有过程在当前打开则产生一个错误。
IFNB ???procedureName
% ???procedureName ENDP
???procedureName TEXTEQU<>
ENDIF
如果一个过程在当前打开,为该过程产生一个ENDP语句,并将全局变量???procedureName设置到一个空串。
ENDIF
ENDM
结束该宏并返回其调用程序。
4.ROM堆栈宏
4.1 CREATE_ROM_STACK宏
CREATE_ROM_STACK宏由本发明用来创建一个ROM堆栈。ROM堆栈是一个用于返回到在不同段中的调用程序同时使对存储器的影响最小的机制。它可以用在当处理器首先被通电时执行的代码中,因为没有随机存取存储器然后可用于存储返回地址,直到该存储器被初始化。
CREATE_ROM_STACK MACRO
CREATE_ROM_STACK宏创建ROM堆栈,并提供一个小的调度程序来返回调用程序。寄存器BP用作返回的偏移。
LOCAL returnDispatcher
LOCAL romStackLabel
这些是由该宏使用的局部变量。
%romStackLabel CATSTR<romStack>,<???currSegmentName>
从串<romStack>和当前段名创建romStackLabel的名字。
%PUBLIC romStackLabel
%romStackLabel LABEL BYTE
DW OFFSET returnDispatcher
DW SEG returnDispatcher
将romStackLabel的名字定义为一个包含当前代码段中的returnDispatcher的远程地址的外部可见的名字。
returnDispatcher :
%mov sp,OFFSET romStackLabel
jmp bp
returnDispatcher复位堆栈指针寄存器以指向ROM堆栈的顶部,并转移到BP寄存器中存储的返回地址偏移。
ENDM
ROM堆栈是一个用于返回到在不同段中的调用程序同时使对存储器的影响最小的机制。它可以用在当处理器首先被通电时执行的代码中,因为没有随机存取存储器然后可用于存储返回地址,直到该存储器被初始化。
调用CREATE_ROM_STACK宏,以便在当前代码段中创建一个ROM堆栈。调用INIT_ROM_STACK宏来初始化堆栈寄存器SS和SP以指向当前代码段中的ROM堆栈。在将当前代码段中的返回地址的偏移保存在BP寄存器中之后,ROMCALL宏产生一个远程跳转指令。
所调用过程保存BP寄存器并以一个将returnDispatcher的地址弹出ROM堆栈的正常远程返回指令返回,从而返回当前代码段。ReturnDispatcher代码复位堆栈指针并采用BP寄存器返回调用程序。
4.2 INIT_ROM_STACK宏
INIT_ROM_STACK宏由本发明用来初始化堆栈寄存器以指向当前代码段中的ROM堆栈。ROM堆栈是一个用于返回到在不同段中的调用程序同时使对存储器的影响最小的机制。它可以用在当处理器首先被通电时执行的代码中,因为没有随机存取存储器然后可用于存储返回地址,直到该存储器被初始化。
INIT_ROM_STACK MACRO
INIT_ROMSTACK宏初始化堆栈寄存器SS和SP以指向当前代码段中的ROM堆栈。
LOCAL romStackLabel
这是由该宏使用的局部变量。
%romStackLabel CATSTR<romStack>,<???currSegmentName>
从串<romStack>和当前段名字创建romStackLabel的名字。
%EXTERNDEF romStackLabel:NEAR
%mov sp,SEG romStackLabel
mov ss,sp
%mov sp,OFFSET romStackLabel
ENDM
将当前代码段中的ROM堆栈的名字声明为外部的,并初始化堆栈寄存器来指向它。
4.3 ROMCALL宏
ROMCALL宏由本发明用来利用ROM堆栈调用不同组件中的一个公共过程。由ROMCALL宏产生的代码依赖于用于由本发明扫描的其过程名的退出声明宏和入口定义宏。来自这些宏的信息随后用于产生一个用于由本发明产生并包括在每个源代码文件中的特征include文件中的过程名的全局宏变量,该源代码文件指示如果有的话应该产生什么代码。
ROMCALL MACRO jRoutineName,codeText,jComponent
EXTJMP jRoutineName,bp,codeText,jComponent
ENDM
ROMCALL宏利用ROM堆栈调用一个远程例程jRoutineName。在将返回地址的偏移保存在BP寄存器中之后,它使用EXTJMP宏来产生一个远程跳转指令。
5.列表宏
列表是由列表名字引用的排序的、相同尺寸的数据结构(称作列表入口)的阵列。一个组件(称作列表所有者)创建列表,给它名字和格式,并分配ROM图象中的将放置该列表的段。任何其他组件(包括列表所有者)可以用列表名向列表添加列表入口。BIOS组件链接程序采集所有列表和列表入口,以它们的列表名字分组,对其排序并将其写出到ROM图象。BIOS组件链接程序还修正对列表和列表入口的引用。
5.1 LIST_CREATE宏
LIST_CREATE宏由本发明用来创建一个列表。它产生信息以识别将由本发明的建立列表的BIOS组件链接程序部分获得的列表。LIST_CREATE宏及其参数由本发明扫描,这样可以将其与定义列表入口的LIST_START宏的参数相比较。
LIST_CREATE MACRO listName,listVersion,listSize,listAttribute
LIST_CREATE宏创建一个列表。其参数是:
listName-代表这个列表的唯一的名字;
listVersion-列表的大.小版本号;
listSize-列表入口的尺寸,可以是字节数、一个合格类型的名字(BYTE,WORD,等等)或一个结构名字;以及
listAttribute-PUBLIC关键字。
用法:“LIST_CREATE postList,1.0,postTaskStruc”。
LOCAL ???entrySize
LOCAL ???listAttr
这些是由该宏使用的局部变量。
???entrySize=0
IFNB<listAttribute>
IFIDN<listAttribute>,<PUBLIC>
???listAttr=1
ELSE
???listAttr=0
%.ERR<LIST_CREATE:属性!′listAttribute!′是不合法的>
ENDIF
ELSE
???listAttr=0
ENDIF
初始化???entrySize。如果指定,确认listAttribute,并将其翻译成1(PUBLIC属性)或0(无属性)。
IFNB<listSize>
IF OPATTR listSize EQ 24h
确保listSize是一个结构、合格类型(BYTE,WORD,DWORD,等等)或一个立即值。如果不是,在ELSE语句中产生一个错误。
IF TYPE listSize NE 0
???entrySize=SIZEOF(listSize)
ELSE
???entrvSize=listSize
ENDIF
ELSE
%.ERR<LIST_CREATE:!,listSize!′不是一个结构、合格类型或立即值>
ENDIF
ENDIF
如果listSize具有一个类型,它是一个结构或合格类型。SIZEOF函数将返回其尺寸。否则它是一个立即值(数),不需要专门处理。
IFNB<listName>
IFNB<listVersion>
IFNB<listSize>
%SAVE_LIST_CREATE_DATA listName,???currSegmentName,???entrySize,listVersion,???listAttr
ELSE
.ERR<LIST_CREATE:列表入口的尺寸被遗漏>
ENDIF
ELSE
.ERR<LISTCREATE:列表版本被遗漏>
ENDIF
ELSE
.ERR<LISTCREATE:列表名字被遗漏>
ENDIF
确认listName、listVersion和listSize已经被指定。调用下面描述的SAVE_LIST_CREATE_DATA宏,以保存列表创建数据。全局变量???currSegmentName包含当前段的名字。
ENDM
结束该宏并返回其调用程序。
5.2 SAVE_LIST_CREATE_DATA宏
SAVE_LIST_CREATE_DATA宏是一个内部宏,向本发明提供一个必需的功能,从不由源代码文件直接调用。
SAVE_LIST_CREATE_DATA MACRO listName:REQ,listSegment:REQ,\
entrySize:REQ,listVersion:REQ,listAttr:REQ
SAVE_LIST_CREATE_DATA宏是一个内部宏,用于保存在一个专门命名的段中创建由其参数所指定的列表所需的数据。其参数是;
listName(必需的)-列表名字;
listSegment(必需的)-列表所位于的段名字;
entrySize(必需的)-列表入口的尺寸;
listVersion(必需的)-列表的版本号;以及
listAttr(必需的)-1(PUBLIC属性)或0(无属性)。
listDeclarationSegment SEGMENT
DB ′&listName′;列表名字
DB 0 ;空值结束该串
DB ′&listSegment′
DB 0 ;空值结束该串
DW entrySize ;列表入口的尺寸
DB ′&listVersion′;版本号
DB 0 ;空值结束该串
DB listAttr ; 列表属性
listDeclarationSegment ENDS
ENDM
当包含调用的代码文件由产品组件链接程序编译、链接和处理时,由对这个宏的每个调用产生的列表创建数据被合并成一单个listDeclarationSegment。当链接目标文件以形成组件.EXE文件时,将每个目标文件中的listDeclarationSegment合并成一单个listDeclarationSegment。每个组件.EXE文件的listDeclarationSegment中的列表创建数据由BIOS组件链接程序用来产生一个列表标题。列表名字将称为一个(PUBLIC)标号,指向最终ROM图象的指定段中的列表标题。
5.3 LIST_START宏
LIST_START宏由本发明用来识别将添加入口的列表。由本发明扫描LIST_START宏及其参数,这样可以将其与创建了该列表的LIST_CREATE宏的参数进行比较。
LIST_START MACRO listName,listVersion,listType,lOverridePriority
LIST_START宏开始向指定列表的指定版本添加入口。它与一个或多个LIST_ENTRY、LIST_DATA和/或LIST_SORT宏结合使用以定义入口以及与一个匹配的LIST_END宏结合使用以结束入口。其参数是:
listName-由LIST_CREATE宏调用声明的唯一的名字;
listVersion-列表的大.小版本号;
listType-列表入口的数据类型,可以是一个合格类型的名字(BYTE,WORD,等等)或一个结构名字;以及
lOverridePriority-列表入口优先权顺序(CORE,PRODUCT或PLATFORM关键字)。这指定后面的列表入口是否将替换具有相同名字但较低超覆优先权的现有列表入口。PLATFORM替换PRODUCT,PRODUCT替换CORE,CORE替换缺省的。
它初始化全局变量:
???listName-listName,
???listType-listType,以及
???listOverride-List entry priority order,
并打开一个专门命名的段。
IFNDEF???listName
???listName CATSTR<LIST_UNDEFINED>
ENDIF
IFDIFI ???listName,<LIST_UNDEFINED>
%.ERR<LIST_START:列表!′&???listName!′已经打开>
ELSE
IFB<listName>
.ERR<LIST_START:列表名字被遗漏>
ELSEIFB<listVersion>
.ERR<LIST_START:列表版本被遗漏>
ELSEIFB<listType>
.ERR<LIST_START:列表类型被遗漏>
ELSE
如果需要,初始化全局变量???listName并执行一些基本的错误检查。
???listName CATSTR<listName>
???listType CATSTR<listType>
IFNB<lOverridePriority>
IFIDN<lOverridePriority>,<CORE>
???listOverride CATSTR<0F0h>
ELSEIFIDN<lOverridePriority>,<PRODUCT>
???listOverride CATSTR<80h>
ELSEIFIDN<lOverridePriority>,<PLAATFORM>
???listOverride CATSTR<010h>
ELSE
%.ERR<LIST_START:超覆优先权类型!′lOverridePriority!′无效>
???listOverride CATSTR<0F0h>
ENDIF
ELSE
???listOverride CATSTR<0FFh>
ENDIF
迄今为止还未发现错误。初始化所有全局变量,将超覆优先权翻译成一个数值。当在构件内发现两个具有相同名字的列表入口时,这个值允许BIOS组件链接程序选择一个。CORE具有最低优先权,PRODUCT较高,PLATFORM最高。
IF(OPATTR listType)NE 24h
%.ERR<LIST_START:列表类型!′listType!′不是一个结构或合格类型>
???listType CATSTR<ERROR>
ELSEIF TYPE listType EQ 0
%.ERR<LIST_START:列表类型!′listType!′是一个立即值,不是一个结构或合格类型>
???listType CATSTR<ERROR>
ELSE
listEntrySegment SEGMENT
ENDIF
ENDIF
ENDIF
ENDM
核对listType是一个有效结构或合格类型,并打开段listEntrySegment。
5.4 LIST_END宏
LIST_END宏由本发明用来结束一个已经向其添加了入口的列表。
LIST_END MACRO
LIST_END宏结束一个列表的入口。
IFDEF???listName
IFIDNI???listName,<LIST_UNDEFINED>
.ERR<LIST_END:打开的列表已经以LIST_END关闭>
ELSE
listEntrySegment ENDS
???listName CATSTR<LIST_UNDEFINED>
ENDIF
ELSE
.ERR<LIST_END:一个列表还未以LIST_START打开>
ENDIF
ENDM
核对全局变量???listName指定一个打开的列表。选择段listEntrySegment并设置???listName以指示一个关闭的列表。
当包含这些段声明的源代码文件由产品组件链接程序编译、链接和处理时,由这个listEntrySegment包围的列表入口数据被合并成一单个listEntrySegment。当链接目标文件以形成组件.EXE文件时,将每个目标文件中的listEntrySegment合并成一单个listEntrySegment。每个组件.EXE文件的listEntrySegment中的列表入口数据由BIOS组件链接程序合并和排序以便在最终ROM图象中产生一个具有由创建了该列表的LIST_CREATE宏指定的列表标题的排序的列表。
5.5 LIST_ENTRY宏
LIST_ENTRY宏由本发明用来定义要添加到一个列表的入口。
LIST_ENTRY MACRO entryName,entryData,ePriority:=<8000h>,eSortKey,listAttribute
LIST_ENTRY宏通过指定要出现在列表中的数据和对入口排序所需的信息来创建一个列表入口。它必须出现在LIST_START宏调用之后和LIST_END宏调用之前。其参数是:
entryName-单个列表入口的名字。在列表内必须是唯一的;
entryData-将出现在ROM图象中的在(<)和(>)内的数据。结构数据必须包含在另外的花括号({和(})内;
ePriority-用于以相同的排序键对列表入口排序的数。小数放在大数的前面。最小值是0,最大值是65535(0FFFFh),缺省值是32768(8000h);
eSortKey-用于将列表入口匹配到一个主引用列表的串。EntryName是缺省的排序键;以及
listAttribute-LABEL和/或PUBLIC。
它还使用由前面的START_LIST宏调用提供的三个全局变量的值:
???listName-打开的列表的名字;
???listType-入口类型;以及
???listOverride-超覆优先权号(CORE,PRODUCT,PLATFORM,或无)。
用法:″LIST_ENTRY vgaData,<24h,45h>″。
LOCAL ???QualifiedType
LOCAL ???dataSize
LOCAL ???eData
LOCAL ???eSortKey
LOCAL ???rawData
LOCAL ???listAttr
这些是由宏使用的局部变量。
IFNB<listAttribute>
IFIDN<listAttribute>,<PUBLIC>
???listAttr=1
ELSEIFIDN<listAttribute>,<LABEL>
???listAttr=2
ELSEIFIDN<listAttribute>,<LABEL OR PUBLIC>
???listAttr=3
ELSEIFIDN<listAttribute>,<PUBLIC OR LABEL>
???listAttr=3
ELSE
???listAttr=0
%.ERR<LIST_ENTRY:属性!′listAttribute!′是非法的>
ENDIF
ELSE
???listAttr=0
ENDIF
分析listAttribute参数并将其翻译成一个数值。PUBLIC关键字使得entryName被定义为一个引用entryData的公共标号。LABEL关键字使得entryName被定义为列表内的一个标号(PUBLICLABEL如果都指定了关键字),而不实际产生一个列表入口。如果在列表由可选入口组成时需要进入一个列表的索引,这个属性是有用的。
IFB<eSortKey>
???eSortKey CATSTR<entryName>
ELSE
???eSortKey CATSTR<eSortKey>
ENDIF
如果eSortKey参数是一个空格,将entryName参数用作缺省排序键。
IFB<entryName>
.ERR<LIST_ENTRY:用于列表数据的入口名字被遗漏>
ELSEIFB<entryData>
.ERR<LIST_ENTRY:列表数据被遗漏>
ELSEIFNDEF???listName
.ERR<LIST_ENTRY:一个列表还未LIST_START开始>
ELSEIFIDNI???listName,<LIST_UNDEFINED>
.ERR<LIST_ENTRY打开的列表已经LIST_END开始>
ELSEIFIDNI???listType,<ERROR>
ELSE
执行在输入数据上的一些明智检查。
%???dataSize=SIZEOF???listType
???qualifiedType=TRUE
IFIDNI???listType,<BYTE>
ELSEIFIDNI???listType,<WORD>
ELSEIFIDNI???listType,<DWORD>
ELSEIFIDNI???listType,<FWORD>
ELSEIFIDNI???listType,<QWORD>
ELSEIFIDNI???listType,<TBYTE>
ELSE
???qualifiedType=FALSE
ENDIF
如果进行到这里则没有错误。确定列表类型的尺寸以及它是一个结构还是合格类型。
IFE???qualifiedType
???eData CATSTR???listType,<!<>,<entryData>,<!>>
???rawData CATSTR<!<>,<entryData>,<!>>
ELSE
???eData CATSTR???listType,<>,<entryData>
???rawData CATSTR<entryData>
ENDIF
如果数据不是一个合格类型,则建立表达式″structureName<structureData>″否则″dataTypedata″(例如BYTE数据)。
%SAVE_LIST_ENTRY_DATA???listName,entryName,???eSortKey,ePriority,\
???listOverride,???listAttr,???dataSize,<???eData>,<???rawData>
ENDIF
ENDM
调用SAVE_LIST_ENTRY_DATA宏以保存列表入口并返回调用程序。
5.6 SAVE_LIST_ENTRY_DATA宏
SAVE_LIST_ENTRY_DATA宏是一个内部宏,向本发明提供一个必需的功能,并且从不由源代码文件直接调用。
SAVE_LIST_ENTRY_DATA MACRO listName,entryName,\
sortKey,sortPriority,overridePriority,\
listAttr,dataSize,listData,listTextData
SAVE_LIST_ENTRY_DATA宏在由LIST_START 打开的段listEntrySegment中保存由其参数指定的列表入口数据。
DB ′&listName′ ;列表名字
DB 0 ;空值结束该串
DB LISTMGR_ENTRY_TYPE;入口类型
DB ′&entryName′ ;列表入口名字
DB 0 ;空值结束该串
DB′&sortKey′ ;列表排序键
DB 0 ;空值结束该串
DW sortPriority ; 排序优先权(多个入口)
DB overridePriority ; 排序超覆(CORE,PLATFORM..)
DB overridePriority ; 数据超覆(CORE,PLATFORM..)
DB listAttr ; 列表属性
DW dataSize ;数据尺寸
@@:
listData ;产生数据
DB ″&listTextData″;原始列表入口数据
DB 0 ;空值结束该串
ENDM
局部标号(@@:)定义入口数据的值填充的位置。
5.7 LIST_DATA宏
LIST_DATA宏由本发明用来超覆用于列表入口的数据。
LIST_DATA MACRO entryName,entryData,eAttributes
LIST_DATA宏必须出现在LIST_START宏调用之后和LIST_END宏调用之前。其参数是
entryName-将使其entryData改变的列表入口的名字;
entryData-列表入口的新数据;以及
eAttributes-LABEL和/或PUBLIC。
它还使用由前面的START_LIST宏调用提供的三个全局变量的值:
???listName-打开的列表的名字;
???listType-人口类型;以及
???listOverride-超覆优先权号(CORE,PRODUCT,PLATFORM,或无)。
LOCAL???dataSize
LOCAL???qualifiedType
LOCAL???eData
LOCAL???rawData
LOCAL???listAttr
这些是由宏使用的局部变量。
IFNB<eAttributes>
IFIDN<eAttributes>,<PUBLIC>
???listAttr=1
ELSEIFIDN<eAttributes>,<LABEL>
???listAttr=2
ELSEIFIDN<eAttributes>,<LABEL OR PUBLIC>
???listAttr=3
ELSEIFIDN<eAttributes>,<PUBLIC OR LABEL>
???listAttr=3
ELSE
???listAttr=0
%.ERR<LIST_DATA:属性!′eAttributes!′是非法的>
ENDIF
ELSE
???listAttr=0
ENDIF
分析eAttributes参数并将其翻译成一个数值。PUBLIC关键字使得entryName被定义为一个引用entryData的公共标号。LABEL关键字使得entryName被定义为列表内的一个标号(如果两个关键字都被指定,是一个PUBLIC LABEL),而不实际产生一个列表入口。如果在列表由可选入口组成时需要一个进入列表的索引,这个属性是有用的。
IFB<entryName>
.ERR<LIST_DATA:列表入口名字被遗漏>
ELSEIFB<entryData>
.ERR<LIST_DATA:列表入口数据被遗漏>
ELSEIFNDEF ???listName
.ERR<LIST_DATA:列表还未以LIST_START开始>
ELSEIFIDNI ???listName.<LIST_UNDEFINED>
.ERR<LIST_DATA:打开的列表已经以LIST_END关闭>
ELSEIFIDNI ???listType,<ERROR>
ELSE
%???dataSize=SIZEOF ???listType
核对一个打开的列表存在并且所有必需的参数都存在。确定列表入口的尺寸。
???qualifiedType=TRUE
IFIDNI ???listType,<BYTE>
ELSEIFIDNI ???listType,<WORD>
ELSEIFIDNI ???listType,<DWORD>
ELSEIFIDNI ???listType,<FWORD>
ELSEIFIDNI ???listType,<QWORD>
ELSEIFIDNI ???listType,<TBYTE>
ELSE
???qualifiedType=FALSE
ENDIF
确定列表类型是一个结构还是合格类型。
IFE???qualifiedType
???eData CATSTR ???listType,<!<>,<entryData>,<!>>
???rawData CATSTR<!<>,<entryData>,<!>>
ELSE
???eData CATSTR ???listType,<>,<entryData>
???rawData CATSTR <entryData>
ENDIF
如果数据不是一个合格类型,则建立表达式“structureName”否则“dataType data”(例如,BYTE数据)。
%SAVE_LIST-OVERRIDE_DATA???listName,entryName,???dataSize,\
<???eData>,<???rawData>,???listOverride,???listAttr
ENDIF
ENDM
调用SAVE_LIST_OVERRIDE_DATA宏,以保存列表超覆数据并返回调用程序。
5.8 SAVE_LIST_OVERRIDE_DATA宏
SAVE_LIST_OVERRIDE_DATA宏是一个内部宏,向本发明提供一个必需的功能,并且从不由源代码文件直接调用。
SAVE_LIST_OVERRIDE_DATA MACRO listName,entryName,dataSize,listData,\
listTextData,overridePriority,attributes
SAVE_LIST_OVERRIDE_DATA宏在由LIST_START打开的段listEntrySegment中保存由其参数指定的列表超覆数据。
DB ′&listName′ ;列表名字
DB 0 ;空值结束该串
DB LISTMGR_OVERRIDE_TYPE ;超覆类型
DB ′&entryName′ ;列表入口名字
DB 0 ;空值结束该串
DB overridePriority ;超覆优先权
DB attributes ;列表属性
DW dataSize ;数据尺寸
@@:
listData ;产生数据
DB ″&listTextData″;原始列表入口数据
DB 0 ;空值结束该串
ENDM
局部标号(@@:)定义入口数据的值填充的位置。
5.9 LIST_SORT宏
LIST_SORT宏由本发明用来改变一个列表入口的排序标准。
LIST_SORT MACRO entryName,ePriority:=<8000h>,eSortKey
LIST_SORT宏必须出现在LIST_START宏调用之后和LIST_END宏调用之前。其参数是:
entryName-将使其排序顺序改变的列表入口的名字;
ePriority-用于以相同的排序键对列表入口排序的数。小数放在大数的前面。最小值是0,最大值是65535(0FFFFh),缺省值是32768(8000h);
eSortKey-用于将列表入口匹配到一个主引用列表的串。EntryName是缺省的排序键。
它还使用由前面的START_LIST宏调用提供的三个全局变量的值:
???listName-打开的列表的名字;
???listType-入口类型;以及
???listOverride一超覆优先权号(CORE,PRODUCT,PLATFORM,或无)。
LOCAL ???eSortKey
由这个宏使用的局部变量。
IFB<eSortKey>
???eSortKey CATSTR<entryName>
ELSE
???eSortKey CATSTR<eSortKey>
ENDIF
如果eSortKey参数是一个空格,使用entryName参数作为缺省排序键。
IFB<entrvName>
.ERR<LIST_SORT:用于列表数据的入口名字被遗漏>
ELSEIFNDEF???listName
.ERR<LIST_SORT:列表还未LIST_START开始>
ELSEIFIDNI???listName,<LIST_UNDEFINED>
.ERR<LIST_SORT:打开的列表已经LIST_END关闭>
ELSEIFIDNI???listType,<ERROR>
ELSE
%SAVE_LIST_SORT_DATA???listName,entryName,???eSortKey,ePriority,???listOverride
ENDIF
ENDM
作一些明智检查,并且,如果都检查合格,保存新的排序数据。
5.10 SAVE_LIST_SORT_DATA宏
SAVE_LIST_SORT_DATA宏是一个内部宏,向本发明提供一个必需的功能,并且从不由源代码文件直接调用。
SAVE_LIST_SORT_DATA MACRO listName,entryName,sortKey,\sortPriority,overridePriority
SAVE_LIST_SORT_DATA宏在由LIST_START宏打开的段listEntrySegmen t中保存由其参数指定的列表排序数据。
DB ′&listName′ ;列表名字
DB 0 ;空值结束该串
DB LISTMGR_SORT_TYPE ;排序类型
DB ′&entryName′ ;列表入口名字
DB 0 ;空值结束该串
DB overridePriority ;要使用的最终入口
DB ′&sortKey′ ;列表排序键
DB 0 ;空值结束该串
DW sortPriority ;排序优先权(多个入口)
ENDM
5.11 MASTER_START宏
MASTER_START宏由本发明用来开始一个主索引的定义。
本发明的BIOS组件链接程序部分根据主索引中排序键的顺序对列表入口排序。每个列表至多有一个主索引。主索引通常在列表自己的组件中找到,在一个单独汇编的源文件中,以便于超覆。主索引由三个宏MASTER_START、MASTER_ENTRY和MASTER_END创建。
MASTER_START MACRO listName,attrib
MASTER_START宏必须在调用MASTER_ENTRY或MASTER_END宏之前调用。其参数是:
listName-这个主索引相联系的完全合格的列表名字(包括组件路径);以及
attrib-LOCKED关键字。如果LOCKED,则这是一个锁定索引;否则它是一个主索引。
锁定索引是主索引的特殊形式。替代使用排序键来确定列表入口的最终次序排列,锁定索引使用列表入口名字。MASTER_START宏初始化全局变量:
???masterName-列表名字,以及
???masterAttribs-主索引或锁定索引,
打开一个专门命名的段并将这些全局变量的值保存在这个段中。
IFNDEF???masterName
???masterName CATSTR<MASTER_LIST_CLOSED>
ENDIF
IFIDN???masterName,<MASTER_LIST_CLOSED>
masterlndexSegment SEGMENT
如果需要的话,初始化全局变量???masterName,执行一些一致性检查并打开段masterlndexSegment。
IFNB<attrib>
???masterAttribs=1
IFDIF<attrib>,<LOCKED>
%.ERR<MASTER_START:!′attrib!′是一个无效属性>
ENDIF
ELSE
???masterAttribs=0
ENDIF
将attrib参数翻译成一个数值,并设置全局变量???masterAttribs以指示是指定了主索引还是锁定索引。
IFNB<listName>
???masterName CATSTR<listName>
ELSE
.ERR<MASTER_START列表名字被遗漏>
???masterName CATSTR<>
ENDIF
%SAVE_MASTER_INFO_START???masterName,???masterAttribs
ELSE
%.ERR<MASTER_START:主索引列表!′&???masterName!′已经打开>
ENDIF
ENDM
在全局变量中存储listName并调用SAVE_MASTER_INFO_START保存全局变量的值。如果参数或全局变量不一致,产生错误。
5.12 SAVE_MASTER_INFO_START宏
SAVE_MASTER_INFO_START宏是一个内部宏,向本发明提供一个必需的功能,并且从不由源代码文件直接调用。
SAVE_MASTER_INFO_START MACRO masterListName,attributes
DB ′&masterListName′ ;主列表名字
DB 0 ;空值结束该串
DW attributes ;列表属性
ENDM
SAVE_MASTER_INFO_START宏在由MASTER_START宏打开的段中保存其参数的值。
5.13 MASTER_END宏
MASTER_END宏由本发明用来结束一个主索引的定义。
MASIER_END MACRO
MASTER_END宏结束一个主索引的定义。它必须出现在一个MASTER_START宏调用之后。
IFNDEF???masterName
.ERR<MASTER_END:一个主索引未以MASTER_START开始>
ELSEIFIDNI???masterName,<MASTER_LIST_CLOSED>
.ERR<MASTER_END:主索引已经以MASTER_END关闭>
ELSE
SAVE_MASTER_INFO 0
masterIndexSegment ENDS
???masterName CATSTR<MASTER_LIST_CLOSED>
ENDIF
ENDM
核对一个主索引被打开。保存一个空的主列表入口以标记列表的结束。关闭主索引段并将???masterName标记为MASTER_LIST_CLOSED。
5.14 MASTER_ENTRY宏
MASTE-ENTRY宏由本发明用来将一个列表入口插入主索引。
MASTER_ENTRY MACRO keyName
MASTER_ENTRY宏必须在一个MASTER_START宏调用之后和一个MASTER_END宏调用之前。其参数是:
keyName-用于在一个指定列表入口和这个主索引位置之间创建一个联系的名字。它必须是排序键(主索引)或列表入口名字(锁定索引)。
IFNDEF???masterName
.ERR<MASTER_ENTRY:一个主索引列表还未以MASTER_START打开>
ELSE
IFDIF???masterName,<MASTER_LIST_CLOSED>
% SAVE_MASTER_INFO keyName
ELSE
%.ERR<MASTER_ENTRY:主索引列表已经MASTER_END关闭>
ENDIF
ENDIF
ENDM
检查一个主列表已经开始。调用SAVE_MASTER_INFO宏以存储排序键或列表入口名字。
5.15 SAVE_MASTER_INFO宏
SAVE_MASTER_INFO宏是一个内部宏,向本发明提供一个必需的功能,并且从不由源代码文件直接调用。
SAVE_MASTER_INFO MACRO keyName
IFDIF<keyName>,<0>
DB ′&keyName′ ;索引名字
ENDIF
DB 0 ;空值结束该串
ENDM
SAVE_MASTER_INFO宏在由前面的MASTER_START宏调用打开的专用段中保存由其参数指定的keyName。
6. 包含宏
6.1 PUBLIC_INCLUDE_START宏
PUBLIC_INCLUDE_START宏由本发明用来识别一个公共include文件。PUBLIC_INCLUDE_START宏及其参数由本发明扫描,这样可以将它们与包括文件的PUBLIC宏的参数进行比较。
include文件驻留在其中在逻辑上“拥有”定义的组件中。如果定义将要由其他目录中的其他组件使用,则include文件通过使用PUBLIC_INCLUDE_START宏将自身声明为公共的。外部组件将使用由一个PUBINC宏指定的类/子类和文件名引用include文件。使用的include文件的物理位置将由建立过程来确定。
类似于接口,一个公共include文件的用法将包括用于文件的所期望的“接口”的大和小版本(不是文件版本)。
PUBLIC_INCLUDE_START MACRO classPath,version
PUBLIC_INCLUDE_START宏标记一个可以由其他目录中的其他组件使用的公共include文件的开始。其参数是:
classPath一类名和零或多个子类名,以句点(.)分隔;以及
version-用于文件的所期望的接口的大.小版本号。
IFB<version>
.ERR<PUBLIC_INCLUDE_START:!用于公共include的版本号被遗漏>
ENDIF
IFB<classPath>
.ERR<PUBLIC_INCLUDE_START:类路径信息被遗漏>
ENDIF
ENDM
核对classPath和version参数都已经被指定。
从include文件扫描每个PUBLIC_INCLUDE_START宏调用的参数,并与include文件名字和目录路径一起输入一个数据库。这允许BIOS开发系统在编译之前将它从include文件扫描的任何接口信息与来自包括它的源文件的接口信息合并。
6.2 PUBINC宏
PUBINC宏由本发明用来包括一个在不同组件中定义的公共include文件。PUBINC宏及其参数由本发明扫描,这样可以将它们与定义该文件的PUBLIC_INCLUDE_START宏的参数进行比较。
PUBINC MACRO classPath,fileName,version
PUBINC宏将一个外部include文件包括在构件中。外部include文件在当前目录和组件的外面。其参数是:
classPath-类名和零或多个子类名,以句点(.)分隔;
fileName-include文件的名字;以及
version-用于文件的期望的大.小版本号。
用法:“PUBINC post.dispatcher,postdisp.inc,1.0”。
LOCAL ???incPath
由该宏使用的局部变量。
IFNB<classPath>
IFNB<fileName>
GET_SYMBOL_NAME classPath
???incPath CATSTR<I_>,???symbol
% INCLUDE???incPath\\fileName
IFB<version>
.ERR<PUBINC:include文件!版本被遗漏>
ENDIF
ELSE
.ERR<PUBINC:include文件名字被遗漏>
ENDIF
ELSE
.ERR<PUBINC:include文件特征路径被遗漏>
ENDIF
ENDM
确认所有参数都存在。调用GET_SYMBOL_NAME宏以返回包含类路径的全局变量???symbol,其中以下划线(_)代替每个句点(.)。通过以I_放在???symbol的值的前面,形成包含include文件的目录路径的全局变量的名字。如果类路径是post.dispatcher,则???incPath是I_post_dispatcher。以一个使用全局变量中的目录路径的INCLUDE指令(即,命令)包括该文件。
BIOS开发系统产生一个包括在源代码库中的每个源代码文件中的特征include文件“feature.inc”。它为由包含include文件的目录路径的PUBINC宏调用声明的每个公共include文件定义一个全局变量,例如,I_post_dispatcher TEXTEQU<@Environ(MANTICORE)\post\dispatcher>。
附录A:用于平台类型桌面的源库
c:\BIOS\core的目录
4-26-99 1:23p 11,645 bda.inc
7-23-99 7:42a 795 beep.obj
7-23-99 7:42a 453 chksum.obj
7-23-99 7:42a 559 compat.obj
7-23-99 7:42a 18,564 compnent.exe
7-28-99 9:48p 1,110 compnentinf
7-23-99 7:42a 803 compnent.map
7-23-99 7:42a 2,261 dispinit.obj
7-23-99 7:42a 1,423 dispintf.obj
7-23-99 7:42a 871 disputil.obj
7-23-99 7:42a 4,274 exe.obj
7-23-99 7:42a 675 fillint.obj
7-23-99 7:42a 577 getnext.obj
7-22-99 10:44a 3,988 makefile
7-23-99 7:42a 3,08O module.obj
7-23-99 7:42a 1,529 service.obj
c:\BIOS\core\beep的目录
4-26-99 2:15p 4,448 beep.asm
4-26-99 1:20p 1,375 featuire.inc
5-24-99 10:19a 1,058 feature.inf
c:\BIOS\devref\intel\440bx的目录
7-22-99 2:49p 143,245 binlink.out
7-22-99 2:49p 262,144 bios.rom
6-29-99 9:15a 1,503 bios.scr
6-03-99 12:14p 44,823 devutils.asm
7-22-99 2:49p 313 dispat-1.out
6-25-99 8:25a 4,865 dmainit.asm
7-29-99 7:20a 245hook.asm
7-28-99 l2:06p 5,809 init.asm
7-22-99 9:01a 3,514 makefile
7-22-99 2:49p 34,650 modules.out
7-29-99 1:l2p 245 myfile.asm
8-12-99 4:38p 113 platform.cfg
8-12-99 4:38p 113 platforsold
6-16-99 3:39p 4,142 register.asm
7-22-99 2:49p 2,401 stackl#1.out
7-22-99 2:49p 1,651 tasklist.out
附录B:列表管理器组件
1.概述
许多组件需要创建和管理来自BIOS的多个组件的相关数据结构的列表的能力。列表的例子可见于安装程序、POST任务、即插即用设备节点、SMI处理程序和其他。这个文件描述了与Manticore的列表管理相联系的设计、宏和函数。
2.相关文件
Manticore高级设计说明 | Frances Cohen,MarcSandusky,Robert Lusinsky,Marc Bombet |
Manticore BIOS源代码低级设计说明 | Frances Cohen |
3.使用的术语
下面是在这个文件中使用的术语的列表。
List-排序的相同尺寸的数据结构(列表入口)的阵列,以列表名字引用。
List Data-放在ROM图象中的实际数据。不包括键、名字或优先权。
List Entry-与相关的名字、键和优先权一起组成一个列表的单个数据结构。
List Header-放在最终ROM图象中的列表之前的小结构,包含入口数和每个入口的尺寸。
List Name-标识-个列表的唯一的名字。
List Owner-创建列表的组件。
List Manager-控制对列表的访问并提供普通实用函数的组件。
Master Index-对于一特定列表的所有可能的列表入口键的列表。不是所有列表都有主索引。根据这个文件内键的位置来对列表入口排序。对于一个列表的所有可能的键必须出现在主索引中。
Locked Index-用于保证列表入口的准确顺序的主索引的专用形式。根据这个文件内列表入口名字(不是排序键)的位置来对列表入口排序。
4.设计
列表是排序的相同尺寸的数据结构(称为列表入口)的阵列,以列表名字引用。一个组件(称为列表所有者)创建列表,给予其名字和格式,并分配列表在BIOS执行期间将存在的位置。任何其他组件(包括列表所有者)可以使用列表名字向列表添加列表入口、对其排序并将其写出到BIOS。二进制链接程序还修正到列表和列表入口的引用。
二进制链接程序实用程序将排序的列表数据放在ROM图象中。其布局依赖于在列表声明中找到的段属性。二进制链接程序将一个列表标题放在列表数据之前,该标题包含列表入口的数目。
偏移 | 长度 | 描述 |
0 | 2 | 列表入口的数目 |
2 | 2 | 每个列表入口的尺寸(字节) |
图2:列表标题
列表标题总是以段落对齐的。从列表名字创建的公共标号指向列表标题。列表标题的尺寸不保证,可以在将来的版本中改变。
4.1 创建一个列表
每个列表必须由自己的组件/特征使用LIST_CREATE宏(第10页)创建一次。如果使用一个主索引对列表排序,则主索引文件也是自己的组件的一部分。如果以同一名字创建两个列表,二进制链接程序将产生一个错误。
LIST_CREATE devnodes,1.0,devNodeListStruct
列表必须具备三个内容:名字、版本号和入口尺寸。名字必须不与任何其他列表或过程相冲突。
列表版本号指示列表的结构或函数中的变化。版本号由两部分组成,大版本和小版本,中间以句点间隔!!较大的数表明较新的修订版。当大版本改变时,具有较低或较高大版本的任何列表入口将使二进制链接程序产生一个错误。当小版本改变时,具有较大小版本的任何列表入口将使二进制链接程序产生一个错误。
入口尺寸是一个指定每个列表入口的列表数据的尺寸的数、合格类型(例如BYTE,WORD等)或结构名字。这个尺寸放在列表标题的第二个字段中。
4.2 创建一个入口
任何组件或特征可以使用LIST_START(第13页)、LIST_END(第11页)和LIST_ENTRY(第11页)宏向一个列表添加列表入口。
LIST_START pnp.devnodes,1.0,devNodeListStruct
LIST_ENTRY pnpDEVNodeName,<(…)>
LIST_END
4.2.1 LIST_S TART用法
LIST_START开始一块列表入口,给出对所有入口都一样的信息,包括列表名字、列表版本号、列表入口尺寸和列表入口超覆优先权。
LIST_START listName,listVersion,entrySize,overridePriority
列表名字在列表名字之后给出列表所有者(就向函数名一样)。如果为一个不存在的列表创建列表入口,二进制链接程序产生一个警告。
列表版本号指示后面的列表入口是为列表的指定修订版设计的。将版本号分成两部分:大版本和小版本。较大的数表明较新的修订版。当列表入口的大版本不等于列表的大版本时,二进制链接程序产生一个错误。当列表入口的小版本高于列表的小版本时,二进制链接程序产生一个错误。
列表入口尺寸指定每个列表入口的列表数据占用多少个字节。这必须是一个MASM合格类型(即,BYTE,WORD等)或结构名字。
附加选项列表入口超覆优先权指定后面的列表入口是否将替换具有相同名字但较低超覆优先权的现有列表入口。对于这个字段目前有三个预定值:CORE(用于核心代码)、PRODUCT(用于生产线代码)、PLATFORM(用于平台代码)。如果未指定,缺省值是CORE。
例如,采用超覆优先权“CORE”,核心可以指定POST任务x将出现在测试点50。然而,客户具有生产线y,其中所有平台将POST任务x重新定位到测试点90。因此,客户在一个OEM“生产线”组件中创建另一个列表入口,并使用超覆优先权“PRODUCT”。最后,在生产线y,有一个断裂了铸模的单个平台,想要将POST任务x移回到测试点33。因此客户在OEM“平台”组件中创建另一个列表入口,并使用超覆优先权“PLATFORM”。
当二进制链接程序看到具有相同名字但不同超覆优先权的多个列表入口时,它优先于PRODUCT选择PLATFORM和优先于CORE选择PRODUCT。
4.2.2 LIST_ENTRY用法
LIST_ENTRY描述关于一单个列表入口的信息,包括其名字、列表数据、其排序键和排序优先权。
LIST_ENTRY entryName,<listData>,sortPriority,sortKey
列表入口名字(与列表入口超覆优先权一起)在列表内唯一地标识该列表入口。列表入口名字可以用作一个指向列表数据的标号。它还可用于排序和超覆。如果找到具有相同超覆优先权的另一个列表入口,二进制链接程序产生一个错误。
列表数据在角括号中包含要放在列表类型(来自LIST_START)之后的准确数据。结构必须包含另外的花括号“{”和“}”。这是将实际出现在ROM图象中的数据。
排序键和排序优先权确定列表内的列表入口的顺序排列。排序键是标准名字或是空的。如下面的表所示,顺序排列行为依赖于排序键和一个主索引或锁定索引的存在:
排序键存在? | 主索引存在? | 锁定索引存在? | 结果 |
否 | 否 | 否 | 根据排序优先权对列表入口排序 |
否 | 否 | 是 | 根据锁定索引中的名字的顺序对列表入口排序。如果在锁定索引中未找到列表入口名字则产生错误。 |
否 | 是 | 否 | 错误(主索引需要排序键) |
否 | 是 | 是 | 错误(主索引需要排序键) |
是 | 否 | 否 | 错误(排序键需要主索引) |
是 | 否 | 是 | 错误(排序键需要主索引) |
是 | 是 | 否 | 根据主索引中的排序键的顺序对列表入口排序。如果在主索引中未找到排序键则产生错误。 |
是 | 是 | 是 | 根据锁定索引中的名字的顺序对列表入口排序。如果在锁定索引中未找到列表入口名字则产生错误。 |
4.2.3 LISI_END用法
LIST_END标记一块列表入口的结束。
4.3 使用一个列表
列表管理器(listmgr)提供用于访问列表的实用函数。对于函数的一个完全列表,参见公共函数(第4页)。这个部分提供使用列表管理器来用于普通任务的准则。
4.3.1 找到一个列表的开始
找到一个列表的开始有两个步骤:
1.或者创建列表(LIST_CREATE,第10页),或者将其声明为外部的(PUBEXT)。
2.采用LOADADDR加载列表的地址。
例如,
PUBEXT posttask,1.0,SUBSTITUTE
LOADADDR posttask ;GS:DI-列表标题
SUBSTITUTE属性与PUBEXT一起使用,这样,如果列表没有入口,GS和DI将包含0xFFFF。列表管理器通过检查用于该值的DI来检测空列表。如果使用了OPTIONAL(而不是SUBSTITUTE),则如果列表为空LOADADDR将不产生代码。在没有SUBSTITUTE或OPTIONAL的情况下,如果列表为空,LOADADDR将使二进制链接程序产生一个错误。
4.3.2 通过一个列表的循环
为了处理列表中的所有入口,列表管理器提供getNext函数。
例如,
ExTINC listMgr,listmgr.inc,1.0;具有列表管理器宏
PUBEXT posttask,1.0,SUBSTITUTE
PUBEXT listMgr.getNext,1.0
LOADADDR posttask ;GS:DI=列表标题
loopl:
EXTCALL listMgr.getNext ;GS:DI=第一入口
Jc exitLoopl ;列表的结束
...Your code here...
jmp loopl
exitLoopl:
4.4 主索引
二进制链接程序使用主索引来对具有排序键的列表入口排序。每个列表至多有一个主索引。主索引是.ASM文件,通常在列表自己的组件中找到,但是是一个单独的文件,以便于超覆。使用三个宏MASTER_START,MASTER_ENTRY和MASTER_END来创建主索引。
例如,
MASTER_START post.postTask
MASTER_ENTRY TpVerifyRealMode ;第一POST任务
MASTER_ENTRY TpChipsetlnit ;第二POST任务
MASTER_ENTRY TpVideolnit ;第三POST任务
…
MASTER_END
MASTER_START后面的名字是列表名字(每个LIST_CREATE)。MASTER_ENTRY后面的名字是排序键,如在列表入口中所找到的。
二进制链接程序根据主索引中的排序键的顺序对列表入口排序。二进制链接程序将产生一个错误,如果:
1.列表入口具有一个排序键,但没有为列表指定主索引。
2.在主索引中不能找到用于列表入口的排序键。
3.找到主索引,但没有相应的列表。
主索引文件可以被正常地超覆。
4.5 列表输出
二进制链接程序将列表的最终内容输出到一个名字为listname.out的可汇编文件中,其中listname是到列表的完全合格的组件路径。例如,列表post.PostTasks的内容将被输出到post.postTasks.out。
列表输出文件具有一个意义明确的格式,它被分成两个部分:注释和代码。注释部分包含关于最终列表内容的人(和调试程序)可读的信息,包括为每个列表入口产生的实际的二进制数据。代码部分包含一个锁定索引,描述构件中的列表入口的准确顺序。列表输出文件可以用作一个锁定索引文件。对于更多的信息参见锁定索引(第7页)。
4.5.1 注释部分
注释部分开始于以标记“;$$COMMENTSTART$$”作为第一个非空格字符的新的一行。注释部分结束于以标记“;$$COMMENTEND$$”作为第一个非空格字符的新的一行。注释部分内的所有行必须以“;”作为第一个非空格字符开始。
在任何其他注释部分语句出现之前,关键字“CommentVersion(x.x)”必须出现,其中x.x是注释部分格式的大小版本号。大版本号表示不向后兼容的改变。小版本号表示向后兼容的改变。
随后是描述列表的LIST_CREATE,LIST_START和LIST_ENTRY宏,就象所有的列表声明语句都已经在一单个.ASM文件(包括超覆的版本)中完成一样。其中有两个不同。首先,所有行都以“;”加在前头。其次,由LIST_ENTRY宏产生的实际的十六进制数据出现紧接在LIST_ENTRY宏之后的一行上(每行16个字节)。
例如:
;$$COMMENTSTART$$
;CommentVersion(1.0)
;
;LIST_CREATE postTask,1.0,postTaskStruct
;LIST_START postTask,1.0,postTaskStruct
;*LIST_ENTRY postEntry1,<(...),TpPost Entry1,0x8000
; ;8000F00869
;LIST_ENTRY postEntry1,<(...)>,TpPostEntry2,0x4000,
SORT_KEY+SORT_PRIORITY
; ;8000F00973
;LIST_ENTRY postEntry2,,(...).,TpPostEntry2,0x8000
;8000F00A90
; …
;LIST_END
;$$COMMENTEND$$
4.5.2 代码部分
代码部分包含锁定索引形式的准确列表次序排列。对于更多信息参见第7页。
4.6 锁定索引
锁定索引是主索引的特殊形式,由OEM用来修正列表中的列表入口的次序排列。锁定索引不是使用排序键来确定列表入口的最终次序排列,而是使用列表入口名字。每个列表至多可以有一个锁定索引。通常,锁定索引是列表输出文件的重命名的版本(参见第6页)。
锁定索引采用与主索引相同的宏来创建,除了MASTER_START具有指定为第二参数的属性LOCKED。对于更多信息参见MASTER_START(第14页)。
二进制链接程序产生一个错误,如果:
1.为一个还未以LIST_CREATE创建的列表找到一个锁定索引。
2.在锁定索引中未找到一个列表入口名字。
3.一个入口出现在没有相应的列表入口的锁定索引中。
4.7 二进制链接程序信息
每个所述宏必须将信息放在要由二进制链接程序使用的组件的图象内。这些数据结构的细节如下:
列表结构段:listDeclarationSegment | ||
名字 | 尺寸 | 说明 |
ListName0ListSegment0listEntrySize | STRINGBYTESTRINGBYTEWORD | 列表名字串的空值结束列表段名字串的空值结束由每个列表入口占据的字节数 |
listVersion0listAttribute | STRINGBYTEBYTE | 列表版本号的原始串串的空值结束位0:<0>=1—所有列表入口是公共的,不管单个列表入口的属性。<0>=0—所有列表入口是私人的,除非列表入口采用列表入口属性声明为公共的。位1-7:保留 |
列表入口结构
段:listEntrySegment
下面的结构用于插入列表入口、超覆列表入口的排序顺序和超覆列表入口的数据。每个结构以列表名字开始,后面是一个NULL字节和一个用于结构类型的字节。结构类型表示在结构中表示的修正信息的类型。
列表入口—修正类型1
名字 | 尺寸 | 描述 |
Listname01entryName0sortKey0sortPrioritysortOverridedataOverride | STRINGBYTEBYTESTRINGBYTESTRINGBYTEWORDBYTEBYTE | 列表名字空值结束串修正类型(列表入口)列表入口名字空值结束串排序键空值结束串入口的优先权排序顺序超覆优先权(在LIST_START宏中给出的等式超覆优先权)。较小数具有较高的优先权。具有相同入口名字的项的优先权(在LIST_START宏中给出的等式超覆优先权)。较小数具有较高的优 |
entryAttribslistEntrySizelistDatalistData0 | BYTEWORDlistEntrySizeSTRINGBYTE | 先权。位0:1=公共,0=私人位1:1=标号,0=无标号位2-7:保留由每个列表入口占据的字节数。尺寸必须与LIST_CREATE中的尺寸相匹配,否则工具将产生一个错误。列表数据。在长度上总是准确地为listEntrySize字节。原始列表入口文本空值结束串 |
排序超覆—修正类型2
名字 | 尺寸 | 描述 |
Listname02entryName0overridePrioritysortKey0sorPriority | STRINGBYTEBYTESTRINGBYTEBYTESTRINGBYTEWORD | 列表名字空值结束串修正类型(排序超覆)列表入口名字空值结束串具有相同入口名字的其他时间上的项的优先权。较小数具有较高的优先权。排序键空值结束串入口的优先权。较高数具有较高的优先权。 |
列表数据超覆—修正类型3
名字 | 尺寸 | 描述 |
ListName03 | STRINGBYTEBYTE | 列表名字空值结束串修正类型(列表数据超覆) |
entryName0overridePriorityattributeslistEntrySizelistDatalistData0 | STRINGBYTEBYTEBYTEWORDlistEntrySizeSTRINGBYTE | 列表入口名字空值结束串具有相同入口名字的其他时间上的项的优先权。较小数具有较高的优先权。位0:1=公共,0=私人位1:1=标号,0=无标号位2-7:保留由每个列表入口占据的字节数。尺寸必须与LIST_CREATE中的尺寸相匹配,否则工具将产生一个错误。列表数据。在长度上总是准确地为listEntrySize字节。原始列表入口文本空值结束串 |
主索引/锁定索引
段masterIndexSegment
名字 | 尺寸 | 描述 |
ListName0listAttibutesindexName0 | STRINGBYTEWORDSTRINGBYTE | 列表名字列表名字的空值结束位0:0=主索引,1=锁定索引位1-15:保留包含索引的串。最后一个索引具有长度0(即,只有0x00)。索引名字的空值结束 |
5. 公共宏
5.1 LIST_CREATE
描述:创建一个列表。列表名字在所有组件中必须是唯一的。
列表名字将变成一个指向最终ROM图象中的列表标题的
公共标号。其他BIOS代码可以使用LOADADDR来检索地
址。列表放在使用LIST_CREATE宏的段中。
二进制实用程序使用信息来对列表排序并将其放在ROM
中所希望的位置。它还采用指定列表名字创建一个输出
文件,该指定列表各带有扩展名‘.out’。文件的格式在
列表输出中描述(第6页)
例子:
LIST_CREATE devnodes,1.0,devNodeListStruc
LOADADDR devnodes;GS:DI=devnodes列表的开始
入口: 名字 listName。表示这个列表的唯一的名字。名
字必须只包含标准符号字符(A...Z,a...z,
0...9或′_′)
版本 listVersion。大.小版本号。增大的号表
示较新的版本。
数字|合格 listEntrySize。每个列表入口占据的字节
类型|结构 数。可以是数字、MASM合格类型的名字
名字 (BYTE,WORD等)或结构名字。
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_ENTRY (第11页),LIST_START(第13页),
LIST_END(第11页)
5.2 LIST_DATA
描述: 为一个已经存在的列表入口改变所有或一部分列表数
据。必须出现在LIST_START和LIST_END之间,超覆优
先权必须是PLATFORM或PRODUCT。
入口: 名字 entryName。将使其列表数据改变的列表
入口的名字。
结构|数字 NewListData。新列表数据。必须包括在
角括号(<abd>)中。要超覆的部分是由
overrideOffset和overrideSize指定
超覆的部分。
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_ENTRY(第11页),LIST_SORT(第12页)
5.3 LIST_END
描述: 用于向一个列表声明一个入口,只有记录数据将保留在
ROM图象中。其他数据由构件实用程序用来对数据排序。
任何组件可以向列表提供一个入口。
入口: 无
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_START(第13页),LIST_ENTRY(第11页)
5.4 LIST_ENTRY
描述: 创建一个列表入口。必须用在LIST_START之后和
LIST_END之前。二进制链接程序将只为ROM中的入口放
置列表数据。
入口: 名字 entryName。单个列表入口的名字。在列表
内必须是唯一的。
结构|数字 listData。在运行时组成列表入口的主体
的数据。数据必须包括在角括号中。数据
必须是在LIST_START的listType参数中
指定的类型。
数字 sortPriority。用于以相同的排序键对项
排序。小数放在大数的前面。最小值是0,
最大值是65535(0xFFFF),缺省值是32768
(0x8000)。
串 sortKey。用于将项与一个主引用列表相匹
配。缺省使用项的入口名字作为排序键。
串必须只包含标准符号字符(A...Z,a...z,
0...9,′_′)。
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_CREATE(第10页),LIST_START(第13页),
LIST_END(第11页)
5.5 LIST_PRIVATE_LABEL
描述: 创建一个列表入口标号。必须用在LIST_START之后和
LIST_END之前。标号只能在声明该标号的组件内被访
问。
入口: 名字 entryName。单个列表入口的名字。在列表内必
须是唯一的。
数字 sortPriority。用于以相同的排序键对项排
序。小数放在大数的前面。最小值是0,最大值
是65535(0xFFFF),缺省值是32768(0x8000)。
串 sortKey。用于将项与一个主引用列表相匹配。
缺省使用项的入口名字作为排序键。串必须只
包含标准符号字符(A...Z,a...z,0...
9,′_′)。
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_CREATE(第10页),LIST_START(第13页),
LIST_END(第11页)
5.6 LIST_PUBLIC_LABEL
描述: 创建一个列表入口标号。必须用在LIST_START之后和
LIST_END之前。标号可以从任何地方访问。
入口: 名字 entryName。单个列表入口的名字。在列表内
必须是唯一的。
数字 sortPriority。用于以相同的排序键对项排
序。小数放在大数的前面。最小值是0,最大
值是65535(0xFFFF),缺省值是32768
(0x8000)。
串 sortKey。用于将项与一个主引用列表相匹
配。缺省使用项的入口名字作为排序键。串必
须只包含标准符号字符(A...Z,a...z,0...
9,′_′)。
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_CREATE(第10页),LIST_START(第13页),
LIST_END(第11页)
5.7 LIST_SORT
描述: 为一个已经存在的列表入口改变排序标准。必须出现在
LIST_START和LIST_END之间,超覆优先权必须是
PLATFORM或PRODUCT。
入口: 名字 entryName。将使其排序顺序改变的列表入口
的名字。
数字 NewSortPriority。用于以相同的排序键对项
排序。小数放在大数的前面。最小值是0,最
大值是65535(0xFFFF),缺省值是32768
(0x8000)。
串 sortKey。用于将项与一个主引用列表相匹
配。缺省使用项的入口名字作为排序键。串必
须只包含标准符号字符(A...Z,a...z,0...
9,′_′)。
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_ENTRY(第11页),LIST_DATA(第10页)
5.8 LIST_START
描述: 开始添加入口到指定列表的指定版本。
入口: 名字 listName。所有列表入口将被添加到这个列
表。如果在构件中有用于一个还未使用
LIST_CREATE声明的列表的列表入口,二进制
链接程序将产生一个警告
版本 listVersion。由listName指定的列表的大.
小版本号。
合格类型 listType。每个列表入口的数据类型。可以是
结构名字 MASM合格类型(BYTE,WORD等)或结构名字。
关键字 overridePriority。当在构件中找到两个具
有相同名字的入口时,这个值允许二进制链接
程序选择一个。CORE具有较低优先权,
PRODUCT其次,PLATFORM最高。
退出: 无
记录: 段:任何段
文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: LIST_CREATE(第10页)
5.9 MASTER_END
描述: 结束一个主索引的定义。必须出现在LIST_START宏之
后。
入口: 无
退出: 无
记录: 文件:.\CORE\LISTMGR\LISTMGR.INC
还参阅: MASTER_START(第14页),MASTER_ENTRY(第10页)
5.10 MASTER_ENTRY
描述: 将一个列表入口插入主索引中。必须在MASTER_START
之后和MASTER_END之前。
入口: 名字 keyName。用于创建在一具体列表入口和这个
主索引位置之间的关联的名字。是排序键(主
索引)或列表入口名字(锁定索引)。
退出: 无
记录: 文件: .\CORE\LISTMGR\LISTMGR.INC
参阅: MASTER_START(第14页),MASTER_END(第13页)
5.11 MASTER_START
描述: 开始一个主索引的定义。必须出现在任何MASTER_ENTRY
或MASTER_END宏之前。
入口: 名字 listName。这个索引与其相联系的完全合格的
列表名字(包括组件路径)的名字。
关键字 indexAttribute。如果LOCTED,则这是一个
锁定索引。否则,是一个主索引。
退出: 无
记录: 文件: .\CORE\LISTMGR\LISTMGR.INC
参阅: MASTER_END(第13页)
6.公共函数
下面是可从列表管理器得到以访问一个列表的函数的表。可以使用一个堆栈的所有代码应该使用列表管理器来导航其列表。
6.1
描述: 执行列表中的所有函数,以指定列表入口开始,一直继
续到列表的结束。假设列表入口数据结构的第一个DWORD
包含对该函数的远程指针。
该函数具有下列参数:
入口 GS:DI 在传到listmgr.exec时指向列表
EAX,EBX 入口
ECX,EDX,
ESI
退出 NONE
该函数必须是基于堆栈的。
例子:
LOADADDR myList
EXTCALL listmgr.execnc
入口: GS:DI 指向要执行的第一个函数。如果DI=0,在列表
的开始处开始。如果DI=0FFFFh,立即退出。
退出: 无
记录: 段: POST,RUNTIME
还参阅: Listmgr.execnc(第15页)
6.2 listmgr.execnc
描述: 执行列表中的函数,以指定列表入口开始,直到一个返
回进位组(CY)或到达列表的结束。假设列表数据结构
的第一个DWORD包含对该函数的远程指针。
该函数具有下列参数:
入口 GS:DI 在传到listmgr.exec时指向列表
EAX,EBX 入口
ECX,EDX,
ESI
退出 EAX,EBX 由最后一个函数返回
ECX,EDX,
ESI
该函数必须是基于堆栈的。
例子:
LOADADDR myList
EXTCALL listmgr.execnc
入口: GS:DI 列表段。如果DI=0,在列表的开始处开始。如
果DI=0FFFFh,立即退出。
退出: 无
记录: 段:POST,RUNTIME
还参阅: Listmgr.exec(第14页)
6.3 listmgr.getCount
描述: 返回列表中的入口数
入口: GS 列表段。
退出: CX 列表中的入口数。0=空列表
记录: 段:POST,RUNTIME
还参阅: 无
6.4 listmgr.getNext
描述: 返回到列表中的下一个入口的指针,或者如果在列表中
再没有入口,返回一个错误。
例子:
LOADADDR myList
processList:
EXTCALL listmgr.execnc
jc processListExit
…
jmp processList
processListExit:
入口: GS:DI 指向列表中的当前入口。如果DI=0,则返回列
表中的第一入口。
退出: CY 列表中再没有入口。DI未定义。
NC GS:DI 指向列表中下一个入口
记录: 段: POST,RUNTIME
参阅: 无
6.5 listmgr.getNth
描述: 返回到列表中一特定入口的指针,或者如果在列表中再
没有入口,返回一个错误。
例子:
LOADADDR myList
Mov cx,itemnumber
EXTCALL listmgr.getNth
Jc noList
…
noList:
入口: GS 指向当前列表。
CX 入口的索引
退出: CY 列表中没有这样的入口。
NC GS:DI指向列表中第CX个入口。
记录: 段:POST,RUNTIME
参阅: 无
附录C
宏用法和数据采集
宏: PUBLIC_PROC Name,Version[,INTERCEPT]
描述: 标记一个可以从其他组件调用的过程的开始。必须
与END_PROC 匹配。
例子:
PUBLIC_PROC memc.shadow.Config,1.0
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后
面可以跟着零或多个字母、数字或下划
线。
版本 Version。大.小版本号。具有不同大版本
的调用程序是不兼容的。具有相同大版本
但较大小版本的调用程序是不兼容的。增
大小版本表示向后兼容性。
关键字 Intercept。如果提供了INTERCEPT,表
明如果有多个定义二进制链接程序将使
用声明。
宏: PRIVATE_PROC Name,Version[,Attributes]
描述: 标记一个只能从声明它的组件内调用的过程的开
始。必须与END_PROC匹配。
例子:
PRIVATE_PROC memc.shadow。NextTableItem,
NO_VER
PRIVATE_PROC memc.shadow。OemSet,1.0,NEAR
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后发 面可以跟着零或多个字母、数字或下划
线。
版本 Version。大.小版本号。具有不同大版本
的调用程序是不兼容的。具有相同大版本
但较大小版本的调用程序是不兼容的。增
大小版本表示向后兼容性。
只在标号定义在组件的外面、例如一个共
享文件或oem hook时使用版本;否则,
使用NO_VER。
关键字 Attributes。
NEAR:该过程只能在段内访问。如果这个
属性未提供,则宏缺省到FAR。
宏: LOCAL_PROC Name,scope
描述: 标记一个只能从声明它的文件内调用的过程的开
始。必须与END_PROC 匹配。
例子:
LOCAL_PROC NextItem,NEAR
LOCAL_PROC CalculateCRC,FAR数据库用法: 名字 Name。遵循MASM命名惯例的名字。
关键字 Scope。过程的范围。有两种可能性:
FAR:过程可以在段间访问。
NEAR:过程只能在段内访问。
宏: END_PROC
描述: 标记一个过程的结束。必须与前面的PUBLIC_PROC
或PRIVATE_PROC匹配。
例子:
END_PROC
数据库用法:无
宏: PUBLIC_LABEL Name,Version[,INTERCEPT]
描述: 创建一个可以从其他组件使用的用于代码执行的标
号。例如,创建固定入口点。
例子:
PUBLIC_LABEL memc.memory.OemSize,1.0
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后
面可以跟着零或多个字母、数字或下划
线。
版本 Version。大.小版本号。具有不同大版本
的调用程序是不兼容的。具有相同大版本
但较大小版本的调用程序是不兼容的。增
大小版本表示向后兼容性。
关键字 Intercept。如果提供了INTERCEPT,表
明如果有多个定义则二进制链接程序将
使用声明。
宏: PRIVATE_LABEL Name,Version
描述: 创建一个只能从声明标号的组件内使用的标号。例
如,创建固定入口点。
例子:
PRIVATE_LABEL pci.enum.Numdevices
db ?
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后面
可以跟着零或多个字母、数字或下划线。
版本 Version。大.小版本号。具有不同大版本
的调用程序是不兼容的。具有相同大版本
但较大小版本的调用程序是不兼容的。增
大小版本表示向后兼容性。
只在标号定义在组件的外面、例如一个共
享文件或oem hook时使用;否则,使用
NO_VER。
宏: FBM_LABEL Name
描述: 指定由二进制链接程序进行的将来二进制操纵
(FBM)。这个宏不产生任何代码。该宏通知扫描实
用程序和二进制链接程序该标号代表由二进制链接
程序在建立时产生的数据。
例子:
FBM_LABEL DisplayMgr.Fonts
数据库用法: 名字 Name。名字由三部分组成:类名、零或多个
子类名和实际函数名,以句点分隔。每个部
分必须以一个字母或下划线开始,后面可以
跟着零或多个字母、数字或下划线。
宏: PUBEXT Name,Version[,Attribute/Component
[,AltName]
描述: 声明对一个公共过程、公共标号、列表或公共列表
入口的外部引用。
注意:可以用在一个宏中,但不能用在由另一个宏
调用的宏中。
注意:不要用在IFDEF、IF等内部。
例子:
PUBEXT memc.shadow.Config,1.0,OPTIONAL
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后
面可以跟着零或多个字母、数字或下划
线。
不能包含任何宏参数。
版本 Version。大.小版本号。具有不同大版本
的调用程序是不兼容的。具有相同大版本
但较大小版本的调用程序是不兼容的。增
大小版本表示向后兼容性。
关键字 Attributes/Component。指定解析标号所
/串 必须的行动。
OPTIONAL:如果指定标号不存在,对标号
的引用将被去除。
ALTERNATE:如果指定标号不存在,将使用
备用名字标号。备用标号的特性(例如,
范围,版本等)将从用于该标号的前一个
PUBEXT继承。这里所用的所有备用标号必
须已经在前面由PUBEXT声明。
SUBSTITUTE:如果指定标号不存在,将使
用值0xFFFFFFFF(远)或0xFFFF(近)。
Component Name:当OEM例程截取一个函数
并希望调用原件时,在这里指定原始组件。
名字 AltName。如果名字不存在,如果属性(上
面)是ALTERNATE,则这是要使用的标号。
如果都不存在,产生一个错误。
宏: PRVEXT Name,Version[,Attribute[,AltName]
描述: 声明对一个私人过程或标号的外部引用。
注意:可以用在一个宏中,但不能用在由另一个宏
调用的宏中。
注意:不要用在IFDEF、IF等内部。
例子:
PRVEXT memc.shadow.Config,1.0,NEAR+
OPTIONAL
PRVEXT memc.shadow.Init,NO_VER
数据库用法:名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后面
可以跟着零或多个字母、数字或下划线。
不能包含任何宏参数。
版本/ Version。大.小版本号或NO_VER。具有不
关键字 同大版本的调用程序是不兼容的。具有相
同大版本但较大小版本的调用程序是不兼
容的。增大小版本表示向后兼容性。
只在标号定义在组件的外面、例如一个共
享文件或oem hook时使用版本;否则,使
用NO_VER。
关键字 Attributes。指定解析标号所必须的行
动。如果未指定属性,则由名字指定的标
号必须存在。
所有属性都是可选的。范围属性(NEAR)
可以与类型属性(OPTIONAL、ALTERNATE
或SUBSTITUTE)中的一个用“+”字符组
合起来。不能组合两个类型属性。在属性
字段内不允许多于一个的组合对。
NEAR:将过程声明为NEAR。如果这个属性
未提供给PRVEXT,FAR缺省。
OPTIONAL:如果指定标号不存在,对标号
的引用将被去除。
ALTERNATE:如果指定标号不存在,将使用
备用名字标号。备用标号的特性(例如,
范围,版本等)将从用于该标号的前一个
PRVEXT继承。这里所用的所有备用标号必
须已经在前面由PRVEXT声明。
SUBSTITUTE:如果指定标号不存在,将使
用值0xFFFFFFFF(远)或0xFFFF(近)。
名字 AltName。如果名字不存在,如果属性(上
面)是ALTERNATE,则这是要使用的标号。
如果都不存在,产生一个错误。
宏: EXTCALL Name[,[<CodeText>][,ComponentName]]
描述: 调用一个公共或私人过程。必须PUBEXT或PRVEXT
使用。
例子:
EXTCALL memc.shadow.Config,<jcexit>
数据库用法: 名字 Name。名字由三部分组成:类名、零或多个
子类名和实际函数名,以句点分隔。每个部
分必须以一个字母或下划线开始,后面可以
跟着零或多个字母、数字或下划线。
串 CodeText。如果PUBEXT/PRVEXT将函数列为
可选的,则如果被调用的例程在构件中,这
个代码将在调用之后汇编。
串 ComponentName。在OEM截取例程中,
EXTCALL必须指定哪一个组件将解析该调
用。
宏: EXTJMP Name[,[Register][,[<CodeText>]
[,ComponentName]]]
描述: 跳转到一个公共或私人过程。必须与PUBEXT或
PRVEXT结合使用。
例子:
EXTJMP memc.shadow.Config,<jcexit>
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后
面可以跟着零或多个字母、数字或下划
线。
关键字 ReturnRegister。将保存返回寄存器的16
位寄存器。缺省是不使用返回寄存器。
串CodeText。如果PUBEXT/PRVEXT将函数列
为可选的,则如果被调用的例程在构件
中,这个代码将在调用之后汇编。
串 ComponentName。在OEM截取例程中,
EXTJMP必须指定哪一个组件将解析该调
用。
宏: EXTPTR Name[,ComponentName]
描述: 跳转到一个公共或私人过程。必须与PUBEXT或
PRVEXT结合使用。
例子:
EXTPTR vga.pm.PowerDown
EXTPTR sio.com.pm.PowerDown
数据库用法: 名字 Name。名字由三部分组成:类名、零或多个
子类名和实际函数名,以句点分隔。每个部
分必须以一个字母或下划线开始,后面可以
跟着零或多个字母、数字或下划线。
串 ComponentName。在OEM截取例程中,EXTPTR
必须指定哪一个组件将解析该调用。
宏: LOADADDR
Name[,[SegmentReg][,[OffsetReg][ComponentName]]]
描述: 将一个公共或私人标号的地址加载进寄存器。必须
与PUBEXT或PRVEXT结合使用。
例子:
LOADADDR vga.pm.powerdown,es,di
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后
面可以跟着零或多个字母、数字或下划
线。
寄存器 SegmentReg。保存标号地址的段部分的寄
存器。缺省是GS。可以是任何一个16位段
寄存器。
寄存器 OffsetReg。保存标号地址的偏移部分的寄
存器。缺省是DI。可以是任何一个16位通
用寄存器。
串 ComponentName。在OEM截取例程中,
LOADADDR必须指定哪一个组件将解析该调
用。
宏: LOADOFF Name[,[OffsetReg][ComponentName]]
描述: 将一个公共或私人标号的地址加载进寄存器。必须
与PUBEXT或PRVEXT结合使用。
例子:
LOADOFF di,vga.pm.powerdown
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后
面可以跟着零或多个字母、数字或下划
线。
寄存器 OffsetReg。保存标号地址的偏移部分的寄
存器。缺省是DI。可以是任何一个16位通
用寄存器。
串 ComponentName。在OEM截取例程中,
LOADOFF必须指定哪一个组件将解析该调
用。
宏: LOADSEG SegmentReg,Name[,ComponentName]]
描述: 将一个公共或私人标号的地址加载进寄存器。必须
与PUBEXT或PRVEXT结合使用。
例子:
LOADSEG es,vga.pm.PowerDown
LOADSEG di,POST_DATA_SEGMENT
数据库用法 :寄存器 SegmentReg。保存标号地址的段部分的寄
存器。可以是任何一个16位寄存器。
名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后
面可以跟着零或多个字母、数字或下划
线。
串 ComponentName。在OEM截取例程中,
LOADSEG必须指定哪一个组件将解析该调
用。
宏: EXTREF
Name[,[StructureMember][,[ComponentName][,
Attribute]]]
描述: 修正一个结构成员以包含一指定公共或私人标号的
地址。必须与PUBEXT或PRVEXT结合使用。
例子:
Taskstruc
<TP_VGA,EXTREF(vga.pm.powerdown,taskstruc.
task>
数据库用法: 名字 Name。名字由三部分组成:类名、零或多
个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后面
可以跟着零或多个字母、数字或下划线。
名字 Structure Member-结构和成员名字。
串 ComponentName。在OEM截取例程中,EXTREF
必须指定哪一个组件将解析该调用。
属性 Attribute。
宏: EVALREF Instruction,Destination[,Source]
描述: 允许在一个指令内使用一个标号的地址。
例子:
EVALREF add,ax,<EXTREF(miser.timerValue,,)
>
数据库用法: 操作码 Instruction。一个80×86处理器指令。
寄存器/ Destination。公共/私人标号必须用该宏
立即数/ 内嵌的EXTREF来定义,并以角括号括
过程/标 (<>)起来。
号
寄存器/ Source。过程/标号必须用该宏内嵌的
立即数/ EXTREF来定义,并以角括号(<>)括起来。
过程/标
号
宏: PUBLIC_INCLUDE_START ClassHierarchy,Version
描述: 声明一个可以由其他组件使用的include文件的开
始。
例子:
PUBLIC_INCLUDE_START smimgr,1.0
数据库用法: 类路径 ClassHierarchy。类层次是以句点分隔的
类名和零或多个子类名。
版本 Version。大.小版本号。包括具有不同大
版本的这个版本号(使用PUBINC)的文件
是不兼容的。包括具有相同大版本但较大
小版本的文件是不兼容的。增大小版本表
示向后兼容性。
宏: PRIVATE_INCLUDE_START ClassHierarchy[,Version]
描述: 声明一个只能在当前组件内使用的include文件的
开始。
例子:
PRIVATE_INCLUDE_START debug
数据库用法: 类路径 ClassHierarchy。类层次是以句点分隔的
类名和零或多个子类名。
版本 Version。大.小版本号。包括具有不同大
版本的这个版本号(使用PRVINC)的文件
是不兼容的。包括具有相同大版本但较大
小版本的文件是不兼容的。增大小版本表
示向后兼容性。
只在文件驻留在组件的外面、例如一个共
享include文件时使用。
宏: PRVINC ClassHierarchy,FileName[,Version]
描述: 包含一个私Ainclude文件。
例子:
PRVINC post.dispatcher,postdisp.inc
数据库用法: 类路径 ClassHierarchy。类路径由两部分组成:
类名和零或多个子类名,以句点分隔。每
个部分必须以一个字母或下划线开始,后面
可以跟着零或多个字母、数字或下划线。
文件名 FileName。Include文件的名字。
版本 Version。大.小版本号。具有不同大版本
的include文件是不兼容的。如果
include文件具有相同大版本但较小的小
版本,则它们是不兼容的。增大小版本表
示向后兼容性。
只用于共享或OEM文件。
宏: PUBINC ClassHierarchy,FileName,Version
描述: 包含一个公共include文件。
例子:
PUBINC post.dispatcher,postdisp.inc,1.0
数据库用法: 类路径 ClassHierarchy。类路径由两部分组成:
类名和零或多个子类名,以句点分隔。每
个部分必须以一个字母或下划线开始,后面
可以跟着零或多个字母、数字或下划线。
文件名 FileName。Include文件的名字。
版本 Version。大.小版本号。具有不同大版本的
include文件是不兼容的。如果include文
件具有相同大版本但较小的小版本,则它们
是不兼容的。增大小版本表示向后兼容性。
宏: DESCRIPTION″DescString″
DESCRIPTION<描述的第一行\
描述的第二行>
描述: 过程的短概要。应该是调用程序感兴趣的信息而不
是内部技术信息。对于技术信息使用PROCESSING。
例子:
DESCRIPTION Set shadow contro1 registers to\
setting as requested from input\
command.>
数据库用法: 串 DescString。过程的描述。
宏: INPUT:
描述: 与MEM和REG宏(后面)一起用来描述函数的输入参数。
例子:
INPUT:
REG EAX,0,1FFFFh
数据库用法: 无
宏: OUTPUT:
描述: 与MEM和REG宏(后面)一起用来描述这个函数的
输出参数。
例子:
OUTPUT:
REG EAX,0,1FFFFh
数据库用法: 无
宏: MODIFIED:
描述: 与MEM和REG宏(后面)一起用来描述由这个函数
以未指定的方式修改的寄存器和存储器。
例子:
MODIFIED:
REG EAX,0,1FFFFh
数据库用法: 无
宏: MEM Name[,RangeStart,RangeEnd…]
描述: 传给这个函数的列表寄存器和适当的值。可以指定
多个范围。假设值是无符号的。
例子:
INPUT
MEM ES:[DI],0,1FFFFh
MEM iteration,0,5
数据库用法: 名字 Name。一个变量名或一个间接寄存器引用。
数 RangeStart。寄存器值将大于或等于这个数。
数 RangeEnd。寄存器值将小于或等于这个数。
宏: REG Register[,RangeStart,RangeEnd…]
描述: 传给这个函数的列表寄存器和适当的值。可以指定多
个范围。假设值是无符号的。
例子:
REG EAX,0,1FFFFh
数据库用法: 寄存器 Register。用作一个参数的寄存器的名字,
除了标准寄存器名字之外,还可以使用:
UEAX,UEBX,UECX,一个32位寄存器的上
UEDX,UESI,UEDI,半部分
UESP,UEBP
CFLAG,ZFLAG 进位标志或零标志
数 RangeStart。寄存器值将大于或等于这个数。
数 RangeEnd。寄存器值将小于或等于这个数。
宏: NONE
描述: 可以用REG或MEM宏的应有位置以指示无值(输入、
输出和修改)。
例子:
数据库用法:无
宏: OEM_HOOK
描述: 指示后面的标题信息是用于由函数提供的OEM异常
分支中的一个的。
例子:
OEM_HOOK
DESCRIPTION<Allow for customization before
configuration of\
PCI devices.All devices have been
enumerated.>
数据库用法:无
宏: CODE_SEGMENT_OPEN Attributes
描述: 标记一个代码段的开始。属性确定随后的代码的放置
和“生存期”。必须用SEGMENT_CLOS E来关闭。
例子:
CODE_SEGMENT_OPEN PRERAM+POST
数据库用法:数 Attributes。下面的关键字(除了加注解的)
可以用“+”组合:
POST 代码在存储器被初始化之后执行。
PRERAM 代码在存储器被初始化之前执行。
SMM 代码位于系统管理存储器中并在
SMM初始化之后执行。可以不与
SMI一起使用。
SMI 在SMI期间执行的代码。可以不与
SMM一起使用。
SMI 在SMI期间执行的代码。可以不与
SMM一起使用。
RUNTIME 在OS引导程序已经启动后执行的
代码。
BOOTBLOCK 在引导块的加电期间执行的代
码。
SIZE32BIT 32位代码段
PARAALIGN 在16字节边界上对齐的代码
LEGACYF000 位于8KB兼容块中的代码
宏: DATA_SEGMENT_OPEN Attributes
描述: 标记一个代码段的开始。属性确定随后的代码的放置
和“生存期”。必须用SEGMENT_CLOSE来关闭。
例子:
DATA_SEGMENT_OPEN POST
数据库用法:数 Attributes。下面的关键字(除了加注解的)
可以用“+”组合:
POST 要由POST任务访问的静态数据段。
SMM 在SMM中的静态数据段。
退出: 无
参阅: 错误!未找到引用源(页错误!未定义书签。)
宏: ASSUME_CODE_SEG SegmentReg,Attributes
描述: 强迫汇编程序以假设指定段寄存器指向包含指定属
性的段。
例子:
ASSUME_CODE_SEG DS,PRERAM+POST
数据库用法:寄存器 SegmentReg。使假设成立的段寄存器。
数 Attributes。下面的关键字(除了加注解
的)可以用“+”组合:
POST 代码在存储器被初始化之后
执行。
PRERAM 代码在存储器被初始化之前
执行。
SMM 代码位于系统管理存储器中
并在SMM初始化之后执行。可
以不与SMI一起使用。
SMI 在SMI期间执行的代码。可以
不与SMM一起使用。
RUNTIME 在OS引导程序已经启动后执
行的代码。
BOOTBLOCK 在引导块的加电期间执行的
代码。
SIZE32BIT 32位代码段
PARAALIGN 在16字节边界上对齐的代码
LEGACYF000 位于8KB兼容块中的代码
宏: ASSUME_DATA_SEG SegmentReg,Attributes
描述: 标记一个代码段的开始。属性确定随后的代码的放置
和“生存期”。必须用SEGMENT_CLOSE来关闭。
例子:
ASSUME_DATA_SEG DS,POST
数据库用法: 寄存器 SegmentReg。使假设成立的段寄存器。
数 Attributes。下面的关键字(除了加注解
的)可以用“+”组合:
POST 要由POST任务访问的静态数据段。
SMM 在SMM中的静态数据段。
宏: SEGMENT_CLOSE
描述: 标记一个代码或数据段的开始。必须首先用
CODE_SEGMENT_OPEN或DATA_SEGMENT_OPEN打开。
例子:
SEGMENT_CLOSE
数据库用法: 无
宏: OPTEXT OptionName[,ComponentName]
描述: 声明从另一个组件或特征对一个选项的引用。选项必
须在组件或特征的INF文件中声明。
例子:
OPTEXT pci.escd.DfltIRQ
数据库用法: 名字 OptionName。名字由三部分组成:类名、零
或多个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后面可
以跟着零或多个字母、数字或下划线。
串 ComponentName。在OEM截取例程中,EXTCALL
必须指定哪一个组件将解析该调用。
宏: OPTCHK
OptionName,Condition,Value[,[<TrueCodeText>
][,FalseCodeText]
描述: 如果指定选项满足指定条件,执行TrueCodeText。
否则,执行FalseCodeText。选项必须首先已经用
OPTEXT声明。
例子:
OPTCHK pci.escd.DfltIRQ,EQ,TRUE,<mov ax,1>
数据库用法: 名字 OptionName。名字由三部分组成:类名、
零或多个子类名和实际函数名,以句点分
隔。每个部分必须以一个字母或下划线开
始,后面可以跟着零或多个字母、数字或下
划线。
关键字 Condition。有效条件是LE(小于或等于)、
LT(小于)、GE(大于或等于)、GT(大于)、
NE(不等于)或EQ(等于)。
数 Value。使用的常数。不能包含其他选项名字。
串 TrueCodeText。如果条件为真则要执行的
代码。
串 FalseCodeText。如果条件为假则要执行的
代码。
宏: DB OPTIONVAL (Name)
描述: 为选项产生一个等于当前选项值的等式。
例子:
mov al,OPTIONVAL(pci.escd.DfltIRQ)
数据库用法: 名字 OptionName。名字由三部分组成:类名、零
或多个子类名和实际函数名,以句点分隔。每
个部分必须以一个字母或下划线开始,后面可
以跟着零或多个字母、数字或下划线。
宏: Mov al,OPTIONENUM(,Name,enumValue)
描述: 为选项产生一个列举的等式。
例子:
mov al,OPTIONENUM(memc.memory.type,SDRAM)
数据库用法: 名字 OptionName。名字由三部分组成:类名、
零或多个子类名和实际函数名,以句点分
隔。每个部分必须以一个字母或下划线开
始,后面可以跟着零或多个字母、数字或下
划线。
列举值 列举的选项值。
附录D
INF文件数据采集表:
命令 BringUp0
描述 识别要包括在任何BIOS中的在PLATFORM.CFG中被识
别为BringUp的组件或特征。对于更多信息,参见“对
于平台配置的低级设计说明”。
这个命令以引导一个母板所需的最小组件和特征快速
地配置一个BIOS。当这个命令被添加到PLATFORM.CFG
文件时,只有将系统引导到DOS所需的组件被安装在
BIOS中。
数据库用法 Bringup状态-真/假
命令 Category (categoryName:Identifier [,
CategoryName...])
描述 识别设备或软件组件所适合的类别。例如:SIO,MEMC,
AUDIO,BUSC,CPU。
数据库用法 标识符 CategoryName。当一个组件可以执行不止
一个函数时,将信息放在这里。
命令 Class(ClassName:Identifier)
描述 提供组件或特征所属的类的名字。每个INF文件最多
允许一个类或子类命令。采用具有它们的类路径的前
缀的名字来引用所有组件/特征的函数、列表和选项。
COMPNENT.INF不需要具有一个类或子类命令。如果
FEATURE.INF的父INF包含一个类或子类命令,则它
必须包含一个类或子类命令。否则它是可选的。
数据库用法 标识符 ClassName。这个组件所属的类的名字。最
大为20个字符。
命令 Classification ()
{
Category(Identifier...)
Category(Identifier…)
}
描述 采用BIOS工具指定用在排序和分类组件中的信息。目
前定义的子命令是:
ComponentType
DeviceVendor
DeviceAlias
PartNumber
Category
例如:
Classification ()
{
ComponentType(Hardware)
DeviceVendor(″Intel″,″Chips″)
DeviceAlias(″PIIX4″,″MyPIIX4Emul″)
PartNumber(″371ab″,″371abEmul″)
Category(BUSC,FDISK,USBC,BUSC)
}
数据库用法 无
命令 CompileUsing(SourceExt:String,DestinationExt
:String,Command:String)
描述 识别要用在组件的makefile中的用于带有指定扩展名
的所有文件的自定义编译命令。这个命令用于这个组
件/特征而不是任何缺省命令。
命令串可以包含专用序列(以%或\开始),以识别具
体文件信息应该位于的地方。
例如,
CompileUsing(″ASL″,″BIN″,″ASL.EXE%f
/Fo%s.tmp\nBIN2EXE%s.tmp
%s.bin″)
对于名字为″mycppfil.asl″的文件翻译到makefile
中的下列语法:mycppfil.bin:mycppfil.asl
ASL.EXE mycppfil.asl/Fomycppfil.tmp
BIN2EXE mycppfil.tmp mycppfil.bin
序列 描述
%f 输入文件的8.3文件名的占位符。例如,如果
输入文件是‘abc.c’,则%f将以‘abc.c’替换。
%s 不带扩展名的文件名的占位符。例如,如果输
入文件是‘abc.c’,则%f将以abc替换。
%% 百分号
\n 新行。将多个命令界定为放在makefile中。
\\ 反斜杠。
数据库用法 串 SourceExt。源代码文件的三个字符的文件扩展
名。这些文件是自定义命令的输入。
串 DestinationExt。由自定义命令输出的文件的
三个字符的文件扩展名。
串 Command。放在makefile中的实际自定义命
令,长度直至240个字符。参见实际格式的描
述。
命令 ComponentType(Type:ComponentTypeKeyword)
描述 将组件标识为硬件或软件。
必须作为Classification的子命令出现。
数据库用法 关键字 Type。硬件或软件
命令 CoreVersion (Version:Version[,Version:
Version...])
描述 组件/特征与这些核心版本兼容。Manticore兼容代码
应该引用版本7.0。
如果它们匹配大版本并且其小版本号小于或等于核心
小版本,则组件/特征与核心兼容。
数据库用法 版本 Version。大.小版本号。如果小版本被遗漏,
假设它为0。
命令 Description(TextDescription:String)
描述 将由BIOS工具用来提供关于被描述的组件或特征的细
节的文本注释。
数据库用法 串 TextDescription。短描述,长度直至512
个字符。
命令 DeviceAlias(AliasName:String[,AliasName...])
描述 任何字母数字名字—典型地是该部分的一个公知的‘绰
号’,例如PIIX4。只用于具有硬件的组件类型的组件。
必须作为Classification的子命令出现。
数据库用法 串 AliasName。该部分的一个或多个常用绰号。
命令 DeviceVendor (VendorName : String [,
VendorName...])
描述 标识组件的制造或制造商。
必须总是作为Classification的子命令出现。
数据库用法 串 VendorName。标识厂商。
命令 LinkUsing(SourceExt:String,Destinat ionExt:
String,Command:String)
描述 标识一个要在组件的makefile中使用的对于带有指定
扩展名的所有文件的自定义链接命令。这个命令用于
这个组件/特征而不是任何缺省命令。
命令串可以包含专用序列(以%或\开始)以标识具体
文件信息应该位于的地方。
例如:
LinkUsing(″OBJ″,″EXE″,″LINK.EXE%1,MYTARGET.
EXE″)
序列 描述
%1 用于带有源扩展名的组件/特征中的8.3文
件名的占位符。
%% 百分号
数据库用法 串 SourceExt。要被链接的目标文件的三个字符的文
件扩展名。这些文件是自定义命令的输入。
串 DestinationExt。由自定义命令输出的文
件的三个字符的文件扩展名。
串 Command。放在makefile中的实际自定义
命令,长度直至240个字符。参见实际格式
的描述。
命令 Name(ComponentName:String)
描述 提供组件或特征的名字。用在BIOS工具中。
数据库用法 串 ComponentName。组件或特征的名字,长度
直至40个字符。不允许有标点符号。
命令 Option (OptionName:Identifier,OptionValue:
Number|Identifier,
OptionSize:OptionSizeKeyword,OptionDesc:
String)
{
ValueName:Identifier,Value:Number,
Description:String
ValueName:Identifier,Value:Number,
Description:String
…
}
描述 创建一个可配置选项并给它一个缺省值。工程师可以
改变PLATFORM.CFG中的设置。子命令将描述性名字给
予有意义的支持值。可以使用这些名字代替数值来用
于声明选项值或改变PLATFORM.CFG中的值。每个值名
字必须在一个单独的行上。如果没有值,则可以只使
用数值。
例如:
Option (IncludeIrDaSupport,FALSE,BYTE,
″Option to Include IrDa Support″)
{
FALSE,0,″No IrDa Support″
TRUE,1,″Include IrDa Support″
}
每个值由以逗点分隔的标识符、数和值描述组成。如
果有多个值,它们应该在不同的行上。
数据库用法 标识符 OptionName:在选项将用在源代码中时给
出选项的名字。
数/串 OptionValue:缺省值。可以是一个数或在
主体中定义的值中的另一个。
选项尺寸 OptionSize:BYTE、WORD或DWORD。在使
关键字 选项是ROM可编辑时使用。
串 OptionDesc:在BIOS工具将选项展示给工
程师以描述选项的目的时使用。
命令 Owner (OwnerName:String[,OwnerName])
描述 提供组件或特征所有者的公司名字。在释放源代码或
将核心树复制到客户地点时BIOS工具可以滤出由特定
客户创建的组件。
例如:
Owner(″Toshiba″)
Owner(″Phoenix″)
数据库用法 串 OwnerName。拥有组件的公司的名字。对于
Phoenix科技公司,使用‘Phoenix’。
命令 PartNumber (PartNumber :String [,
PartNumber...])
描述 标记在部分上的任何字母数字串。
数据库用法 串 PartNumber。标识芯片上的数字。
命令 PlatformType (Architecture :
PlatformTypeKeyword)
{
PlatformType (Rule)
…
AllOthers (Rule)
}
描述 描述在满足时使这个组件或特征被自动带BIOS
中的标准。用于特征的规则将被忽略,除非其父组件已
经包括在BIOS中。
在PLATFORM.CFG中,每个平台可以被分配一个平台类
型。子命令将平台类型与一个描述组件或特征何时应该
包括在BIOS中的规则相合并。这个规则后面将跟着
PLATFORM.CFG,否则明确指出。
通常,如果没有用于一特定平台的规则,则它不被包
括,除非在PLATFORM.CFG中指定。然而,关键字
AllOthers改变用于(a)未列出或(b)用‘Explicit’
规则列出的所有平台类型的规则。
目前有五个规则:
推荐(Recommended) 组件/特征将被缺省包括。
测试(Test) 组件/特征将为调试构件缺省包括,
但从非调试构件中排除。用于专用测
试组件。
随选(OnDemand) 如果需要解析一个硬PUBEXT或
PRVEXT(即,不使用OPTIONAL、
ALTERNATE或SUBSTITUTE属性),
组件/特征将被包括。
明确(Explicit) 只有在PLATFORM.CFG中明确指定时
组件才被包括。不能与AllOthers
一起使用。
外部触发(类路径) 如果指定组件或特征被包括,组件/
(ExternalTrigger 特征将被包括。
(ClassPath))
PlatformType ()
{
Desktop(Recommended)
Notebook(Recommended)
Notebook(OnDemand)
Server(Recommended)
}
每个INF文件每个体系结构最多有一个PlatformType命令。
数据库用 平台类型关 Architecture。标识用于组件或特征代
法 键字 码的处理器体系结构。对于支持多个体系
(PlatformT 结构的组件或特征,必须存在两个单独的
ypeKeyword PlatformType语句。目前定义的体系结
) 构是:
IA32-80×86 code
IA64-Merced code
命令 ShieldPrivates ()
描述 保护一个特征的私人过程不被它的同层特征访问。这个
构造对于用作在功能上不相关的混杂特征的储存的组
件是有用的。
例如,POST组件包含用于错误管理和存储器管理的特
征。这两个特征以其在时间上的关系被分成一组,因为
它们都提供POST-时间服务,但它们在功能上不相关,
不应该允许通过私人过程连系。
例子:
ShieldPrivates ()
数据库用 标识符 Architecture。标识用于组件或特征代码
法 的处理器体系结构。对于支持多个体系结构
的组件或特征,必须存在两个单独的
PlatformType语句。目前定义的体系结构
是:
IA32-80×86 code
IA64-Merced code
命令 SubClass(SubClassName:Identifier|..)
描述 提供特征所属的子类的名字。每个.INF文件只允许一个
类或子类。一个组件或特征的公共过程由其前缀有其
类.子类路径(class.subclass path)的函数名所引
用。一个专用子类入口‘..’表明这个组件/特征使用
父的类或子类名字。
例子:
SubClass(timer)
SubClass(..)
数据库用 标识符|.. SubClassName:子类的名字。子类名字可
法 以是在长度上直至20个字符的只有字符
没有空格的串。使用‘..’来使用父的类
或子类名字。
命令 Target (TargetName: FileName[, TypeKey:
Identifier])
描述 提供应该从建立这个组件中得到的库或二进制的名
字。
例子1:
Target(SMC77X.AML,ACPI)
例子2:
Target(SMC77X.EXE)-正常BIOS代码不需要一个关
键字。
例子3:
Target (MYMUSIC.WAV,WAV1)
数据库用 文件名字 TargetName:8.3文件名。
法
标识符 TypeKey。用于标识非标准目标类型的四个
字符的代码。例如,ACPI、DISP、STRG等。
命令 Uses (FileName:Filepath)
描述 这个命令用于标识由所描述的组件或特征使用的共享
文件的位置。构件工具可以使用这个命令来将文件标识
为在为组件或特征创建的MAKEFILE中的相关性。下面
的限制运用于使用共享文件:
·在Uses命令中指定的路径和文件名必须是任何
COMPNENT.INF文件的上游。例如,如果一个
COMPNENT.INF文件存在于SIO\SMC\77x中,则
SIO\SMC\77x\COMA\file.asm不能由一个Uses命令引
用。
例子A:
下面的物理目录结构例子举例说明共享目录组织。
SMC
|
|-MyCompDirA
| |
| |---Feature1\MYCODE.ASM
| |---Feature2\MYCODE.ASM
| |---Shared\BADSHARE.ASM<-这是不正确的
|-MyCompDirB
| |---Fea turel\MYCODE.ASM
|
|-shared\FILE1.ASM <-这是正确的
例子B:
下面的放在COMPNENT.INF或FEATURE.INF中的Uses
命令表明共享文件\SMC\SHARED\FILE1.ASM由组件或
特征使用。
数据库用 文件路径 FileName:要被包括的路径或文件,
法 (FilePath) 就象它是这个组件或特征的一部分。
附录E
平台类型分层结构
如本发明中所述的,源代码库的每个部分/目录根据平台/产品类型声明其构件包含触发特性。例如,在BIOS中,多个处理器支持是一个用于服务器的推荐的缺省特征,但对于其他产品类型只是明确地可安装的。在新的平台类型出现时,不希望改变源代码库的每个特征以声明该类型。这样,产品类型在分层结构中声明,允许从另一个类型派生出新类型。只有需要不同于父的触发的特征需要被改变。下面是一个声明系统的产品类型的文件及其用于BIOS的派生分层结构的例子,
Basic PC ;基本产品类型Desktop99 ;从Basic PC派生出的Desktop2000 ;从desktop派生出的Laptop2000 ;从desktop2000派生出的Laptop99 ;也是从desktop99派生出的 |
下面是用于选择对一给定特征的触发的递归算法。
1)如果在PLATFORM.CFG中声明的平台类型具有一个声明的INF触发,假设该触发用于该特征并退出
2)如果未声明父,假设触发为“Explicit”并退出
3)检查父平台类型的声明。如果声明了,假设父类型触发用于该特征并退出
4)转到2
附录F
触发规则
这个图定义了对于一个代码树的无效触发组合。当不止一个组件或特征包含相同的类路径定义时,代码树中的一个无效触发组合可能导致不确定的触发。
定义:
集体触发:一个组件或特征的触发考虑特征的祖先。集体触发作为算法的一部分被确定:
触发图例:
R=推荐(Recommended)
O=随选(Ondemand)
O+E=随选和外部触发的组合
X=明确(Explicit)
集体触发图例:
R=推荐(Recommended)
Root=对于类似类的有效性检查的根的重新建立
I=不确定(Indeterminate)
静态树确定
为了确认一个树:
1.将状态表A加到树上
2.将状态表B加到树上
3.重复步骤1和2,直到没有状态变化
对于相同根下的类似类名字和函数的组件/特征,下面的表表示无效触发组合的条件。
无效树状态
相同根下的类似类的第一组件/特征的集体触发 | 相同根下的类似类的第二组件/特征的集体触发 |
I | I |
R | R |
状态表A—初始集体触发状态
父集体触发 | 组件/特征触发 | 组件/特征集体触发 |
R | R | R |
R | O,O+E,E | I |
R | X | Root |
Root | R | R |
Root | O,O+E,E | I |
Root | X | Root |
I | R,O,0+E,E | I |
I | X | Root |
状态表B—改变确定性外部触发
集体触发 | 父集体触发 | 组件/特征触发 | 外部触发的集体触发 | 组件/特征集体触发 |
I | R | E,0+E | R | R |
I | Root | E,O+E | R | R |
附录G
代码分段访问确认
对一个函数的调用的访问特权由调用程序和被调用程序的段的属性来确认。被调用程序必须具有调用程序的属性作为最小子集,或者将在图形产品视图中注释一个错误。在下面的例子中,X不能由Y调用,因为它不具有SMI的属性。原因在于,如果Y可以从一个SMI调用,则必须假设它调用的函数可以从SMI运行。配置过程向被调用程序确认调用程序的这些属性,并给出适当的错误。在链接的代码在被调用时不再可得到时,这些错误可以防止几个小时的运行时间调试。
段访问违规的例子OPEN_CODE_SEGMENT RUNTIME+PRERAM;声明代码段PUBLIC_PROC X ;声明过程XENDP ;结束X声明CLOSE_SEGMENT ;结束代码段声明OPEN_CODE_SEGMENT RUNTIME+PRERAM+SMI ;声明代码段PUBLIC_PROC Y ;声明过程YCALL X ;对X的调用程序—将产生错误ENDP ;过程结CLOSE_SEGMENT ;结束代码段声明 |
附录H
配置的定制技术的例子
步骤1)用户从INF文件中定义的缺省改变选项值。在图形上,这是一个点击操作。新值在源代码中是可以以高亮显示查看的。步骤2)使用接口调用配置以便将新的选项值写在PLATFORM.CFG文件中。步骤3)当准备建立时,在动态创建的预处理器文件FEATURE.INC定义一个等式,对编译程序定义选项值。新值替换缺省值。步骤4)编译使用新值。 |
选项值定制
通过文件超覆定制
步骤1)用户在一个源库文件上右击并选择“超覆”。步骤2)用户界面提示使用自定义目录来放超覆文件。步骤3)用户界面调用配置以便将文件名和文件夹放在PLATFORM.CFG中。步骤4)用户界面以一个自定义图标显示代替原始文件的超覆文件。步骤5)构件准备过程在构件脚本中使用代替原始文件的超覆文件。 |
通过向特征添加自定义文件定制
步骤1)用户在特征上右击并选择“添加自定义文件”。步骤2)用户界面提示用户自定义文件的自定义目录。步骤3)用户界面调用配置以便将文件名和文件夹放在PLATFORM.CFG中。步骤4)用户界面以一个自定义图标显示特征文件列表中的自定义文件。步骤5)构件准备过程在构件脚本中为特征/组件添加自定义文件。 |
附录I
数据库档案库
在开发环境中有两个主组件数据库。核心主组件数据库位于核心服务器上,包括关于核心源文件的信息。本地主组件数据库位于开发者的工作站上,包括关于本地开发树的信息。所有数据库都只能通过数据访问API访问。下面的图以图形显示了这些关系。
核心主组件数据库具有三个子部分,“提示数据库”、“组件档案库数据库”和“核心标号档案库数据库”。每个数据库提供一种不同类型的支持。
·提示数据库由来自在最新的组件和特征文件提示中引用的文件的信息组成。对一个目录内的一组文件的改变将产生一个触发对提示数据库的更新的事件。这个数据库由GUI和其他工具用来访问最新的可用核心信息。
·组件档案库数据库是为保存的每个新组件标号创建的。这个档案库数据库与提示数据库几乎相同,但它包括用于一具体组件标号的信息。对组件标号的改变将在服务器上产生一个触发对组件档案库的更新的事件。组件档案库数据只用于核心标号档案库数据的构造。
·核心标号档案库数据库是为保存的每个新的核心标号创建的。这个档案库数据库与组件档案库几乎相同。在这个档案库中的信息是基于从用于核心标号中引用的每个组件标号的组件档案库同化的数据的。对核心标号的改变将在服务器上产生一个触发对核心标号档案库的更新的事件。核心标号档案库数据由GUI用来展示较老的核心标号上的信息。这在确定需要哪些文件来从核心向一个本地开发树下载指定组件以匹配开始文件时是有用的。
本地主组件数据库具有与提示数据库相同的数据库结构。这个数据库的不同之处是它的信息源。本地数据库包含从本地目录树获得的信息。因此,信息包括工作代码库中的改变。
附录J
组件/特征触发算法
下面的算法描述了系统用来确定被带入产品的组件和特征的机制。下面显示了状态表引用。
算法:
Algorithm:
1)运用状态表A
2)运用状态表B
3)运用状态表C
4)运用状态表D
5)运用状态表E
6)如果任何特征的状态在步骤3-5中改变,转到2
7)解析激活特征的相关性。记录未解析的相关性。注意下面的规则:
a.只有允许范围内的解析器被考虑用于相关性解析。私人/屏蔽私人限制该范围。
b.只有硬相关性被列为未解析的。可选的或备用的不列出。
8)如果没有未解析的相关性,转到11
9)运用状态表F。
10)如果任何项的状态在步骤9改变,转到2
11)运用状态表G
用于运用状态表的定义:
触发:
R=推荐(Recommended)
O=随选(On Demand)
E=外部触发(External Trigger)
X=明确触发(Explicit Trigger)
O+E=随选和外部触发两者
其他:
Dc=无关的
A-激活-将被建立进产品
IA-非活动-将不被建立进产品
UD-不确定状态
UDO-不确定的,但可以被带入以解析一个引用。如果定义了一个平台,树的根总是被认为是激活的。父被定义为所讨论的特征向上的一层。
触发是在运用于这个配置的平台类型的feature.inf中定义的。
状态表A—初始状态设置
Platform.cfg中的强迫状态 | 结果状态 |
强迫放入 | A |
强迫拿出 | IA |
无强迫 | UD |
状态表B—下游调整
状态 | 父状态 | 结果状态 |
Dc | IA | IA |
状态表C—上游调整
状态 | 子状态 | 结果状态 |
Dc | A | A |
状态表D—基本触发状态
状态 | 父状态 | 触发 | 结果状态 |
UD | Dc | X | IA |
UD | A | R | A |
UD | UDO,A | O,O+E | UDO |
状态表E—外部触发状态
状态 | 父状态 | 触发 | 外部触发激活 | 结果状态 |
UD,UDO | A | E,E+O | 是 | A |
状态表F—相关性解析
状态 | 解析相关性 | 结果状态 |
UDO | 是 | A |
状态表G—定案
状态 | 结果状态 |
UDO,UD | IA |
附录K
动态树确认确定
为了在用户动态地强迫放入或强迫拿出组件/特征时确认配置是确定性的,运用下面的算法。这个确认由配置机在用户将组件和特征强迫放入或拿出构件时运用。
1.将状态表C运用到树
2.将状态表A运用到树
3.将状态表B运用到树
4.重复步骤2和3直至没有状态改变
对于同一根下的类似类名字的组件/特征,下面的表表示无效触发组合的条件。
无效状态
同一根下的类似类的第一组件/特征的集体触发 | 同一根下的类似类的第二组件/特征的集体触发 |
I | I |
状态将需要公共例程的自定义截取
同一根下的类似类的第一组件/特征的集体触发 | 同一根下的类似类的第二组件/特征的集体触发 |
R | R |
状态表C—用户强迫的集体状态
强迫状态 | 结果的组件/特征集体触发 | 组件/特征的所有子女的结果的集体触发 | 组件/特征的所有祖先的结果的集体触发 |
强迫放入 | R | R | |
强迫拿出 | Root | Root |
附录L
代码流信息
通过在编译之前扫描代码库和在产品配置中捕获函数调用,数据的不同视图可以向一个人提供有价值的信息。这个数据参与产品调试和聚焦回归测试。下面是同一数据库和配置信息的所产生的两个不同报告的高度简化的例子:
在函数X开始的代码流 |
函数X工调用函数Y调用函数Z调用函数W调用函数Q调用函数Z |
测试是否对函数Z作出改变的函数 |
Z由函数Y和X调用由函数X调用 |
除了这个分析之外,调用和引用信息还可以报告源代码库问题,包括死代码或未解析的代码(即使被可选地引用)。在源代码库中未引用的任何函数将被报告为可能死的代码。在源代码库中未解析的任何引用将被报告为一个无用的引用。这些报告可以被过滤以便自定义代码,允许开发者确认他或她的定制仍然被引用,或在库更新之后引用现有代码。
Claims (73)
1.一种用于开发一个完成产品的软件开发系统,包括:
定义完成产品的产品配置数据;
包含定义一个或多个包括接口和相关性的目标的源代码的至少一个源代码库;
定义所述目标的性质的指令;
配置程序,从所述产品配置数据、所述指令和从从所述源代码库获得的数据开发配置状态数据;
图形用户界面,用于展示代表完成产品的配置状态数据、遗漏和选定和取消选定的目标和选项的一个可视的逻辑表示,所述界面接受命令来调整完成产品;以及
在所述配置状态数据的控制下从所述源代码产生完成产品的例程。
2.如权利要求1所述的软件开发系统,其中,所述目标包括至少一个源代码单元和一个包含所述指令的目标信息数据集合。
3.如权利要求2所述的软件开发系统,其中,所述指令包括构件指令。
4.如权利要求1所述的软件开发系统,其中,所述目标包括至少一个组件,所述组件包括至少一个是特征的目标。
5.如权利要求4所述的软件开发系统,其中,所述组件和特征的每一个都包括至少一个源代码和一个包含用于相应的组件或特征的指令的目标信息数据集合。
6.如权利要求1所述的软件开发系统,其中,至少一些所述接口和相关性既具有名字又具有在完成产品的开发之前以正确的绝对地址替换的类名称。
7.如权利要求6所述的软件开发系统,其中,所述产生完成产品的例程在其修改源代码单元时将用于至少一些相关性和接口的名字和引用变换成名字和库引用。
8.如权利要求1所述的软件开发系统,其中,至少一些所述接口和相关性具有版本指示,至少一些所述接口和相关性既具有名字又具有在完成产品的开发之前以正确的绝对地址替换的类名称。
9.如权利要求8所述的软件开发系统,其中,所述图形用户界面警告在匹配的接口和相关性中的不兼容的版本号。
10.如权利要求1所述的软件开发系统,进一步包括目标说明数据作为与至少一些相关性相联系的数据的一部分,其中,目标说明数据优先于具有相同标识符的其他接口使得相应的相关性被链接到在以指定目标包括的源代码单元中的一个接口。
11.如权利要求10所述的软件开发系统,其中,至少一些所述接口和相关性既具有名字又具有在完成产品的开发之前以正确的绝对地址替换的类名称。
12.如权利要求11所述的软件开发系统,其中,至少一些类名称拥有多个目标,所述目标包括包括特征的组件,并且至少一些名称涉及多个特征的接口和相关性。
13.如权利要求10所述的软件开发系统,其中,至少一些所述接口和相关性具有版本指示。
14.如权利要求13所述的软件开发系统,其中,所述图形用户界面警告在匹配的接口和相关性中的不兼容的版本号。
15.如权利要求1所述的软件开发系统,包括指明在无RAM环境中运行的源代码单元,其中,产生完成产品的例程在模拟一个子例程跳转和返回的调用或跳转相关性插入代码修改所述源代码单元,而不需要一个基于RAM的子例程堆栈。
16.如权利要求15所述的软件开发系统,其中,在调用或跳转和返回相关性的插入代码设置一个执行跟随着一个返回的寄存器分支的假返回堆栈,并且,在调用或跳转处,产生并插入将立即地址加载到所述寄存器中然后产生一个到指定接口的跳转的代码。
17.如权利要求15所述的软件开发系统,其中,在调用或跳转和返回相关性的插入代码在一个标明的寄存器中保存返回地址或指示返回地址的位置的索引,并利用所述寄存器执行到调用程序中的正确点的返回。
18.如权利要求1所述的软件开发系统,其中,配置程序在遇到一个依赖于一个带有相应的接口的未选定目标的存在的相关性时自动选择所述目标来包含在完成产品中。
19.如权利要求18所述的软件开发系统,其中,至少一些所述接口和相关性既具有名字又具有在完成产品的开发之前以正确的绝对地址替换的类名称。
20.如权利要求19所述的软件开发系统,其中,至少一些类名称拥有多个目标,所述目标包括包括特征的组件,并且至少一些类名称涉及多个特征的接口和相关性。
21.如权利要求1所述的软件开发系统,其中,一些接口可以可选地包括一个截取名称,并且,其中,所述配置程序优先于其他相同命名的接口将一个相关性与一个具有截取名称的接口相关联。
22.如权利要求21所述的软件开发系统,其中,至少一些所述接口和相关性具有版本。
23.如权利要求21所述的软件开发系统,其中,所述目标包括至少一个组件,所述组件包括至少一个是特征的目标。
24.如权利要求1所述的软件开发系统,其中,所述产生完成产品的例程在面临至少一些由于未选择一个目标而没有相应的接口的相关性并且这不是一个错误条件时通过从包含相关性的源代码单元去除相关性来修改源代码单元。
25.如权利要求24所述的软件开发系统,其中,至少一些所述接口和相关性具有版本指示。
26.如权利要求24所述的软件开发系统,其中,宏程序3806被用于识别相关性,所述宏程序包括对由所述配置程序设置的一个控制变元的引用,使得当包含一个相应接口的目标未被选择时在选择配置程序时去除相关性。
27.如权利要求24所述的软件开发系统,其中,所述图形用户界面指示由于未选择包含相应的接口并接受选择或不选择相应目标的命令的目标而要消除哪些相关性。
28.如权利要求1所述的软件开发系统,其中,对于至少一些没有接口的相关性,所述配置程序可以使图形用户界面给出一个可视错误指示。
29.如权利要求28所述的软件开发系统,其中,至少一些所述接口和相关性具有版本指示。
30.如权利要求1所述的软件开发系统,其中,定义所述目标的性质的数据在至少一些情况下包括一个目标的选择由另一个目标的选择所触发的指示;以及,所述配置程序在遇到这样的数据时只要所述一个目标也被选择就选择所述另一个目标。
31.如权利要求30所述的软件开发系统,其中,所述指令包括建立指令。
32.如权利要求30所述的软件开发系统,其中,至少一些所述接口和相关性既具有名字又具有在完成产品的开发之前以绝对地址替换的类名称,并且,至少一些所述接口和相关性具有版本指示。
33.如权利要求1所述的软件开发系统,其中,至少一些所述源代码单元包含列表单元,并且,其中,所述例程包括一个通过将这些列表单元放在一起来修改源代码并在一个指定点将其插入最终产品并建立到列表项引用的链接的产品组件链接程序。
34.如权利要求33所述的软件开发系统,其中,所述列表单元包括排序优先权说明。
35.如权利要求33所述的软件开发系统,其中,所述列表单元包括排序键说明。
36.如权利要求33所述的软件开发系统,其中,所述列表单元包括列表入口。
37.如权利要求33所述的软件开发系统,其中,可以定义多个列表,向每个列表入口分配一个列表名字,以便于识别和采集列表的单元。
38.如权利要求37所述的软件开发系统,其中,所述列表单元包括列表入口,至少一些列表入口标明排序优先权和排序键。
39.如权利要求1所述的软件开发系统,其中,至少一些所述接口被声明为公共的,可以由任何目标中的任何相关性访问,或者被声明为私人的,只能由同一目标内的相关性访问。
40.如权利要求1所述的软件开发系统,其中,所述目标包括至少一个包括至少一个特征的组件,至少一些接口被声明为公共的,可以由任何目标中的任何相关性访问,一些被声明为私人的,只能由同一组件内的相关性访问,一些被声明为屏蔽的,只能由同一特征内的相关性访问。
41.如权利要求1所述的软件开发系统,其中,至少一些所述源代码单元包含定义文本和串的语言的串单元,并且,其中,所述产生完成产品的例程插入允许通过在非易失存储器中存储的一个值来选择正确的语言串的代码。
42.如权利要求1所述的软件开发系统,其中,所述产品配置数据包括定义要建立的平台的类型的数据。
43.如权利要求42所述的软件开发系统,其中,所述定义要建立的平台的类型的数据可以标明一个从包括台式的,便携式的和服务器的组中选择其类型的平台。
44.如权利要求1所述的软件开发系统,其中,所述产生完成产品的例程包括一个允许提供超覆数据来替换数据表中的一些数据项的产品组件链接程序。
45.如权利要求1所述的软件开发系统,其中,所述产生完成产品的例程包括一个在单独编译和链接的可执行代码块之间设立段内链接的产品组件链接程序。
46.如权利要求1所述的软件开发系统,其中,所述代码库中的代码单元可以被标明为存在于非易失存储器中,并且,其中,所述产生完成产品的例程包括一个产品组件链接程序,所述产品组件链接程序分配非易失存储器来存储这样的单元,并且还在完成产品中插入使程序以系统设计者不需要关心非易失存储器的性质的方式访问非易失存储器中的这种变量所必须的代码。
47.如权利要求46所述的软件开发系统,其中,至少一些所述源代码单元包含定义文本和串的语言的串单元,并且,其中,所述产生完成产品的例程插入允许通过在非易失存储器中存储的一个值来选择正确的语言串的代码。
48.如权利要求1所述的软件开发系统,其中,所述图形用户界面包括一个用于查看和修改目标的源代码单元的编辑器。
49.如权利要求48所述的软件开发系统,其中,通过点击配置状态数据的所述可视逻辑表示中的单元中的一个,可以在所述图形用户界面中打开一个编辑窗口。
50.如权利要求1所述的软件开发系统,其中,使用宏指令来标记所述接口和相关性,并且,其中,代码修改由被所述配置程序开发的配置状态数据驱动和控制的宏程序来执行,使得标准汇编程序、编译程序和链接程序可以用在实现软件开发系统中。
51.如权利要求50所述的软件开发系统,其中,所述配置状态数据被馈送入一个产生特征include文件和make文件的产品make例程,然后,一个产品建立例程使得由所述make文件控制的编译程序和链接程序将从所述源代码库取出的源代码单元和所述特征include文件合并成定义完成产品的所建立产品组件。
52.如权利要求51所述的软件开发系统,其中,所述make文件包括组件make文件和产品make文件。
53.如权利要求51所述的软件开发系统,其中,产品组件链接程序将所述所建立产品组件转换成所述完成产品。
54.一种用于开发一个完成产品的方法,包括:
产生定义完成产品的产品配置数据;
提供包含定义一个或多个包括接口和相关性的目标的源代码单元的至少一个源代码库;
提供定义所述目标的性质的指令;
从所述产品配置数据、所述指令和从从所述源代码库获得的数据开发配置状态数据;
利用一个图形用户界面,检查代表完成产品的配置状态数据、遗漏和选定和取消选定的目标和选项的一个可视的逻辑表示,并提供命令来调整完成产品;以及
在所述配置状态数据的控制下从所述源代码单元产生完成产品。
55.如权利要求54所述的方法,包括对所述目标的提供包括至少一个源代码单元和一个包含所述指令的目标信息数据集合。
56.如权利要求54所述的方法,包括提供至少一个是组件的目标,所述组件包括至少一个是特征的目标。
57.如权利要求54所述的方法,包括向至少一些所述接口和相关性既分配名字又分配类名称并在完成产品的开发之前以正确的绝对地址替换它们。
58.如权利要求54所述的方法,包括分配目标说明数据作为与至少一些相关性相联系的数据的一部分,然后,由链接相应相关性的目标说明数据优先于具有相同标识符的其他接口引导到一个以指定目标包括的源代码单元中的接口。
59.如权利要求54所述的方法,包括指明源代码单元在无RAM环境中运行,并在模拟一个子例程跳转和返回的调用或跳转相关性处产生修改的源代码单元,而不需要一个基于RAM的子例程堆栈。
60.如权利要求54所述的方法,包括在遇到一个依赖于一个带有相应的接口的未选定目标的存在的相关性时自动选择所述目标来包含在完成产品中。
61.如权利要求54所述的方法,包括为至少一些接口添加截取名称,并优先于其他相同名字的接口将一个相关性与一个具有截取名称的接口相关联。
62.如权利要求54所述的方法,包括在面临由于未选择一个目标而没有相应的接口的相关性并且这不是一个错误条件时通过从源代码单元去除相关性来修改源代码单元。
63.如权利要求54所述的方法,包括对于没有接口的相关性以图形用户界面发出一个可视错误指示信号。
64.如权利要求54所述的方法,包括标明由另一个目标选择触发的一个目标的选择;以及,只要所述另一个目标被选择,就选择一个目标。
65.如权利要求54所述的方法,包括在至少一些所述源代码单元中提供列表单元,并且,然后通过将这些列表单元放在一起来修改源代码单元,并在一个指定点将其插入最终产品,并建立到列表项引用的链接。
66.如权利要求54所述的方法,包括将一些接口声明为公共的,使其可以由任何目标中的任何相关性访问,并将其他接口声明为私人的,使其只能对同一目标内的相关性访问。
67.如权利要求54所述的方法,包括向至少一些所述源代码单元添加至少一些定义文本和串的语言的串单元,并且,插入允许通过在非易失存储器中存储的一个值来选择正确的语言串的代码。
68.如权利要求54所述的方法,包括向所述产品配置数据添加定义要建立的平台的类型的数据。
69.如权利要求54所述的方法,包括提供至少一些超覆数据并使其替换数据表中的一些数据项。
70.如权利要求54所述的方法,包括下面的在单独编译和链接的可执行代码块之间设立段内链接的汇编或编译。
71.如权利要求54所述的方法,包括将所述代码库中的一些代码单元标明为其目的地是存在于非易失存储器中,并且,在以后分配非易失存储器来存储这样的单元,并且还在完成产品中插入使程序以系统设计者不需要关心非易失存储器的性质的方式访问非易失存储器中的这种变量所必须的代码。
72.如权利要求54所述的方法,包括使用所述图形用户界面来查看和修改目标的源代码单元。
73.如权利要求54所述的方法,包括用宏指令来识别接口和相关性,并且,然后通过在配置状态数据的控制下执行宏程序来执行代码修改,并使用标准汇编程序、编译程序和链接程序来汇编或编译和链接源代码单元。
Applications Claiming Priority (2)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
US53167800A | 2000-03-20 | 2000-03-20 | |
PCT/US2001/009094 WO2001093031A1 (en) | 2000-03-20 | 2001-03-20 | A software development system that presents a logical view of project components, facilitates their selection, and signals missing links prior to compilation |
Publications (1)
Publication Number | Publication Date |
---|---|
CN1957328A true CN1957328A (zh) | 2007-05-02 |
Family
ID=24118600
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CNA018094716A Pending CN1957328A (zh) | 2000-03-20 | 2001-03-20 | 展示方案组件的逻辑视图、便于其选择以及在编译之前的信号遗漏链接的软件开发系统 |
Country Status (5)
Country | Link |
---|---|
EP (1) | EP1266284A4 (zh) |
JP (1) | JP2003535415A (zh) |
CN (1) | CN1957328A (zh) |
AU (1) | AU2001249327A1 (zh) |
WO (1) | WO2001093031A1 (zh) |
Cited By (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN102841782A (zh) * | 2011-06-23 | 2012-12-26 | 腾讯科技(深圳)有限公司 | 全局变量管理方法及装置 |
CN109828752A (zh) * | 2018-12-14 | 2019-05-31 | 平安科技(深圳)有限公司 | 项目代码自动生成方法、装置、计算机设备及存储介质 |
CN111722846A (zh) * | 2020-05-29 | 2020-09-29 | 苏州浪潮智能科技有限公司 | 一种兼容多种oem产品的cim接口定制的方法和设备 |
CN111857033A (zh) * | 2020-08-07 | 2020-10-30 | 深圳市派姆智能机器有限公司 | 一种可编程控制器的编译系统 |
Families Citing this family (5)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US20030200532A1 (en) * | 2002-04-17 | 2003-10-23 | Thomas Gensel | System and method for sharing reusable code base |
US7562346B2 (en) | 2003-09-02 | 2009-07-14 | Microsoft Corporation | Software componentization for building a software product |
US20060178858A1 (en) * | 2005-02-07 | 2006-08-10 | Microsoft Corporation | Baseline architecture monitor application for distributed systems |
KR100834676B1 (ko) | 2006-08-08 | 2008-06-02 | 삼성전자주식회사 | 소프트웨어 프로젝트 빌드 방법 |
KR102057724B1 (ko) * | 2018-05-25 | 2019-12-19 | 고려대학교 산학협력단 | 메모리 해제 오류를 자동으로 수정하는 장치 및 방법 |
Family Cites Families (6)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US5339433A (en) * | 1992-11-19 | 1994-08-16 | Borland International, Inc. | Symbol browsing in an object-oriented development system |
US5325533A (en) * | 1993-06-28 | 1994-06-28 | Taligent, Inc. | Engineering system for modeling computer programs |
US5758160A (en) * | 1993-06-28 | 1998-05-26 | Object Technology Licensing Corporation | Method and apparatus for building a software program using dependencies derived from software component interfaces |
CA2128387C (en) * | 1993-08-23 | 1999-12-28 | Daniel F. Hurley | Method and apparatus for configuring computer programs from available subprograms |
US5950209A (en) * | 1996-10-02 | 1999-09-07 | Alcatel Usa Sourcing, L.P. | Software release control system and method |
US6167564A (en) * | 1998-09-17 | 2000-12-26 | Unisys Corp. | Software system development framework |
-
2001
- 2001-03-20 CN CNA018094716A patent/CN1957328A/zh active Pending
- 2001-03-20 AU AU2001249327A patent/AU2001249327A1/en not_active Abandoned
- 2001-03-20 WO PCT/US2001/009094 patent/WO2001093031A1/en not_active Application Discontinuation
- 2001-03-20 JP JP2002501178A patent/JP2003535415A/ja active Pending
- 2001-03-20 EP EP01922536A patent/EP1266284A4/en not_active Withdrawn
Cited By (7)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN102841782A (zh) * | 2011-06-23 | 2012-12-26 | 腾讯科技(深圳)有限公司 | 全局变量管理方法及装置 |
CN102841782B (zh) * | 2011-06-23 | 2017-08-01 | 腾讯科技(深圳)有限公司 | 全局变量管理方法及装置 |
CN109828752A (zh) * | 2018-12-14 | 2019-05-31 | 平安科技(深圳)有限公司 | 项目代码自动生成方法、装置、计算机设备及存储介质 |
CN109828752B (zh) * | 2018-12-14 | 2024-01-02 | 平安科技(深圳)有限公司 | 项目代码自动生成方法、装置、计算机设备及存储介质 |
CN111722846A (zh) * | 2020-05-29 | 2020-09-29 | 苏州浪潮智能科技有限公司 | 一种兼容多种oem产品的cim接口定制的方法和设备 |
CN111722846B (zh) * | 2020-05-29 | 2022-05-31 | 苏州浪潮智能科技有限公司 | 一种兼容多种oem产品的cim接口定制的方法和设备 |
CN111857033A (zh) * | 2020-08-07 | 2020-10-30 | 深圳市派姆智能机器有限公司 | 一种可编程控制器的编译系统 |
Also Published As
Publication number | Publication date |
---|---|
EP1266284A1 (en) | 2002-12-18 |
WO2001093031A1 (en) | 2001-12-06 |
JP2003535415A (ja) | 2003-11-25 |
AU2001249327A1 (en) | 2001-12-11 |
EP1266284A4 (en) | 2003-08-06 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN1399737A (zh) | 便于组件选择的软件开发系统 | |
CN1182467C (zh) | 可扩充的分布企业应用集成系统 | |
CN1130626C (zh) | 支援并行程序的装置以及支持程序编制的方法 | |
CN100338568C (zh) | 开发片上系统用的开发环境的生成方法 | |
CN1321275A (zh) | 与源代码控制系统交互的方法和设备 | |
CN1073276A (zh) | 语言的中性对象 | |
CN1666202A (zh) | 管理集成电路设计的装置和方法 | |
CN1105507A (zh) | 模型化系统 | |
CN1755721A (zh) | 组件化和可扩展的工作流模型 | |
CN1591401A (zh) | 一种使用应用程序的各个版本进行数据处理的方法 | |
CN1073540A (zh) | 管理类方法名 | |
CN1659589A (zh) | 用于提供推理服务的系统和方法 | |
CN101052948A (zh) | 对象过程图应用程序开发系统 | |
CN1961294A (zh) | 为可由硬件/软件接口系统管理的信息单元提供关系和分层同步服务的系统和方法 | |
CN1270348A (zh) | 用于结构仿真的动态优化目标码翻译器和翻译方法 | |
CN1102934A (zh) | 增量连接系统 | |
CN1781078A (zh) | 硬件加速器个性编译器 | |
CN1739107A (zh) | 为可由硬件/软件接口系统管理的信息单元提供同步服务的系统和方法 | |
CN1728153A (zh) | 支持配置实体的选择性表示的配置说明语言的方法和系统 | |
CN1551006A (zh) | 分布式计算系统架构及分布式应用的设计、部署和管理 | |
CN1359489A (zh) | 用于构筑建模工具的装置和方法 | |
CN1063168A (zh) | 并行处理装置 | |
CN1524216A (zh) | 软件构件插件程序结构的系统和方法 | |
CN1828517A (zh) | 文档处理装置和文档处理方法 | |
CN100345105C (zh) | 办公应用程序中用于提供内容相关帮助信息的方法和系统 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
C02 | Deemed withdrawal of patent application after publication (patent law 2001) | ||
WD01 | Invention patent application deemed withdrawn after publication |