小華的部落格: BIOS相關

搜尋此網誌

網頁

顯示具有 BIOS相關 標籤的文章。 顯示所有文章
顯示具有 BIOS相關 標籤的文章。 顯示所有文章

星期日, 5月 25, 2025

Dump TCG log

Dump TCG log

    一個簡易的方式在UEFI Shell底下,先找到TPM2 的ACPI Table ,再從Table中找到紀錄TCG log的記憶體位址(一般UEFI PCD目前都是設定0x10000 大小,但進入OS後,OS有可能會加大這塊的內容) ,然後分析TCG log中的每一筆紀錄的Event , 然後重新計算Digest ,這樣子可以呈現出BIOS交給OS前,TCG log中所記錄的TPM PCR可能的值會是甚麼. 底下是部分實作的程式碼,幫助大家了解流程. 


        // Loop through all ACPI tables to find TPM2

        Status = GetAcpiTableBySignature(SIGNATURE_32('T','P','M','2'), &Table);

        Tpm2Table =  (EFI_TPM2_ACPI_TABLE_V4 *) Table;


        if (Tpm2Table == NULL) {

            Print(L"[Fail] TPM2 ACPI Table not found\n");

            return EFI_NOT_FOUND;

        }


        Print(L"TPM2 ACPI Table found\n");

        Print(L"Event Log Start Address: 0x%lx\n", Tpm2Table->Lasa);

        Print(L"Event Log Length: %u bytes\n", Tpm2Table->Laml);

        Print(L"******** TCG Log Dump ******** \n");

        PrintHexAndAscii((UINT8 *) Tpm2Table->Lasa, (UINTN) Tpm2Table->Laml); // Print partial event data  


        Print(L"******** TCG Events ******** \n");


        // 儲存 PCR0 到 PCR23 的最後 Digest

        PCRDigest PcrDigests[PCR_COUNT];

        ZeroMem(PcrDigests, sizeof(PCRDigest) * PCR_COUNT);


        MY_ACPI_TCG2_EVENT *TcgEvent = (MY_ACPI_TCG2_EVENT *)(UINTN)Tpm2Table->Lasa;

        UINT8 *LogEnd = (UINT8 *)(UINTN)(Tpm2Table->Lasa + Tpm2Table->Laml);

        UINTN EventIndex = 0;


        while ((UINT8 *)TcgEvent < LogEnd) {

            UINT8 *EventStart = (UINT8 *)TcgEvent;

               //TODO:  1. 處理EV_NO_ACTION

                               2.CalculateDigest (CombinedData, CombinedDataSize, PcrDigests[PcrIndex].Digest, AlgId);


       } 

...

// 1.找到事件起始位置。
// 2.依序讀出:
// PCRIndex(4 bytes)
// EventType(4 bytes)
// DigestCount(4 bytes)
// 3.每個 Digest 結構:
//        AlgorithmId(2 bytes)
//        Digest(對 SHA128 而言,是 20 bytes, SHA256 而言,是 32 bytes..etc)
// 3.接著是 EventDataSize(4 bytes)
// 4.再來是 EventData
#pragma pack(1)
typedef struct {
    UINT32 PCRIndex;          // 4 bytes
    UINT32 EventType;         // 4 bytes
    UINT32 DigestCount;       // 4 bytes
                              // 之後是 DigestList 和 EventData
    UINT8  Event[];           // 可變長度,儲存 Digest 和 EventData (參考前面說明)
} MY_ACPI_TCG2_EVENT;
#pragma pack()

#define PCR_COUNT 24 // PCR0 到 PCR23,共 24 個 PCR

// 儲存每個 PCR 的最後一筆 Digest
typedef struct {
    UINT8 Digest[64];  // 假設 Digest 最長為 64 字節 (可以根據實際需要調整)
    UINTN DigestSize;  // Digest 大小
} PCRDigest;


UINTN
GetHashSizeFromAlgo(
  IN TPMI_ALG_HASH HashAlgo
  )
{
  switch (HashAlgo) {
    case TPM_ALG_SHA1:   return 20;
    case TPM_ALG_SHA256: return 32;
    case TPM_ALG_SHA384: return 48;
    case TPM_ALG_SHA512: return 64;
    case TPM_ALG_SM3_256:return 32;
    default:             return 0;
  }
}

// Hex + ASCII Dump
VOID
PrintHexAndAscii(IN UINT8 *Data, IN UINTN Length)
{
    for (UINTN i = 0; i < Length; i += 16) {
        Print(L"%08x: ", i);

        // Print hex
        for (UINTN j = 0; j < 16; j++) {
            if ((i + j) < Length) {
                Print(L"%02x ", Data[i + j]);
            } else {
                Print(L"   ");
            }
        }

        Print(L" ");

        // Print ASCII
        for (UINTN j = 0; j < 16; j++) {
            if ((i + j) < Length) {
                CHAR8 c = (CHAR8)Data[i + j];
                if (c >= 0x20 && c <= 0x7E) {
                    Print(L"%c", c);
                } else {
                    Print(L".");
                }
            }
        }

        Print(L"\n");
    }
}

// Covert to EventType string

CONST CHAR16* GetEventTypeString(UINT32 EventType)
{
    // Standard event types
    switch (EventType) {
        case EV_PREBOOT_CERT:             return L"EV_PREBOOT_CERT(0x00000000)";
        case EV_POST_CODE:                return L"EV_POST_CODE(0x00000001)";
        case EV_NO_ACTION:                return L"EV_NO_ACTION(0x00000003)";
        case EV_SEPARATOR:                return L"EV_SEPARATOR(0x00000004)";
        case EV_ACTION:                   return L"EV_ACTION(0x00000005)";
        case EV_EVENT_TAG:                return L"EV_EVENT_TAG(0x00000006)";
        case EV_S_CRTM_CONTENTS:          return L"EV_S_CRTM_CONTENTS(0x00000007)";
        case EV_S_CRTM_VERSION:           return L"EV_S_CRTM_VERSION(0x00000008)";
        case EV_CPU_MICROCODE:            return L"EV_CPU_MICROCODE(0x00000009)";
        case EV_PLATFORM_CONFIG_FLAGS:    return L"EV_PLATFORM_CONFIG_FLAGS(0x0000000A)";
        case EV_TABLE_OF_DEVICES:         return L"EV_TABLE_OF_DEVICES(0x0000000B)";
        case EV_COMPACT_HASH:             return L"EV_COMPACT_HASH(0x0000000C)";
        case EV_NONHOST_CODE:             return L"EV_NONHOST_CODE(0x0000000F)";
        case EV_NONHOST_CONFIG:           return L"EV_NONHOST_CONFIG(0x00000010)";
        case EV_NONHOST_INFO:             return L"EV_NONHOST_INFO(0x00000011)";
        case EV_OMIT_BOOT_DEVICE_EVENTS:  return L"EV_OMIT_BOOT_DEVICE_EVENTS(0x00000012)";

        // EFI specific event types (0x80000000 and above)
        case EV_EFI_VARIABLE_DRIVER_CONFIG:     return L"EV_EFI_VARIABLE_DRIVER_CONFIG(0x80000001)";
        case EV_EFI_VARIABLE_BOOT:              return L"EV_EFI_VARIABLE_BOOT(0x80000002)";
        case EV_EFI_BOOT_SERVICES_APPLICATION:  return L"EV_EFI_BOOT_SERVICES_APPLICATION(0x80000003)";
        case EV_EFI_BOOT_SERVICES_DRIVER:       return L"EV_EFI_BOOT_SERVICES_DRIVER(0x80000004)";
        case EV_EFI_RUNTIME_SERVICES_DRIVER:    return L"EV_EFI_RUNTIME_SERVICES_DRIVER(0x80000005)";
        case EV_EFI_GPT_EVENT:                  return L"EV_EFI_GPT_EVENT(0x80000006)";
        case EV_EFI_ACTION:                     return L"EV_EFI_ACTION(0x80000007)";
        case EV_EFI_PLATFORM_FIRMWARE_BLOB:     return L"EV_EFI_PLATFORM_FIRMWARE_BLOB(0x80000008)";
        case EV_EFI_HANDOFF_TABLES:             return L"EV_EFI_HANDOFF_TABLES(0x80000009)";
        case EV_EFI_PLATFORM_FIRMWARE_BLOB2:    return L"EV_EFI_PLATFORM_FIRMWARE_BLOB2(0x8000000A)";
        case EV_EFI_HANDOFF_TABLES2:            return L"EV_EFI_HANDOFF_TABLES2(0x8000000B)";
        case EV_EFI_HCRTM_EVENT:                return L"EV_EFI_HCRTM_EVENT(0x80000010)";
        case EV_EFI_VARIABLE_AUTHORITY:         return L"EV_EFI_VARIABLE_AUTHORITY(0x800000E0)";
        case EV_EFI_SPDM_FIRMWARE_BLOB:         return L"EV_EFI_SPDM_FIRMWARE_BLOB(0x800000E1)";
        case EV_EFI_SPDM_FIRMWARE_CONFIG:       return L"EV_EFI_SPDM_FIRMWARE_CONFIG(0x800000E2)";
        
        // Add 
        //case EV_EFI_SPDM_DEVICE_BLOB:           return L"EV_EFI_SPDM_DEVICE_BLOB(0x800000E1)"; // 和 EV_EFI_SPDM_FIRMWARE_BLOB 相同
        //case EV_EFI_SPDM_DEVICE_CONFIG:         return L"EV_EFI_SPDM_DEVICE_CONFIG(0x800000E2)"; // 和 EV_EFI_SPDM_FIRMWARE_CONFIG 相同

        default:                                return L"UNKNOWN(0x%08x)"; // Unknown event type
    }
}


#pragma pack(1)
typedef struct {                             // Refer to Tcg2Acpi.c 
  EFI_ACPI_DESCRIPTION_HEADER    Header;     // "TPM2"
  // Flags field is replaced in version 4 and above
  //    BIT0~15:  PlatformClass      This field is only valid for version 4 and above
  //    BIT16~31: Reserved
  UINT32                         Flags;
  UINT64                         AddressOfControlArea;
  UINT32                         StartMethod;
  UINT8                          PlatformSpecificParameters[12]; // size up to 12
  UINT32                         Laml;                           // Optional
  UINT64                         Lasa;                           // Optional
} EFI_TPM2_ACPI_TABLE_V4;
#pragma pack()


