我的BIOS之行1-Introduction

发布时间 2023-08-15 14:16:18作者: King_Alex

前言

想对自己在本月所学的东西做一个总结,因而产生了写本系列博客的冲动,由于工作较为繁忙,不能及时更新,敬请原谅

CPU Introduction & Multi-Processor

本节博客将简单介绍CPU的情况。

1、CPU简介

CPU – The Central Processor Unit is the hardware within a computer system which carries out the instructions of a computer program by performing the basic arithmetical, logical, and input/output operations of the system.

CPU是运算的中心处理,相当于计算机的大脑,在计算机中起到至关重要的作用。

Two typical components of a CPU are the arithmetic logic unit (ALU), which performs arithmetic and logical operations, and the control unit (CU), which extracts instructions from memory and decodes and executes them, calling on the ALU when necessary.

CPU典型组件有ALU(算术逻辑单元)与CU(控制单元)

CPU中的寄存器如下:

1.1CPU Pipeline

Pipeline : An instruction pipeline is a technique used in the design of computers to increase their instruction throughput (the number of instructions that can be executed in a unit of time). Pipelining does not reduce the time to complete an instruction, but increases the number of instructions that can be processed at once.

Basic five-stage pipeline in a RISC machine (IF = Instruction Fetch, ID = Instruction Decode, EX = Execute, MEM = Memory access, WB = Register write back). In the fourth clock cycle (the green column), the earliest instruction is in MEM stage, and the latest instruction has not yet entered the pipeline.

其实通过这张图就可以看到基础的5级流水线制的基础运行模式!IF=指令取出,ID=指令解码,EX=执行,MEM =内存访问,WB=寄存器会写)。第四时钟周期(绿色列),MEM阶段,最早的指令和最新指令尚未进入管道。

BSP : The Boot Strap Processor is responsible for initializing the system and for booting the operating system.

AP : The Application processors are activated only after the operating system is up and running.

APIC : The Advanced Programmable Interrupt Controller units are collectively responsible for delivering interrupts from interrupt sources to interrupt destinations throughout the multiprocessor system.

具体可以参考计算机组成原理这本书

Aptio BIOS Overview

这里说的是一个BIOS的工具,但这个工具我也没有办法说清楚,只是有各种不一样的说明,在此我便不加以赘述。

module

对于一个BIOS的module,它具体有什么构成的?在这里,我将做一个介绍,告诉大家具体的情况。

一个module有

  • VEB: 管理Component
  • CIF : Component Information Format
  • SDL: System Description Language
  • C, H: C source & header
  • ASM: 組合語言文件(EFI BIOS 99% C + 1% ASM)
  • DXS: 依賴性表達式腳本文件(Dependency eXpression Script)
  • SD : Setup 定義文件(Setup Definition), 實現部分以前SSP的功能
  • UNI : 字符串定義文件(Unicode),實現以前ASD的功能
  • MAK: 組件的make檔
  • ASL – ACPI Source Language

加粗的文件類型是一个module 一定要有的file。

介绍Module

veb 文件管理組件, cif 文件管理組件中的其它文件或子模組

SDL 文件定義編譯過程中的一些參數,對應到BIOS Parameters。

DXS檔可以include header檔, 目的是爲了引入一些GUID的定義

DXS核心語法是
開始於DEPENDENCY_START
結束於DEPENDENCY_END
中間的條件表達式用連接詞鏈接
第一次練習可以直接在START和END之間寫一個永真表達式TRUE

SD 文件使用在外部某處定義的常量來分割描述語言,可以讓不同的使用者引入不同的定義部分。

EFI

  1. 基本的Chipset初始化
  2. Memory Sizing
  3. BIOS Recovery
  4. ACPI S3 Resume
  5. 切換Stack to Memory
  6. Disable CAR
  7. Enable Cache
  8. 啟動DxeIpl (DXE Initial Program Loader)

特性:
在ROM上執行
沒有壓縮的Code

PEI – PEIM, PPI

  • PEIM —— PEI的模組(Module)
  • PEI Core —— 提供PEIM基本的服務、負責Execute PEIM
  • PEI Service —— PEI Core所提供的服務函式, 所有的PEIM都可以使用
  • PPI —— 是PEI to PEI的介面(Interface),提供其他的PEIM使用的介面

每個PEIM都可以對外提供一些interface供其它PEIM來使用,這些interface可以指向function 或data, 這些interface 叫做PEIM-to-PEIM Interface (PPI).