// Signature macro
//#define SIGNATURE_32(A,B,C,D)  ((UINT32)(A) | ((UINT32)(B)<<8) | ((UINT32)(C)<<16) | ((UINT32)(D)<<24))

EFI_STATUS
GetAcpiTableBySignature (
  IN  UINT32 Signature,
  OUT EFI_ACPI_DESCRIPTION_HEADER **OutTable
  )
{
  EFI_CONFIGURATION_TABLE             *ConfigTable = gST->ConfigurationTable;
  EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp = NULL;
  EFI_ACPI_DESCRIPTION_HEADER         *Xsdt;
  UINT64                              *EntryPtr;
  UINTN                               EntryCount;

  // Step 1: Find RSDP
  for (UINTN i = 0; i < gST->NumberOfTableEntries; i++) {
    if (CompareGuid(&ConfigTable[i].VendorGuid, &gEfiAcpi20TableGuid)) {
      Rsdp = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)ConfigTable[i].VendorTable;
      break;
    }
  }
  if (Rsdp == NULL) {
    Print(L"[Error] ACPI 2.0 RSDP not found\n");
    return EFI_NOT_FOUND;
  }

  // Step 2: Get XSDT
  Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);
  if (Xsdt->Signature != EFI_ACPI_6_3_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
    Print(L"[Error] XSDT Signature mismatch (found: %08X)\n", Xsdt->Signature);
    return EFI_NOT_FOUND;
  }

  // Step 3: Traverse XSDT entries
  EntryCount = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
  EntryPtr = (UINT64 *)(Xsdt + 1); // entries come right after the header

  for (UINTN i = 0; i < EntryCount; i++) {
    EFI_ACPI_DESCRIPTION_HEADER *Hdr = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)EntryPtr[i];
    if (Hdr->Signature == Signature) {
      *OutTable = Hdr;
      return EFI_SUCCESS;
    }
  }

  return EFI_NOT_FOUND;
}

EFI_STATUS
EFIAPI
CalculateDigest (
  IN UINT8  *Data,
  IN UINTN  DataSize,
  OUT UINT8  *Digest,
  IN UINT16  AlgId
  )
{
    BOOLEAN  Status;

    if (AlgId == TPM_ALG_SHA256) {
        Status = Sha256HashAll (Data, DataSize, Digest);
    } else {
        // 支援其他演算法
        return EFI_UNSUPPORTED;
    }

    if (!Status) {
        return EFI_DEVICE_ERROR;
    }

    return EFI_SUCCESS;
}

星期二, 9月 16, 2014

EDK2/EDKII Python Build Tool 兩三事 (Build.py)

EDK2 Python Build Tool 兩三事

最近因為工作需要,所以不得已逼自己去把EDK2 Python Build source code看完,看完後順便整理一下一些小重點,以免過陣子自己又忘記了。

     1)EDK_GLOBAL 
     這種定義的Macro只能給EDK1 driver使用,因為他會去檢查.inf 內的
     INF_VERSION  = 0x00010005 ,如果大於或是等於這個值就是當成EDK2,如果找不到這個值就會當成是EDK1。

因為不好用,所以就隨手改了一下CODE,讓他通吃EDK1 + EDK2 + FDF + DSC + DEC + INF

   2) Build Rule and Package rule
   在EDK2 中,他把EDK1原本的Build Rule & Package Rule 分別描述成:
        Tools_def.txt 
        Build_Rule.txt
        [Rule.$(Arch).$(ModuleType] 

好不好用看個人,不過如果你要支援原本EDK1 Package Rule時那就對不起啦,你要修改Python source code,不然你做不到。  例如說底下的EDK1 的COMPONENT_TYPE = FILE原本對應到某個Package Rule,但是在EDK2內不支援就是不支援,除非自己改python source code.

[Defines]
BASE_NAME               = xxxxx
FILE_GUID                   = 126A4D6A-C404-4200-8779-F327A4A79087
COMPONENT_TYPE  = FILE
BUILD_TYPE               = MAKEFILE

   3) Python v.s SQL
   Python build tool 只是拿SQL當成是存放他收集到的資料的一個地方,然後在另一個地方就可以去撈資料庫內的資訊然後寫對應的CODE去分析要幹嘛,所以rebuild的時候最好把這個資料庫暫存檔案刪除。 EX: Conf\.cache\build.db

   4) GenSection & GenFFS
   以前EDK1的這兩個工具也整合進去Python Build tool內了,所以想了解FDF是怎麼產生FV或是FD的人就請自行研究,不過他是另一隻Tool叫做GenFds.py。

   5) AutoGen.c v.s AutoGen.h
   偷偷產生的檔案用來存放一些PCD操作/有用到的PCD Value,GUID 定義跟一些偷塞的include... 如果是給PCD database使用的,他還會塞Dynamic PCD給PCD 資料庫當成初始化值。

    另外,Library 只會產生AutoGen.h 不會產生AutoGen.c,因為Library通常會跟某個Driver Link,所以等到真正要去產生Module make時,才會去檢查Library 內用到的GUID/PCD ,然後產生在Module's AutoGen.c內。

    6) Hard code
    恩,很多東西都寫死在Python build tool內,像是nmake command 要增加修改時就要改一改他,不過也是個好處,就是我可以偷加很多東西在裡面,然後不給你source code...哈!!!

   7) 產生執行檔
    .py  轉成 .exe 方式我自己再用的有兩種,一種是py2Exe不過版本過舊已經不能支援了,所以我採用EDK2 所建議的cx_Freeze 去轉換,轉換時還要搭配你的Python 版本,目前我看到的codebase內使用的是Python 2.7.3,所以應該以這個為主吧! 底下是EDK2 建議的方式:

Using cx_Freeze 4.2.3 with Python 2.7.2
Using cx_Freeze 3.0.3 with Python 2.5.4

  8) 嗯...有想到再說~


     
   




星期一, 6月 20, 2011

SmmOEMInt15SmiDispatcher

今天在Debug USB問題的時候,設定了斷點在SmmOEMInt15SmiDispatcher中,結果發現進入DOS時這個SWSMI會被一直呼叫。

他的原因是因為CSM 在Hook INT15h的時候,並沒有先在Assembly內判斷任何的Signature,沒有利用任何的Signature來判斷要不要產生SWSMI,因此就變成了只要有人呼叫INT15h 就會產生SWSMI而跳到SmmOEMInt15SmiDispatcher內,然後再EFI 那邊再判斷要不要執行Sub function,如果沒有就退出SWSMI。

為了怕自己忘記有這個BUG所以在BLOG先記錄一下。

目前進入DOS時,有看到呼叫INT15h的人是CONFIG.SYS,而且每按一次Key,就會呼叫3次(SWSMI斷點可以攔到3次?) 這也是件奇怪的事情。

開機過程中攔截到的INT15h 時的AX值如下(依順序):
AX=5355
AX=4101
AX=0000
AX=133A
AX=0326 (此時已經出現Win98 Logo)
AX=3E00 <--我們自己的USB test Utility

進入DOS後,每按下一個Key都會產生下面這個INT15h,看起來跟Config.sys有關,不過尚未查證:  AX=5355h , INT15h  <--Config.sys

星期二, 2月 22, 2011

BlueScreen

發現BlueScreen後,在求救前微軟希望你做的事情:


1. 按 "開始",在 "電腦" 按滑鼠右鍵,選擇 "內容"
2. 選擇 "進階系統設定"
3. 切換到 "進階" 索引標籤,在 "啟動及修復"的分類中,選擇 "設定"
4. 系統失敗分類打勾全選,當有錯誤時會產生Log在底下的路徑檔案中
%SystemRoot%\MEMORY.DMP

這邊有個工具 AppCrashView 讓你可以去分析Log

微軟網站也有一些說明:

另外一個工具 BlueScreenView

星期日, 1月 09, 2011

Microsoft PNPID

今天有同事來問我PNPID,我一直以為我有把這些資料放到部落格了,但是後來才在我的筆記本資料匣內找到,為了大家方便所以就順便放到部落格,給一些需要查資料的人使用。

我另一個同事的部落格也有相關資料,大家也可以去參考一下他的部落格:


WINDOWS GENERIC DEVICE IDs

----------------------------------------------------------------------
Many devices have no standard EISA ID, such as the interrupt controller
or keyboard controller. Also, a set of compatible devices, such as VGA
and Super VGA, are not actually devices, but define a compatibility
hardware subset. Yet another set of IDs needs to be used to identify
buses.

Microsoft has reserved an EISA prefix of "PNP" to identify various
devices that do not have an existing EISA ID, as well as defining
compatibility devices. The IDs are defined in the following tables.

DEVICE ID RANGES

ID range Category
-------- -------------
PNP0xxx System devices
PNP8xxx Network adapters
PNPAxxx SCSI, proprietary CD adapters
PNPBxxx Sound, video capture, multimedia
PNPCxxx - Dxxx Modems

The following device ID is provided only for compatibility
with earlier device ID lists:

Device ID Description
-------- -------------
PNP0802 Microsoft Sound System-compatible device
(obsolete; use PNPB0xx instead)

---------------------------------------------------------------------------
Device ID Description
-------- -------------
***** System Devices - PNP0xxx **************************
--Interrupt Controllers--
PNP0000 AT Interrupt Controller
PNP0001 EISA Interrupt Controller
PNP0002 MCA Interrupt Controller
PNP0003 APIC
PNP0004 Cyrix SLiC MP interrupt controller

--Timers--
PNP0100 AT Timer
PNP0101 EISA Timer
PNP0102 MCA Timer

--DMA--
PNP0200 AT DMA Controller
PNP0201 EISA DMA Controller
PNP0202 MCA DMA Controller

--Keyboards--
PNP0300 IBM PC/XT keyboard controller (83-key)
PNP0301 IBM PC/AT keyboard controller (86-key)
PNP0302 IBM PC/XT keyboard controller (84-key)
PNP0303 IBM Enhanced (101/102-key, PS/2 mouse support)
PNP0304 Olivetti Keyboard (83-key)
PNP0305 Olivetti Keyboard (102-key)
PNP0306 Olivetti Keyboard (86-key)
PNP0307 Microsoft Windows(R) Keyboard
PNP0308 General Input Device Emulation Interface (GIDEI) legacy
PNP0309 Olivetti Keyboard (A101/102 key)
PNP030A AT&T 302 keyboard
PNP030B Reserved by Microsoft
PNP0320 Japanese 106-key keyboard A01
PNP0321 Japanese 101-key keyboard
PNP0322 Japanese AX keyboard
PNP0323 Japanese 106-key keyboard 002/003
PNP0324 Japanese 106-key keyboard 001
PNP0325 Japanese Toshiba Desktop keyboard
PNP0326 Japanese Toshiba Laptop keyboard
PNP0327 Japanese Toshiba Notebook keyboard
PNP0340 Korean 84-key keyboard
PNP0341 Korean 86-key keyboard
PNP0342 Korean Enhanced keyboard
PNP0343 Korean Enhanced keyboard 101b
PNP0343 Korean Enhanced keyboard 101c
PNP0344 Korean Enhanced keyboard 103

--Parallel Devices--
PNP0400 Standard LPT printer port
PNP0401 ECP printer port

--Serial Devices--
PNP0500 Standard PC COM port
PNP0501 16550A-compatible COM port
PNP0510 Generic IRDA-compatible device

--Disk Controllers--
PNP0600 Generic ESDI/IDE/ATA compatible hard disk controller
PNP0601 Plus Hardcard II
PNP0602 Plus Hardcard IIXL/EZ
PNP0603 Generic IDE supporting Microsoft Device Bay Specification
PNP0700 PC standard floppy disk controller
PNP0701 Standard floppy controller supporting MS Device Bay Spec

--Compatibility with early device ID list--
PNP0802 Microsoft Sound System compatible device (obsolete, use
PNPB0xx instead)
--Display Adapters--
PNP0900 VGA Compatible
PNP0901 Video Seven VRAM/VRAM II/1024i
PNP0902 8514/A Compatible
PNP0903 Trident VGA
PNP0904 Cirrus Logic Laptop VGA
PNP0905 Cirrus Logic VGA
PNP0906 Tseng ET4000
PNP0907 Western Digital VGA
PNP0908 Western Digital Laptop VGA
PNP0909 S3 Inc. 911/924
PNP090A ATI Ultra Pro/Plus (Mach 32)
PNP090B ATI Ultra (Mach 8)
PNP090C XGA Compatible
PNP090D ATI VGA Wonder
PNP090E Weitek P9000 Graphics Adapter
PNP090F Oak Technology VGA
PNP0910 Compaq QVision
PNP0911 XGA/2
PNP0912 Tseng Labs W32/W32i/W32p
PNP0913 S3 Inc. 801/928/964
PNP0914 Cirrus Logic 5429/5434 (memory mapped)
PNP0915 Compaq Advanced VGA (AVGA)
PNP0916 ATI Ultra Pro Turbo (Mach64)
PNP0917 Reserved by Microsoft
PNP0918 Matrox MGA
PNP0919 Compaq QVision 2000
PNP091A Tseng W128
PNP0930 Chips & Technologies Super VGA
PNP0931 Chips & Technologies Accelerator
PNP0940 NCR 77c22e Super VGA
PNP0941 NCR 77c32blt
PNP09FF Plug and Play Monitors (VESA DDC)

--Peripheral Buses--
PNP0A00 ISA Bus
PNP0A01 EISA Bus
PNP0A02 MCA Bus
PNP0A03 PCI Bus
PNP0A04 VESA/VL Bus
PNP0A05 Generic ACPI Bus
PNP0A06 Generic ACPI Extended-IO Bus (EIO bus)


-- Real Time Clock, BIOS, System board devices--
PNP0800 AT-style speaker sound
PNP0B00 AT Real-Time Clock
PNP0C00 Plug and Play BIOS (only created by the root enumerator)
PNP0C01 System Board
PNP0C02 General ID for reserving resources required by Plug and Play
motherboard registers. (Not specific to a particular device.)
PNP0C03 Plug and Play BIOS Event Notification Interrupt
PNP0C04 Math Coprocessor
PNP0C05 APM BIOS (Version independent)
PNP0C06 Reserved for identification of early Plug and Play
BIOS implementation.
PNP0C07 Reserved for identification of early Plug and Play
BIOS implementation.
PNP0C08 ACPI system board hardware
PNP0C09 ACPI Embedded Controller
PNP0C0A ACPI Control Method Battery
PNP0C0B ACPI Fan
PNP0C0C ACPI power button device
PNP0C0D ACPI lid device
PNP0C0E ACPI sleep button device
PNP0C0F PCI interrupt link device
PNP0C10 ACPI system indicator device
PNP0C11 ACPI thermal zone
PNP0C12 Device Bay Controller

--PCMCIA Controller Chipsets--
PNP0E00 Intel 82365-Compatible PCMCIA Controller
PNP0E01 Cirrus Logic CL-PD6720 PCMCIA Controller
PNP0E02 VLSI VL82C146 PCMCIA Controller
PNP0E03 Intel 82365-compatible CardBus controller

--Mice--
PNP0F00 Microsoft Bus Mouse
PNP0F01 Microsoft Serial Mouse
PNP0F02 Microsoft InPort Mouse
PNP0F03 Microsoft PS/2-style Mouse
PNP0F04 Mouse Systems Mouse
PNP0F05 Mouse Systems 3-Button Mouse (COM2)
PNP0F06 Genius Mouse (COM1)
PNP0F07 Genius Mouse (COM2)
PNP0F08 Logitech Serial Mouse
PNP0F09 Microsoft BallPoint Serial Mouse
PNP0F0A Microsoft Plug and Play Mouse
PNP0F0B Microsoft Plug and Play BallPoint Mouse
PNP0F0C Microsoft-compatible Serial Mouse
PNP0F0D Microsoft-compatible InPort-compatible Mouse
PNP0F0E Microsoft-compatible PS/2-style Mouse
PNP0F0F Microsoft-compatible Serial BallPoint-compatible Mouse
PNP0F10 Texas Instruments QuickPort Mouse
PNP0F11 Microsoft-compatible Bus Mouse
PNP0F12 Logitech PS/2-style Mouse
PNP0F13 PS/2 Port for PS/2-style Mice
PNP0F14 Microsoft Kids Mouse
PNP0F15 Logitech bus mouse
PNP0F16 Logitech SWIFT device
PNP0F17 Logitech-compatible serial mouse
PNP0F18 Logitech-compatible bus mouse
PNP0F19 Logitech-compatible PS/2-style Mouse
PNP0F1A Logitech-compatible SWIFT Device
PNP0F1B HP Omnibook Mouse
PNP0F1C Compaq LTE Trackball PS/2-style Mouse
PNP0F1D Compaq LTE Trackball Serial Mouse
PNP0F1E Microsoft Kids Trackball Mouse
PNP0F1F Reserved by Microsoft Input Device Group
PNP0F20 Reserved by Microsoft Input Device Group
PNP0F21 Reserved by Microsoft Input Device Group
PNP0F22 Reserved by Microsoft Input Device Group
PNP0F23 Reserved by Microsoft Input Device Group
PNP0FFF Reserved by Microsoft Systems