當一個PEIM要使用另一個PEIM提供的interface時,首先要能夠成功的Locate所要使用的PPI。否則無法使用

這裡就是一個DLL的概念,一切都是動態的。在程式生成的時候,并不知道要使用的一些function是否ready, 必須在運行時動態查詢

EFI_STATUS EFIAPI HomeWorkPei_Init (
    IN EFI_FFS_FILE_HEADER      *FfsHeader,
    IN EFI_PEI_SERVICES         **PeiServices )
{
	EFI_STATUS   Status;     
        EFI_GUID     gPeiStallPpiGuid    = EFI_PEI_STALL_PPI_GUID;//delay id
        EFI_PEI_STALL_PPI	*StallPpi;//stall id
        EFI_GUID     gSetupGuid = SETUP_GUID; //setup id
        EFI_PEI_READ_ONLY_VARIABLE_PPI  *pReadOnlyVariable; //read id
        EFI_GUID	EfiPeiReadOnlyVariablePpiGuid = EFI_PEI_READ_ONLY_VARIABLE_PPI_GUID;

  
       SETUP_DATA	SetupData;
UINTN		nVariableSize = sizeof(SETUP_DATA);

    Status = (**PeiServices).LocatePpi(
	PeiServices,
	&EfiPeiReadOnlyVariablePpiGuid,
	0, NULL,
	(VOID**)&pReadOnlyVariable);
if (EFI_ERROR(Status)) {
            IoWrite16(0x80,0xA1);
            while(1);
	ASSERT_PEI_ERROR(PeiServices, Status);
	return Status;
}
    Status = pReadOnlyVariable->GetVariable(
	PeiServices,
	L"Setup",
	&gSetupGuid,
	NULL,
	&nVariableSize,
	(VOID*)&SetupData);
    if (EFI_ERROR(Status)) {
            IoWrite16(0x80,0xA2);
            while(1);
	ASSERT_PEI_ERROR(PeiServices, Status);
	return Status;
}
   
    Status = (**PeiServices).LocatePpi (PeiServices, &gPeiStallPpiGuid, 0,
                    NULL, (VOID **)&StallPpi);
   if (EFI_ERROR(Status)) {
            IoWrite16(0x80,0xA3);
            while(1);
	ASSERT_PEI_ERROR(PeiServices, Status);
	return Status;
}
    IoWrite16(0x80,0xAA);
    StallPpi->Stall(PeiServices,StallPpi,3*1000*1000);
    IoWrite16(0x80,SetupData.HomeWorkOption);
    //IoWrite16(0x80,0xA4);
    StallPpi->Stall(PeiServices,StallPpi,3*1000*1000);
    //IoWrite16(0x80,0xA5);
    //while(1);
//        IoWrite16(0x80,0xA6);
    return EFI_SUCCESS;
}   

DXE phase特性

既然有了PPI那么为什么还要DXE,通过它的特性,我可以发现,有许多事情PPI不能完成而DXE能够完成

  • 所有的Driver 都是壓縮過的
  • Code 都是在RAM 上執行
  • CPU Cache Enabled
  • 可以使用所有的Memory Resource
  • DXE core 和硬體沒有關聯
  • 避免使用中斷
  • Single Thread

什麽是Protocol

  • 和PPI的概念幾乎相同,本質是一個指針,指向一個data structure, data structure的域是一組指向function或data的指針。

  • 這些function或data就是Driver提供的Service.

  • 其它Driver可以通過調用Protocol的interface來訪問Service.

  • 和PPI一樣,Protocol必須能夠成功locate后才能使用

      EFI_STATUS HomeWorkDxe_Init (
      IN EFI_HANDLE       ImageHandle,
      IN EFI_SYSTEM_TABLE *SystemTable )
      {
      EFI_STATUS Status;
      SETUP_DATA	SetupData;
      UINTN		nVariableSize = sizeof(SETUP_DATA);
      EFI_GUID     gSetupGuid = SETUP_GUID; //setup id
      InitAmiLib(ImageHandle,SystemTable);
      Status = pRS->GetVariable (
                  L"Setup",
                  &gSetupGuid,
                  NULL,
                  &nVariableSize,
                  &SetupData
                  );
        if(EFI_ERROR(Status)){
           IoWrite16(0x80,0xB2);
              while(1);
         return Status;
         }
    	 IoWrite16(0x80,0xBB);
      pBS->Stall(3*1000*1000);
      IoWrite16(0x80,SetupData.HomeWorkOption);
      pBS->Stall(6*1000*1000);
     	return EFI_SUCCESS;
      }