***** Network Adapters - PNP8xxx ***********************
PNP8001 Novell/Anthem NE3200
PNP8004 Compaq NE3200
PNP8006 Intel EtherExpress/32
PNP8008 HP EtherTwist EISA LAN Adapter/32 (HP27248A)
PNP8065 Ungermann-Bass NIUps or NIUps/EOTP
PNP8072 DEC (DE211) EtherWorks MC/TP
PNP8073 DEC (DE212) EtherWorks MC/TP_BNC
PNP8078 DCA 10 Mb MCA
PNP8074 HP MC LAN Adapter/16 TP (PC27246)
PNP80c9 IBM Token Ring
PNP80ca IBM Token Ring II
PNP80cb IBM Token Ring II/Short
PNP80cc IBM Token Ring 4/16Mbs
PNP80d3 Novell/Anthem NE1000
PNP80d4 Novell/Anthem NE2000
PNP80d5 NE1000 Compatible
PNP80d6 NE2000 Compatible
PNP80d7 Novell/Anthem NE1500T
PNP80d8 Novell/Anthem NE2100
PNP80dd SMC ARCNETPC
PNP80de SMC ARCNET PC100, PC200
PNP80df SMC ARCNET PC110, PC210, PC250
PNP80e0 SMC ARCNET PC130/E
PNP80e1 SMC ARCNET PC120, PC220, PC260
PNP80e2 SMC ARCNET PC270/E
PNP80e5 SMC ARCNET PC600W, PC650W
PNP80e7 DEC DEPCA
PNP80e8 DEC (DE100) EtherWorks LC
PNP80e9 DEC (DE200) EtherWorks Turbo
PNP80ea DEC (DE101) EtherWorks LC/TP
PNP80eb DEC (DE201) EtherWorks Turbo/TP
PNP80ec DEC (DE202) EtherWorks Turbo/TP_BNC
PNP80ed DEC (DE102) EtherWorks LC/TP_BNC
PNP80ee DEC EE101 (Built-In)
PNP80ef DECpc 433 WS (Built-In)
PNP80f1 3Com EtherLink Plus
PNP80f3 3Com EtherLink II or IITP (8 or 16-bit)
PNP80f4 3Com TokenLink
PNP80f6 3Com EtherLink 16
PNP80f7 3Com EtherLink III
PNP80f8 3Com Generic Etherlink Plug and Play Device
PNP80fb Thomas Conrad TC6045
PNP80fc Thomas Conrad TC6042
PNP80fd Thomas Conrad TC6142
PNP80fe Thomas Conrad TC6145
PNP80ff Thomas Conrad TC6242
PNP8100 Thomas Conrad TC6245
PNP8105 DCA 10 MB
PNP8106 DCA 10 MB Fiber Optic
PNP8107 DCA 10 MB Twisted Pair
PNP8113 Racal NI6510
PNP811C Ungermann-Bass NIUpc
PNP8120 Ungermann-Bass NIUpc/EOTP
PNP8123 SMC StarCard PLUS (WD/8003S)
PNP8124 SMC StarCard PLUS With On Board Hub (WD/8003SH)
PNP8125 SMC EtherCard PLUS (WD/8003E)
PNP8126 SMC EtherCard PLUS With Boot ROM Socket (WD/8003EBT)
PNP8127 SMC EtherCard PLUS With Boot ROM Socket (WD/8003EB)
PNP8128 SMC EtherCard PLUS TP (WD/8003WT)
PNP812a SMC EtherCard PLUS 16 With Boot ROM Socket (WD/8013EBT)
PNP812d Intel EtherExpress 16 or 16TP
PNP812f Intel TokenExpress 16/4
PNP8130 Intel TokenExpress MCA 16/4
PNP8132 Intel EtherExpress 16 (MCA)
PNP8137 Artisoft AE-1
PNP8138 Artisoft AE-2 or AE-3
PNP8141 Amplicard AC 210/XT
PNP8142 Amplicard AC 210/AT
PNP814b Everex SpeedLink /PC16 (EV2027)
PNP8155 HP PC LAN Adapter/8 TP (HP27245)
PNP8156 HP PC LAN Adapter/16 TP (HP27247A)
PNP8157 HP PC LAN Adapter/8 TL (HP27250)
PNP8158 HP PC LAN Adapter/16 TP Plus (HP27247B)
PNP8159 HP PC LAN Adapter/16 TL Plus (HP27252)
PNP815f National Semiconductor Ethernode *16AT
PNP8160 National Semiconductor AT/LANTIC EtherNODE 16-AT3
PNP816a NCR Token-Ring 4 Mbs ISA
PNP816d NCR Token-Ring 16/4 Mbs ISA
PNP8191 Olicom 16/4 Token-Ring Adapter
PNP81c3 SMC EtherCard PLUS Elite (WD/8003EP)
PNP81c4 SMC EtherCard PLUS 10T (WD/8003W)
PNP81c5 SMC EtherCard PLUS Elite 16 (WD/8013EP)
PNP81c6 SMC EtherCard PLUS Elite 16T (WD/8013W)
PNP81c7 SMC EtherCard PLUS Elite 16 Combo (WD/8013EW or 8013EWC)
PNP81c8 SMC EtherElite Ultra 16
PNP81e4 Pure Data PDI9025-32 (Token Ring)
PNP81e6 Pure Data PDI508+ (ArcNet)
PNP81e7 Pure Data PDI516+ (ArcNet)
PNP81eb Proteon Token Ring (P1390)
PNP81ec Proteon Token Ring (P1392)
PNP81ed Proteon ISA Token Ring (1340)
PNP81ee Proteon ISA Token Ring (1342)
PNP81ef Proteon ISA Token Ring (1346)
PNP81f0 Proteon ISA Token Ring (1347)
PNP81ff Cabletron E2000 Series DNI
PNP8200 Cabletron E2100 Series DNI
PNP8209 Zenith Data Systems Z-Note
PNP820a Zenith Data Systems NE2000-Compatible
PNP8213 Xircom Pocket Ethernet II
PNP8214 Xircom Pocket Ethernet I
PNP821d RadiSys EXM-10
PNP8227 SMC 3000 Series
PNP8228 SMC 91C2 controller
PNP8231 Advanced Micro Devices AM2100/AM1500T
PNP8263 Tulip NCC-16
PNP8277 Exos 105
PNP828A Intel '595 based Ethernet
PNP828B TI2000-style Token Ring
PNP828C AMD PCNet Family cards
PNP828D AMD PCNet32 (VL version)
PNP8294 IrDA Infrared NDIS driver (Microsoft-supplied)
PNP82bd IBM PCMCIA-NIC
PNP82C2 Xircom CE10
PNP82C3 Xircom CEM2
PNP8321 DEC Ethernet (All Types)
PNP8323 SMC EtherCard (All Types except 8013/A)
PNP8324 ARCNET Compatible
PNP8326 Thomas Conrad (All Arcnet Types)
PNP8327 IBM Token Ring (All Types)
PNP8385 Remote Network Access Driver
PNP8387 RNA Point-to-point Protocol Driver
PNP8388 Reserved for Microsoft Networking components
PNP8389 Peer IrLAN infrared driver (Microsoft-supplied)

***** SCSI, Proprietary CD Adapters - PNPAxxx **********
PNPA002 Future Domain 16-700 compatible controller
PNPA003 Panasonic proprietary CD-ROM adapter (SBPro/SB16)
PNPA01B Trantor 128 SCSI Controller
PNPA01D Trantor T160 SCSI Controller
PNPA01E Trantor T338 Parallel SCSI controller
PNPA01F Trantor T348 Parallel SCSI controller
PNPA020 Trantor Media Vision SCSI controller
PNPA022 Always IN-2000 SCSI controller
PNPA02B Sony proprietary CD-ROM controller
PNPA02D Trantor T13b 8-bit SCSI controller
PNPA02F Trantor T358 Parallel SCSI controller
PNPA030 Mitsumi LU-005 Single Speed CD-ROM controller + drive
PNPA031 Mitsumi FX-001 Single Speed CD-ROM controller + drive
PNPA032 Mitsumi FX-001 Double Speed CD-ROM controller + drive

***** Sound/Video-capture, multimedia - PNPBxxx ********
PNPB000 Sound Blaster 1.5-compatible sound device
PNPB001 Sound Blaster 2.0-compatible sound device
PNPB002 Sound Blaster Pro-compatible sound device
PNPB003 Sound Blaster 16-compatible sound device
PNPB004 Thunderboard-compatible sound device
PNPB005 Adlib-compatible FM synthesizer device
PNPB006 MPU401 compatible
PNPB007 Microsoft Windows Sound System-compatible sound device
PNPB008 Compaq Business Audio
PNPB009 Plug and Play Microsoft Windows Sound System Device
PNPB00A MediaVision Pro Audio Spectrum
(Trantor SCSI enabled, Thunder Chip Disabled)
PNPB00B MediaVision Pro Audio 3D
PNPB00C MusicQuest MQX-32M
PNPB00D MediaVision Pro Audio Spectrum Basic
(No Trantor SCSI, Thunder Chip Enabled)
PNPB00E MediaVision Pro Audio Spectrum
(Trantor SCSI enabled, Thunder Chip Enabled)
PNPB00F MediaVision Jazz-16 chipset (OEM Versions)
PNPB010 Auravision VxP500 chipset - Orchid Videola
PNPB018 MediaVision Pro Audio Spectrum 8-bit
PNPB019 MediaVision Pro Audio Spectrum Basic
(no Trantor SCSI, Thunder chip Disabled)
PNPB020 Yamaha OPL3-compatible FM synthesizer device
PNPB02F Joystick/Game port

***** Modems - PNPCxxx-Dxxx****************************
PNPC000 Compaq 14400 Modem (TBD)
PNPC001 Compaq 2400/9600 Modem (TBD)

======================================================================

DEVICE TYPE CODES

-----------------------------------------------------------------------
Base Type = 0: Reserved
Base Type = 1: Mass Storage Device
Sub-Type = 0: SCSI Controller
Sub-Type = 1: IDE Controller (Standard ATA compatible)
Interface Type = 0: Generic IDE
Sub-Type = 2: Floppy Controller (Standard 765 compatible)
Interface Type = 0: Generic Floppy
Sub-Type = 3: IPI Controller
Interface Type = 0: General IPI
Sub-Type = 80h: Other Mass Storage Controller
Base Type = 2: Network Interface Controller
Sub-Type = 0: Ethernet
Interface Type = 0: General Ethernet
Sub-Type = 1: Token Ring Controller
Interface Type = 0: General Token Ring
Sub-Type = 2: FDDI Controller
Interface Type = 0: General FDDI
Sub-Type = 80h: Other Network Interface Controller

Base Type = 3: Display Controller
Sub-Type = 0: VGA Controller (Standard VGA compatible)
Interface Type = 0: Generic VGA compatible
Interface Type = 1: VESA SVGA Compatible Controller
Sub-Type = 1: XGA Compatible Controller
Interface Type = 0: General XGA Compatible Controller
Sub-Type = 80h: Other Display Controller
Base Type = 4: Multi-media Controller
Sub-Type = 0: Video Controller
Interface Type = 0: General Video
Sub-Type = 1: Audio Controller
Interface Type = 0: General Audio Controller
Sub-Type = 80h: Other Multi-media Controller
Base Type = 5: Memory
Sub-Type = 0: RAM
Interface Type = 0: General RAM
Sub-Type = 1: FLASH Memory
Interface Type = 0: General FLASH Memory
Sub-Type = 80h: Other Memory Device

Base Type = 6: Bridge Controller
Sub-Type = 0: Host Processor Bridge
Interface Type = 0: General Host Processor Bridge
Sub-Type = 1: ISA Bridge
Interface Type = 0: General ISA Bridge
Sub-Type = 2: EISA Bridge
Interface Type = 0: General EISA Bridge
Sub-Type = 3: MicroChannel Bridge
Interface Type = 0: General Micro-Channel Bridge
Sub-Type = 4: PCI Bridge
Interface Type = 0: General PCI Bridge
Sub-Type = 5: PCMCIA Bridge
Interface Type = 0: General PCMCIA Bridge
Sub-Type = 80h: Other Bridge Device
Base Type = 7: Communications Device
Sub-Type = 0: RS-232 Device (XT-compatible COM)
Interface Type = 0: Generic XT-compatible
Interface Type = 1: 16450-compatible
Interface Type = 2: 16550-compatible
Sub-Type = 1: AT-Compatible Parallel Port
Interface Type = 0: Generic AT Parallel Port
Interface Type = 1: Model-30 Bidirectional Port
Interface Type = 2: ECP 1.? compliant port
Sub-Type = 80h: Other Communications Device
Base Type = 8: System Peripherals
Sub-Type = 0: Programmable Interrupt Controller (8259 Compatible)
Interface Type = 0: Generic 8259 PIC
Interface Type = 1: ISA PIC (8259 Compatible)
Interface Type = 2: EISA PIC (8259 Compatible)
Sub-Type = 1: DMA Controller (8237 Compatible)
Interface Type = 0: Generic DMA Controller
Interface Type = 1: ISA DMA Controller
Interface Type = 2: EISA DMA Controller
Sub-Type = 2: System Timer (8254 Compatible)
Interface Type = 0: Generic System Timer
Interface Type = 1: ISA System Timer
Interface Type = 2: EISA System Timers (2 Timers)
Sub-Type = 3: Real Time Clock
Interface Type = 0: Generic RTC Controller
Interface Type = 1: ISA RTC Controller
Sub-Type = 80h: Other System Peripheral
Base Type = 9: Input Devices
Sub-Type = 0: Keyboard Controller
Interface Type = 0: Not applicable
Sub-Type = 1: Digitizer (Pen)
Interface Type = 0: Not applicable
Sub-Type = 2: Mouse Controller
Interface Type = 0: Not applicable
Sub-Type = 80h: Other Input Controller
Base Type = 0Ah: Docking Station
Sub-Type = 0: Generic Docking Station
Interface Type = 0: Not applicable
Sub-Type = 80h: Other type of Docking Station
Base Type = 0Bh: CPU Type
Sub-Type = 0: 386-based processor
Interface Type = 0: Not applicable
Sub-Type = 1: 486-based processor
Interface Type = 0: Not applicable
Sub-Type = 2: Pentium-based processor
Interface Type = 0: Not applicable


Reference

星期六, 11月 06, 2010

ACPI1.0/ ACPI2.0 傻傻分不清楚?

最近在解一條ACPI Bug,遇到了XP 的ACPI Support的問題!
所以這邊留個紀錄,紀錄一下XP到底是支援哪一種ACPI 版本?

從微軟文件可以看到這兩句話:

Windows XP is not an ACPI 2.0 implementation
Windows XP implements ACPI 1.0b and supports a few new features defined in ACPI 2.0

WinXP不是完全支援ACPI2.0 ,WinXP是ACPI1.0b +某些ACPI2.0的功能!

星期四, 4月 22, 2010

Cx State

最近很少更新部落格,都被一些網友說"小華已經很久沒更新了"...所以就先上來更新些文章QQ..

先說說Cx State 在BIOS端是怎麼跟CPU還有ASL code甚至是SetupMenu串再一起的.

首先,一般BIOS會在SetupMenu中建立出一些item來控制Cx State的Enable/Disable,這部分會因為各家BIOS在SetupMenu上的做法不同而有所不同,但是你只要知道一個東西! 就是一定會有一個地方儲存好SetupMenu上選項內的設定值. (Ex: CMOS/EFI Variable...)

接著,在PPM 的相關 Reference code那邊 (一般都是Ixxel的CPU的PPM reference code)會去參考SetupMenu內的設定值來組態CPU內部的MSR暫存器,至於他是如何得到SetupMenu的設定值又會因為不同的BIOS而有所不同,像是EFI就可能透過Policy來得到,所以要有人把SetupMenu的值放進去Policy內,這樣子Reference code才能參考SetupMenu的選項來組態MSR!

當這邊在一般組態MSR時,他會一邊修改Acpi Table! 例如你想關閉C2/C3,大家都知道去ACPI Table把值改成>100 或是 > 1001就可以了,所以這邊的Reference code會去參考你的SetupMenu的設定值來決定要不要修改ACPI Table內那個回報給OS的值!

其他的部分有牽扯到ASL code的部分我可能就不明說了,請大家搜尋CFGD這個值,看看他在哪邊被放進,然後ASL code為什麼要判斷他! 追個一遍就清楚了^^Y

星期二, 12月 23, 2008

SST SPI Serial Flash

今天在網路瀏覽的時候看到SST 有提供 Software Driver 的範例程式,從範例程式中可以很容易的知道如何
去控制Flash part的存取 , 如果想學R/W Flash Part的朋友可以參考看看,而底下是一個範例程式:

SST25VF080B 8 Mbit(1M x 8) Serial Flash Memory

November 4th, 2005, Rev. 1.0

ABOUT THE SOFTWARE
This application note provides software driver examples for SST25VF080B,
Serial Flash. Extensive comments are included in each routine to describe
the function of each routine. The interface coding uses polling method
rather than the SPI protocol to interface with these serial devices. The
functions are differentiated below in terms of the communication protocols
(uses Mode 0) and specific device operation instructions. This code has been
designed to compile using the Keil compiler.


ABOUT THE SST25VF080B

Companion product datasheets for the SST25VF080B should be reviewed in
conjunction with this application note for a complete understanding
of the device.


Device Communication Protocol(pinout related) functions:

Functions Function
------------------------------------------------------------------
init Initializes clock to set up mode 0.
Send_Byte Sends one byte using SI pin to send and
shift out 1-bit per clock rising edge
Get_Byte Receives one byte using SO pin to receive and shift
in 1-bit per clock falling edge
Poll_SO Used in the polling for RY/BY# of SO during AAI programming
CE_High Sets Chip Enable pin of the serial flash to high
CE_Low Clears Chip Enable of the serial flash to low
Hold_Low Clears Hold pin to make serial flash hold
Unhold Unholds the serial flash
WP_Low Clears WP pin to make serial flash write protected
UnWP Disables write protection pin

Note: The pin names of the SST25VF080B are used in this application note. The associated test code
will not compile unless these pinouts (SCK, SI, SO, SO, CE, WP, Hold) are pre-defined on your
software which should reflect your hardware interfaced.


Device Operation Instruction functions:

Functions Function
------------------------------------------------------------------
Read_Status_Register Reads the status register of the serial flash
EWSR Enables the Write Status Register
WRSR Performs a write to the status register
WREN Write enables the serial flash
WRDI Write disables the serial flash
EBSY Enable SO to output RY/BY# status during AAI programming
DBSY Disable SO to output RY/BY# status during AAI programming
Read_ID Reads the manufacturer ID and device ID
Jedec_ID_Read Reads the Jedec ID
Read Reads one byte from the serial flash and returns byte(max of 25 MHz CLK frequency)
Read_Cont Reads multiple bytes(max of 25 MHz CLK frequency)
HighSpeed_Read Reads one byte from the serial flash and returns byte(max of 50 MHz CLK frequency)
HighSpeed_Read_Cont Reads multiple bytes(max of 50 MHz CLK frequency)
Byte_Program Program one byte to the serial flash
Auto_Add_IncA Initial Auto Address Increment process
Auto_Add_IncB Successive Auto_Address_Increment process after AAI initiation
Auto_Add_IncA_EBSY Initial Auto Address Increment process with EBSY
Auto_Add_IncB_EBSY Successive Auto_Address_Increment process after AAI initiation with EBSY and WRDI/DBSY
Chip_Erase Erases entire serial flash
Sector_Erase Erases one sector (4 KB) of the serial flash
Block_Erase_32K Erases 32 KByte block memory of the serial flash
Block_Erase_64K Erases 64 KByte block memory of the serial flash
Wait_Busy Polls status register until busy bit is low
Wait_Busy_AAI Polls status register until busy bit is low for AAI programming
WREN_Check Checks to see if WEL is set
WREN_AAI_Check Checks to see if WEL and AAI mode is set




"C" LANGUAGE DRIVERS

/********************************************************************/
/* Copyright Silicon Storage Technology, Inc. (SST), 1994-2005 */
/* Example "C" language Driver of SST25VF080B Serial Flash */
/* Conrado Canio, Silicon Storage Technology, Inc. */
/* */
/* Revision 1.0, November 4th, 2005 */
/* */
/* */
/********************************************************************/

#include
#include

/* Function Prototypes */

void init();
void Send_Byte(unsigned char out);
unsigned char Get_Byte();
void Poll_SO();
void CE_High();
void CE_Low();
void Hold_Low();
void Unhold();
void WP_Low();
void UnWP();
unsigned char Read_Status_Register();
void EWSR();
void WRSR(byte);
void WREN();
void WRDI();
void EBSY();
void DBSY();
unsigned char Read_ID(ID_addr);
unsigned long Jedec_ID_Read();
unsigned char Read(unsigned long Dst);
void Read_Cont(unsigned long Dst, unsigned long no_bytes);
unsigned char HighSpeed_Read(unsigned long Dst);
void HighSpeed_Read_Cont(unsigned long Dst, unsigned long no_bytes);
void Byte_Program(unsigned long Dst, unsigned char byte);
void Auto_Add_IncA(unsigned long Dst, unsigned char byte1, unsigned char byte2);
void Auto_Add_IncB(unsigned char byte1, unsigned char byte2);
void Auto_Add_IncA_EBSY(unsigned long Dst, unsigned char byte1, unsigned char byte2);
void Auto_Add_IncB_EBSY(unsigned char byte1, unsigned char byte2);
void Chip_Erase();
void Sector_Erase(unsigned long Dst);
void Block_Erase_32K(unsigned long Dst);
void Block_Erase_64K(unsigned long Dst);
void Wait_Busy();
void Wait_Busy_AAI();
void WREN_Check();
void WREN_AAI_Check();

void Verify(unsigned char byte, unsigned char cor_byte);

unsigned char idata upper_128[128]; /* global array to store read data */
/* to upper RAM area from 80H - FFH */

/************************************************************************/
/* PROCEDURE: init */
/* */
/* This procedure initializes the SCK to low. Must be called prior to */
/* setting up mode 0. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* SCK */
/************************************************************************/
void init()
{
SCK = 0; /* set clock to low initial state */
}

/************************************************************************/
/* PROCEDURE: Send_Byte */
/* */
/* This procedure outputs a byte shifting out 1-bit per clock rising */
/* edge on the the SI pin(LSB 1st). */
/* */
/* Input: */
/* out */
/* */
/* Output: */
/* SI */
/************************************************************************/
void Send_Byte(unsigned char out)
{

unsigned char i = 0;
for (i = 0; i < 8; i++)
{

if ((out & 0x80) == 0x80) /* check if MSB is high */
SI = 1;
else
SI = 0; /* if not, set to low */
SCK = 1; /* toggle clock high */
out = (out << 1); /* shift 1 place for next bit */
SCK = 0; /* toggle clock low */
}
}

/************************************************************************/
/* PROCEDURE: Get_Byte */
/* */
/* This procedure inputs a byte shifting in 1-bit per clock falling */
/* edge on the SO pin(LSB 1st). */
/* */
/* Input: */
/* SO */
/* */
/* Output: */
/* None */
/************************************************************************/
unsigned char Get_Byte()
{
unsigned char i = 0, in = 0, temp = 0;
for (i = 0; i < 8; i++)
{
in = (in << 1); /* shift 1 place to the left or shift in 0 */
temp = SO; /* save input */
SCK = 1; /* toggle clock high */
if (temp == 1) /* check to see if bit is high */
in = in | 0x01; /* if high, make bit high */

SCK = 0; /* toggle clock low */

}
return in;
}

/************************************************************************/
/* PROCEDURE: Poll_SO */
/* */
/* This procedure polls for the SO line during AAI programming */
/* waiting for SO to transition to 1 which will indicate AAI programming*/
/* is completed */
/* */
/* Input: */
/* SO */
/* */
/* Output: */
/* None */
/************************************************************************/
void Poll_SO()
{
unsigned char temp = 0;
CE_Low();
while (temp == 0x00) /* waste time until not busy */
temp = SO;
CE_High();
}

/************************************************************************/
/* PROCEDURE: CE_High */
/* */
/* This procedure set CE = High. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* CE */
/* */
/************************************************************************/
void CE_High()
{
CE = 1; /* set CE high */
}

/************************************************************************/
/* PROCEDURE: CE_Low */
/* */
/* This procedure drives the CE of the device to low. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* CE */
/* */
/************************************************************************/
void CE_Low()
{
CE = 0; /* clear CE low */
}

/************************************************************************/
/* PROCEDURE: Hold() */
/* */
/* This procedure clears the Hold pin to low. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* Hold */
/************************************************************************/
void Hold_Low()
{
Hold = 0; /* clear Hold pin */
}

/************************************************************************/
/* PROCEDURE: Unhold() */
/* */
/* This procedure sets the Hold pin to high. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* Hold */
/************************************************************************/
void Unhold()
{
Hold = 1; /* set Hold pin */
}

/************************************************************************/
/* PROCEDURE: WP() */
/* */
/* This procedure clears the WP pin to low. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* WP */
/************************************************************************/
void WP_Low()
{
WP = 0; /* clear WP pin */
}

/************************************************************************/
/* PROCEDURE: UnWP() */
/* */
/* This procedure sets the WP pin to high. */
/* */
/* Input: */
/* None */
/* */
/* Output: */
/* WP */
/************************************************************************/
void UnWP()
{
WP = 1; /* set WP pin */
}

/************************************************************************/
/* PROCEDURE: Read_Status_Register */
/* */
/* This procedure read the status register and returns the byte. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* byte */
/************************************************************************/
unsigned char Read_Status_Register()
{
unsigned char byte = 0;
CE_Low(); /* enable device */
Send_Byte(0x05); /* send RDSR command */
byte = Get_Byte(); /* receive byte */
CE_High(); /* disable device */
return byte;
}

/************************************************************************/
/* PROCEDURE: EWSR */
/* */
/* This procedure Enables Write Status Register. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void EWSR()
{
CE_Low(); /* enable device */
Send_Byte(0x50); /* enable writing to the status register */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: WRSR */
/* */
/* This procedure writes a byte to the Status Register. */
/* */
/* Input: */
/* byte */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WRSR(byte)
{
CE_Low(); /* enable device */
Send_Byte(0x01); /* select write to status register */
Send_Byte(byte); /* data that will change the status of BPx
or BPL (only bits 2,3,4,5,7 can be written) */
CE_High(); /* disable the device */
}

/************************************************************************/
/* PROCEDURE: WREN */
/* */
/* This procedure enables the Write Enable Latch. It can also be used */
/* to Enables Write Status Register. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WREN()
{
CE_Low(); /* enable device */
Send_Byte(0x06); /* send WREN command */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: WRDI */
/* */
/* This procedure disables the Write Enable Latch. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WRDI()
{
CE_Low(); /* enable device */
Send_Byte(0x04); /* send WRDI command */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: EBSY */
/* */
/* This procedure enable SO to output RY/BY# status during AAI */
/* programming. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void EBSY()
{
CE_Low(); /* enable device */
Send_Byte(0x70); /* send EBSY command */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: DBSY */
/* */
/* This procedure disable SO as output RY/BY# status signal during AAI */
/* programming. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void DBSY()
{
CE_Low(); /* enable device */
Send_Byte(0x80); /* send DBSY command */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Read_ID */
/* */
/* This procedure Reads the manufacturer's ID and device ID. It will */
/* use 90h or ABh as the command to read the ID (90h in this sample). */
/* It is up to the user to give the last byte ID_addr to determine */
/* whether the device outputs manufacturer's ID first, or device ID */
/* first. Please see the product datasheet for details. Returns ID in */
/* variable byte. */
/* */
/* Input: */
/* ID_addr */
/* */
/* Returns: */
/* byte: ID1(Manufacture's ID = BFh or Device ID = 8Eh) */
/* */
/************************************************************************/
unsigned char Read_ID(ID_addr)
{
unsigned char byte;
CE_Low(); /* enable device */
Send_Byte(0x90); /* send read ID command (90h or ABh) */
Send_Byte(0x00); /* send address */
Send_Byte(0x00); /* send address */
Send_Byte(ID_addr); /* send address - either 00H or 01H */
byte = Get_Byte(); /* receive byte */
CE_High(); /* disable device */
return byte;
}

/************************************************************************/
/* PROCEDURE: Jedec_ID_Read */
/* */
/* This procedure Reads the manufacturer's ID (BFh), memory type (25h) */
/* and device ID (8Eh). It will use 9Fh as the JEDEC ID command. */
/* Please see the product datasheet for details. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* IDs_Read:ID1(Manufacture's ID = BFh, Memory Type (25h), */
/* and Device ID (8Eh) */
/* */
/************************************************************************/
unsigned long Jedec_ID_Read()
{
unsigned long temp;

temp = 0;

CE_Low(); /* enable device */
Send_Byte(0x9F); /* send JEDEC ID command (9Fh) */
temp = (temp | Get_Byte()) << 8; /* receive byte */
temp = (temp | Get_Byte()) << 8;
temp = (temp | Get_Byte()); /* temp value = 0xBF258E */
CE_High(); /* disable device */

return temp;
}

/************************************************************************/
/* PROCEDURE: Read */
/* */
/* This procedure reads one address of the device. It will return the */
/* byte read in variable byte. */
/* */
/* */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* */
/* Returns: */
/* byte */
/* */
/************************************************************************/
unsigned char Read(unsigned long Dst)
{
unsigned char byte = 0;

CE_Low(); /* enable device */
Send_Byte(0x03); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
byte = Get_Byte();
CE_High(); /* disable device */
return byte; /* return one byte read */
}

/************************************************************************/
/* PROCEDURE: Read_Cont */
/* */
/* This procedure reads multiple addresses of the device and stores */
/* data into 128 byte buffer. Maximum byte that can be read is 128 bytes*/
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* no_bytes Number of bytes to read (max = 128) */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Read_Cont(unsigned long Dst, unsigned long no_bytes)
{
unsigned long i = 0;
CE_Low(); /* enable device */
Send_Byte(0x03); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
for (i = 0; i < no_bytes; i++) /* read until no_bytes is reached */
{
upper_128[i] = Get_Byte(); /* receive byte and store at address 80H - FFH */
}
CE_High(); /* disable device */

}

/************************************************************************/
/* PROCEDURE: HighSpeed_Read */
/* */
/* This procedure reads one address of the device. It will return the */
/* byte read in variable byte. */
/* */
/* */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* */
/* Returns: */
/* byte */
/* */
/************************************************************************/
unsigned char HighSpeed_Read(unsigned long Dst)
{
unsigned char byte = 0;

CE_Low(); /* enable device */
Send_Byte(0x0B); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(0xFF); /*dummy byte*/
byte = Get_Byte();
CE_High(); /* disable device */
return byte; /* return one byte read */
}

/************************************************************************/
/* PROCEDURE: HighSpeed_Read_Cont */
/* */
/* This procedure reads multiple addresses of the device and stores */
/* data into 128 byte buffer. Maximum byte that can be read is 128 bytes*/
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* no_bytes Number of bytes to read (max = 128) */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void HighSpeed_Read_Cont(unsigned long Dst, unsigned long no_bytes)
{
unsigned long i = 0;
CE_Low(); /* enable device */
Send_Byte(0x0B); /* read command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(0xFF); /*dummy byte*/
for (i = 0; i < no_bytes; i++) /* read until no_bytes is reached */
{
upper_128[i] = Get_Byte(); /* receive byte and store at address 80H - FFH */
}
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Byte_Program */
/* */
/* This procedure programs one address of the device. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* byte: byte to be programmed */
/* */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Byte_Program(unsigned long Dst, unsigned char byte)
{
CE_Low(); /* enable device */
Send_Byte(0x02); /* send Byte Program command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(byte); /* send byte to be programmed */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Auto_Add_IncA */
/* */
/* This procedure programs consecutive addresses of 2 bytes of data into*/
/* the device: 1st data byte will be programmed into the initial */
/* address [A23-A1] and with A0 = 0. The 2nd data byte will be be */
/* programmed into initial address [A23-A1] and with A0 = 1. This */
/* is used to to start the AAI process. It should be followed by */
/* Auto_Add_IncB. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* */
/* Note: Only RDSR command can be executed once in AAI mode with SO */
/* disable to output RY/BY# status. Use WRDI to exit AAI mode */
/* unless AAI is programming the last address or last address of */
/* unprotected block, which automatically exits AAI mode. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* byte1: 1st byte to be programmed */
/* byte1: 2nd byte to be programmed */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncA(unsigned long Dst, unsigned char byte1, unsigned char byte2)
{
CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Auto_Add_IncB */
/* */
/* This procedure programs consecutive addresses of 2 bytes of data into*/
/* the device: 1st data byte will be programmed into the initial */
/* address [A23-A1] and with A0 = 0. The 2nd data byte will be be */
/* programmed into initial address [A23-A1] and with A0 = 1. This */
/* is used after Auto_Address_IncA. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* Note: Only WRDI and AAI command can be executed once in AAI mode */
/* with SO enabled as RY/BY# status. When the device is busy */
/* asserting CE# will output the status of RY/BY# on SO. Use WRDI */
/* to exit AAI mode unless AAI is programming the last address or */
/* last address of unprotected block, which automatically exits */
/* AAI mode. */
/* */
/* Input: */
/* */
/* byte1: 1st byte to be programmed */
/* byte2: 2nd byte to be programmed */
/* */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncB(unsigned char byte1, unsigned char byte2)
{
CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Auto_Add_IncA_EBSY */
/* */
/* This procedure is the same as procedure Auto_Add_IncA except that it */
/* uses EBSY and Poll_SO functions to check for RY/BY. It programs */
/* consecutive addresses of the device. The 1st data byte will be */
/* programmed into the initial address [A23-A1] and with A0 = 0. The */
/* 2nd data byte will be programmed into initial address [A23-A1] and */
/* with A0 = 1. This is used to to start the AAI process. It should */
/* be followed by Auto_Add_IncB_EBSY. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* */
/* Note: Only WRDI and AAI command can be executed once in AAI mode */
/* with SO enabled as RY/BY# status. When the device is busy */
/* asserting CE# will output the status of RY/BY# on SO. Use WRDI */
/* to exit AAI mode unless AAI is programming the last address or */
/* last address of unprotected block, which automatically exits */
/* AAI mode. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* byte1: 1st byte to be programmed */
/* byte1: 2nd byte to be programmed */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncA_EBSY(unsigned long Dst, unsigned char byte1, unsigned char byte2)
{
EBSY(); /* enable RY/BY# status for SO in AAI */

CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */

Poll_SO(); /* polls RY/BY# using SO line */

}

/************************************************************************/
/* PROCEDURE: Auto_Add_IncB_EBSY */
/* */
/* This procedure is the same as Auto_Add_IncB except that it uses */
/* Poll_SO to poll for RY/BY#. It demonstrate on how to use DBSY after */
/* AAI programmming is completed. It programs consecutive addresses of */
/* the device. The 1st data byte will be programmed into the initial */
/* address [A23-A1] and with A0 = 0. The 2nd data byte will be */
/* programmed into initial address [A23-A1] and with A0 = 1. This is */
/* used after Auto_Address_IncA. */
/* Assumption: Address being programmed is already erased and is NOT */
/* block protected. */
/* */
/* Note: Only WRDI and AAI command can be executed once in AAI mode */
/* with SO enabled as RY/BY# status. When the device is busy, */
/* asserting CE# will output the status of RY/BY# on SO. Use WRDI */
/* to exit AAI mode unless AAI is programming the last address or */
/* last address of unprotected block, which automatically exits */
/* AAI mode. */
/* */
/* Input: */
/* */
/* byte1: 1st byte to be programmed */
/* byte2: 2nd byte to be programmed */
/* */
/* */
/* Returns: */
/* Nothing */
/* */
/************************************************************************/
void Auto_Add_IncB_EBSY(unsigned char byte1, unsigned char byte2)
{
CE_Low(); /* enable device */
Send_Byte(0xAD); /* send AAI command */
Send_Byte(byte1); /* send 1st byte to be programmed */
Send_Byte(byte2); /* send 2nd byte to be programmed */
CE_High(); /* disable device */

Poll_SO(); /* polls RY/BY# using SO line */

WRDI(); /* Exit AAI before executing DBSY */
DBSY(); /* disable SO as RY/BY# output if in AAI */
}

/************************************************************************/
/* PROCEDURE: Chip_Erase */
/* */
/* This procedure erases the entire Chip. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Chip_Erase()
{
CE_Low(); /* enable device */
Send_Byte(0x60); /* send Chip Erase command (60h or C7h) */
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Sector_Erase */
/* */
/* This procedure Sector Erases the Chip. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Sector_Erase(unsigned long Dst)
{


CE_Low(); /* enable device */
Send_Byte(0x20); /* send Sector Erase command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Block_Erase_32K */
/* */
/* This procedure Block Erases 32 KByte of the Chip. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Block_Erase_32K(unsigned long Dst)
{
CE_Low(); /* enable device */
Send_Byte(0x52); /* send 32 KByte Block Erase command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Block_Erase_64K */
/* */
/* This procedure Block Erases 64 KByte of the Chip. */
/* */
/* Input: */
/* Dst: Destination Address 000000H - 0FFFFFH */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Block_Erase_64K(unsigned long Dst)
{
CE_Low(); /* enable device */
Send_Byte(0xD8); /* send 64KByte Block Erase command */
Send_Byte(((Dst & 0xFFFFFF) >> 16)); /* send 3 address bytes */
Send_Byte(((Dst & 0xFFFF) >> 8));
Send_Byte(Dst & 0xFF);
CE_High(); /* disable device */
}

/************************************************************************/
/* PROCEDURE: Wait_Busy */
/* */
/* This procedure waits until device is no longer busy (can be used by */
/* Byte-Program, Sector-Erase, Block-Erase, Chip-Erase). */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Wait_Busy()
{
while (Read_Status_Register() == 0x03) /* waste time until not busy */
Read_Status_Register();
}

/************************************************************************/
/* PROCEDURE: Wait_Busy_AAI */
/* */
/* This procedure waits until device is no longer busy for AAI mode. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Wait_Busy_AAI()
{
while (Read_Status_Register() == 0x43) /* waste time until not busy */
Read_Status_Register();
}

/************************************************************************/
/* PROCEDURE: WREN_Check */
/* */
/* This procedure checks to see if WEL bit set before program/erase. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WREN_Check()
{
unsigned char byte;
byte = Read_Status_Register(); /* read the status register */
if (byte != 0x02) /* verify that WEL bit is set */
{
while(1)
/* add source code or statements for this file */
/* to compile */
/* i.e. option: insert a display to view error on LED? */

}
}

/************************************************************************/
/* PROCEDURE: WREN_AAI_Check */
/* */
/* This procedure checks for AAI and WEL bit once in AAI mode. */
/* */
/* Input: */
/* None */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void WREN_AAI_Check()
{
unsigned char byte;
byte = Read_Status_Register(); /* read the status register */
if (byte != 0x42) /* verify that AAI and WEL bit is set */
{
while(1)
/* add source code or statements for this file */
/* to compile */
/* i.e. option: insert a display to view error on LED? */

}
}

/************************************************************************/
/* PROCEDURE: Verify */
/* */
/* This procedure checks to see if the correct byte has be read. */
/* */
/* Input: */
/* byte: byte read */
/* cor_byte: correct_byte that should be read */
/* */
/* Returns: */
/* Nothing */
/************************************************************************/
void Verify(unsigned char byte, unsigned char cor_byte)
{
if (byte != cor_byte)
{
while(1)
/* add source code or statement for this file */
/* to compile */
/* i.e. option: insert a display to view error on LED? */

}
}


int main()
{

return 0;
}

而範例程式中已經把主要的控制方式的"概念"都已經列出來了!
所以只要讀一下Datasheet應該就可以了解他的意義!

至於main()裡面要做甚麼就因人而異,因此千萬不要問我 main()要怎麼寫!

Reference
http://www.sst.com

點Software Driver 旁邊的TXT就可以看到範例程式

星期二, 7月 22, 2008

CRB V.S ERB

公板,大家都這樣叫,CRB (Customer Reference Board) ,這是入行的時候一直聽到的名詞。

記得當入行的時候很多人都跟我說I晶片公司會出ㄧ個CRB 板子,然後我們也會有個CRB BIOS,剛開始的時候搞不清楚那是什麼,後來才慢慢的有些概念。

查詢了相關文獻中指出,以前晶片組廠商各家爭鳴,但是相容性卻是個最大的問題,後來就有些廠商乾脆就自己做塊板子然後把自己的晶片組放上去,順便跟客戶展示一下Performance ,這塊板子就是所謂的CRB,用來給客戶參考用的板子。

隨著時間的演變,系統廠便直接參考CRB的設計去設計出不同的系統出來,也就是我們現在在做的事情,這樣的好處是不用擔心太多相容性的問題,而且可以快速開發出機種。

有些系統廠可能直接拿CRB板子,上面可能就多加個USB 接口就是一個機種,然後就可以拿去賣了,當然也有些系統廠特別針對某些晶片功能去設計一些特別的Features,當然售價也就不同於直接拿CRB修改的機種。

ERB, Evaluation Reference Board 當某個新的晶片組在研發過程中,總是會需要有模擬的板子來測試,因此這類型的板子會在現成的Platform 基礎上,去配置出新的晶片組的線路,並且讓BIOS廠商開始Study ㄧ些相關問題(Bring up next BIOS code),由於他是模擬的環境,所以往往Bring up出來的BIOS code跟實際上新的晶片組的CRB BIOS code還是會有些差距。

實際上我並沒有參與過CRB/ERB開發過程,畢竟我是系統端的BIOS, 因此我不能確定我所述一定正確,如有誤的地方請大家不吝指正。
  

星期一, 7月 21, 2008

Verb Table v.s S3 resume

前幾天在英業達的網友小偉用msn問了我一個問題,有關於Verb Table 在S3回來後不正確的問題.
他人還在大陸打拼中,目前情況不明,也不知道能不能回的了台灣........在此希望他能順利解決問題,早點回家吧!

Verb Table , 一般我們在設定的時候就是拿著Data Sheet然後設定相關的設定值進去BIOS code或是偷懶點請教廠商設定值是什麼然後加入進去,而BIOS會自己透過相關介面寫入Audio device.

在bios的觀點中,我們進入S3 前我們會去存PCI Regs 以確保HDA 相關暫存器有回填正確,當 S3 Resume 後一般我們會去回填PCI Reg 但是不會去回填Verb Table , 頂多就是拿工具去看S3 resume後Verb table是否一樣(一般都一樣),所以進入S3的時候並不會把Verb Table儲存到RAM中. 以上是我原本接觸的這部分設定時候的認知........但是經過小偉一問,我才發現原來我錯了 >.<

目前查詢到的資料如下:

Windows XP 之前的作業系統 - S3 Resume 時 , BIOS 需要自己手動回填Verb Table ,因為OS不會幫你回填.

Vista - 作業系統"理論上應該會/看似"會幫你回填 ,不過我沒找到M$有相關的說明,只有在某"紅皮"的書裡面有提到(也有可能不會=.=), 因此我們BIOS端就不需要再去填 (因為我都是接觸到這種會自己填的OS , 所以讓我以為BIOS 不用再填 一次, 由此可知 bios的知識還真的不能以偏蓋全,而且多接觸不同種類的平台才能累積更多經驗 >.<)

由於我接觸的還是某大公司的晶片組 , 而情況大概就是這樣 , 在某本書上提到的資訊是屬於保密部分,所以我也不能說太清楚,請自行查閱有關這部分的說明. 至於其他家的晶片組請自行測試.

另外BIOS如果要回填Verb Table , 做法大同小異 , 就是註冊SMI Routine , 在S3 Resume的點去跑你的Routine , 然後自己在回填一次Verb Table就可以了!

至於註冊方式, 依照各家bios做法不同,所以請自行參考BIOS廠商的範例!

星期二, 10月 16, 2007

[我所知道的BIOS]->[Remaining POST Tasks] 11

除了之前所提的 tasks外,還有下列 main tasks是 BIOS POST會執行的:

[USB init]
=> initialize USB的部份.這方面的code幾乎是 kernel code,再加上少許的 chipset code(因為,chipset's USB controller是哪一種需要 customize, Ex. OHCI or UHCI...etc).

主要在 implement USB spec的部份(USB 1.1/2.0 and USB legacy). (天書也...沒看過...)

[KB init]
=> init KBC的部份

[HDD init]
=> 這是 locate IPL(Initial Program Load)的code.因為最終系統需要 load OS,而OS是存在 storage device中,因此需要讓storage....動起來 !

主要的工作有:
- 設定 chipset端的 storage controller(PATA or SATA)'s settings
- identify HDD
- config HDD by set-feature(<-設定 device端的 settings)

這樣一來,controller端與 device端有了 "相同的認知" 後,就可以 access HDD了 !

[ACPI]
=> 主要是將所有的 ACPI tables建至 memory中;讓ACPI OS可以 parse & config.

[Boot-to-OS]
=> 最後 BIOS's 工作是: invoke int19h(for Boot-strap) !此中斷服務程式會嘗試去找 boot device,並從中(storage)將 boot-loader 載入至 memory中;然後跳到 boot loader處,開始執行載入OS的工作 !


* 一但進入OS後,與BIOS會有關的....幾乎只剩 ACPI 了 !

BIOS不是雞肋 ^_^

[我所知道的BIOS]->[VGA init] 10

一般而言,BIOS會在POST時 locate 3 devices:
- Input device(Ex. Keyboard)
- Output device(Ex. Display device)
- IPL(Initial Program Load, Ex. HDD)

這次要提到的是 Display device,即 VGA !

在PCI_SCAN之後,BIOS會在記憶體中建立一個data structure,代表整個系統的 PCI architecture.
Ex. Ponter-> NB->P2P->SB->IDE->AUDIO->LAN->USB 2.0->USB 1.1->...->VGA->...->End

在VGA_init的階段,BIOS會去 go-through this list,一個個的問:"有沒有人需要shadow Option ROM的 ?"

-------------------------------
*1 在此,先break,並說明一些觀念:
1. Option ROM是 for H/W的 firmware;像BIOS一樣是 for MB.有可能直接在硬體上 ,or 包在BIOS image中
2. 有Option ROM的 H/W可能有: VGA card,Lan card, RAID card,...etc
3. VGA's Option ROM 也就是 VBIOS ! 專門處理 screen I/O operation(主要是int10h)
4. VGA "shadow" 即代表: 將 VBIOS copy 到 shadow RAM, Ex. C0000h~C7FFFh處(32K)
5. VGA init這個階段只 consider "VGA device" ! for 其他 device,之後再考慮其 shadow的事宜
-------------------------------

(承接前面的 flow):此時,VGA device會舉手說:"我要" !此時,BIOS會去尋找VGA device's Option ROM(即VBIOS)在哪裡;此時,VBIOS有可能在card上 or "當初" 被包在 BIOS image中(*2)

一但找到,則會先 作一些 checks:Ex.
- Option ROM signature is 0xAA55 ?
- 比較 Option ROM內的 Vendor ID/Device ID = H/W's IDs ?
- class code and sub-class code correct ?
- length = 0 ?
...etc...

若都符合,則視它為 VGA Option ROM(VBIOS) ! 之後,利用 memory2memory copy將之 copy到 shadow memory,從 C0000h處開始存放...

複製完後,再 check "checksum"是否正確;if yes then jump to "entry of initialization code",控制權自此轉移至 VGA Option ROM,由它去做 initialize VGA的工作 ! ( 若是CRT螢幕,user會聽到ㄉ一ㄤ的一聲 ! 即代表 initialize VGA成功 !!! )

<- 此為 VGA_init的工作 !!!

*2 說"當初"的原因是: VGA BIOS若包在BIOS image中,在 BIOS shadow時,也會被一併 copy到記憶體的某處放著;當然,會記住存放處 !

[Note] 一般遇到 VGA init fail的issue時,可以先 check:是否 VGA BIOS已被 copy 至 C0000h處;若有,則check是否已經 jump to VBIOS or NOT;若否,則可以往前 check是否前面所列的一些 "關卡"沒過 (Ex. ID不 match, or checksum 不相等...etc )

VGA 若 ok,電腦就是彩色的 ^_^

---------------------------
- 相關討論 -----------------
---------------------------


通常都是板子一來就會去開始Debug VGA...
VBIOS 若壞,螢幕是黑ㄟ
VBIOS若好,螢幕是彩色ㄟ
沒螢幕的情況下要繼續Porting BIOS就比較麻煩一點

[Q]Option ROM是 for H/W的 firmware;像BIOS一樣是 for MB.有可能直接在硬體上 ,or 包在BIOS image中。前者我叫它SW ROM,後者叫legacy ROM,您已經提到sw rom的load方式,那麽legacy rom load方式是否應該有所不同呢?一但找到OpROM,則BIOS 會先作一些 checks:
Ex.
- Option ROM signature is 0xAA55 ?
- 比較 Option ROM內的 Vendor ID/Device ID = H/W's IDs ?
- class code and sub-class code correct ?
- length = 0 ?
...etc...

兩种rom都是通過這種方式嗎?

Ans: 我所說的都是 rough flow,而這兩種ROM的"處理方式"不同,但"檢查的機制"大同小異...建議去trace BIOS code比較清楚

[補充1]
1.可以查看PCI ROM Spec... 裡面有詳細說明如何Load OpROM 的方式,而檢查項目就各家BIOS不同...

2.可以用HEX編輯器直接開啟ROM File,例如VBIOS.bin or OpROM.dat ...etc 來查看內容(Binary file),例如某VBIOS.DAT 的內容如下:

00000 55 AA 80 E9 4B ....
00010 30 30 00 22 E9 19 21 5F 40 00
.......................................
00040 50 43 49 52 86 80 42 2A ..............

其中:
a)55AA是這個ROM的Signature <--代表他是符合規範的ROM
b)80 這個ROM的Code size <--需查閱Spec確定一下
c) 接著是EntryPoint Address <--實際上會執行的程式碼進入點的位址,所以一般都是講
Jmp OpRomBaseAddr+3 <-- 你如果trace BIOS 程式碼,這就是 +3 的由來
d) 000018h=40 代表另一個PCI Header在Offset 00040h的地方
所以 50 43 49 52 是Signature,如果用ACSII 來看就是"PCIR"
其他更多資訊可以查看PCI ROM Spec說明.....

e) "PCIR"後面緊跟著這個OpRom的VID與DID ...即8086 2A42 <--Intel=8086

3.如果想要改OpRom裡面的Code,可以使用反組譯工具去修改或是用Debug去修改
如果比較簡單的OpROM要做實驗的話我都用Debug.com 把OpROM 載入到Mem,接著利用T /P 指令單步執行去追蹤與修改,修改好之後再查看機器碼,再利用Hex編輯器 or 反組譯工具寫回去OpROM (找Bug時可以嘗試這樣寫啦,不過違反智慧財產權,最好還是叫Vendor幫你改,而且光看懂OpROm的流程就需要一點時間了 ^^!)

如果要用組合語言寫一個Dummy OpRom的做法就像下面範例去模擬一個OpROM...
至於你BIOS端可不可以run 就要看你的檢查機制嚴謹程度或是你自己修改你的BIOS code來達到模擬的目的 :
.586p
.code
YourCodeStart:
ORG 0
db 55h, 0AAh
TotalCodeSize db (offset YourCodeEnd) - (offset YourCodeStart)
ORG 3
jmp entrypoint

entrypoint:
........

YourCodeEnd:
END

組譯完之後可以利用微軟工具EXE2BIN.EXE 把他轉成xxx.bin (binary file)然後你就可以包進去BIOS測試。

[補充2]
當VGA init時,那時VGA BIOS的放置處可能有:
case 1: 在 memory中(當初在 shadow stage時被 copy 到 memory)
case 2: 在 card上(Ex. 一般的 external VGA card上都有一顆小rom)

因此,這兩種case的處理方式便不同.
Ex. In case 2 若VGA card在 bridge後面,則還需要 config 該 bridge's resource window使Option(in card)可以被正確的 accessed...<- 所以處理方式有所不同 !

至於檢查機制;因為Option ROM不管放哪裡,其 content都是一樣 ! 因此檢查機制大同小異...還有,不同家BIOS的 "checks" 也未必完全相同 !!!