RAS--APEI 报错解析流程(2)

7 篇文章 0 订阅

RAS--APEI 报错解析流程(1)

除了APEI 中除了GHES会记录错误,在Post过程中的错误通常是通过BERT Table汇报

 

1.BERT

Boot Error Record Table is used to report unhandled errors that occurred in a previous boot,it is reported as a ‘one-time polled’type error source.

Bert 用于记录post 过程中产生的 error 以及UCE hang 重启 BIOS 错误状态未进行清除在下次重启扫描出的error

具体结构如图所示:

使用BERT 的header  通过section type 区分错误类型 对应到不同的错误结构 都是通过block error status addrss 链接

内存 pcie cpu的错误汇报信息结构体

 

 

使用IASL 解析BERT table:

BIOS 在Post 过程中去扫描pcie error 内存 error  CPU error

NBIOErrorDetection 检测到错误 addbert ->GENERIC_PCIE_AER_ERR_ENTRY

MCAErrorDetection 检测到MCA Bank UMC 错误  addbert ->GENERIC_MEM_ERR_ENTRY

MCAErrorDetection 检测到MCA Bank PIE  错误  addbert ->GENERIC_PRO_ERR_ENTRY

CPU BERT OS 解析

内存OS 解析

PCIE OS 解析

 

Post过程中检测到多个BERT :有内存和CPU bank 的错误状态

BIOS 日志:两个MCA Bank 读取到错误MCA_Status

 

BERT Table: BIOS 汇报和OS 解析通过Boot Error Region Address 联系

 

Boot Error Region Address 对应到结构体

///

/// Generic Error Status Definition

///

typedef struct {

  EFI_ACPI_6_2_ERROR_BLOCK_STATUS    BlockStatus;

  UINT32                             RawDataOffset;

  UINT32                             RawDataLength;

  UINT32                             DataLength;

  UINT32                             ErrorSeverity;

} EFI_ACPI_6_2_GENERIC_ERROR_STATUS_STRUCTURE;

 

对于OS去打印HardWare error 只需要参考GHES 中的Error Block status 就会去打印 错误的GHES Table中的错误信息

typedef struct {

  UINT32    UncorrectableErrorValid     : 1;

  UINT32    CorrectableErrorValid       : 1;

  UINT32    MultipleUncorrectableErrors : 1;

  UINT32    MultipleCorrectableErrors   : 1;

  UINT32    ErrorDataEntryCount         : 10;

  UINT32    Reserved                    : 18;

} EFI_ACPI_6_2_ERROR_BLOCK_STATUS;

也就是当扫描到BlockStatus 存在错误状态 OS就会上报Hardware error  然后清除错误状态

后面接着结构体,后面的结构体会根据SectionType 接着内存/CPU/PCIE 的结构体

typedef struct {

  UINT8     SectionType[16];

  UINT32    ErrorSeverity;

  UINT16    Revision;

  UINT8     ValidationBits;

  UINT8     Flags;

  UINT32    ErrorDataLength;

  UINT8     FruId[16];

  UINT8     FruText[20];

  UINT8     Timestamp[8];

} EFI_ACPI_6_2_GENERIC_ERROR_DATA_ENTRY_STRUCTURE;

 

/*

 * Section type definitions, used in section_type field in struct

 * cper_section_descriptor

 *

 * Processor Generic

 */

#define CPER_SEC_PROC_GENERIC                       \

    GUID_INIT(0x9876CCAD, 0x47B4, 0x4bdb, 0xB6, 0x5E, 0x16, 0xF1,   \

          0x93, 0xC4, 0xF3, 0xDB)

/* Processor Specific: X86/X86_64 */

#define CPER_SEC_PROC_IA                        \

    GUID_INIT(0xDC3EA0B0, 0xA144, 0x4797, 0xB9, 0x5B, 0x53, 0xFA,   \

          0x24, 0x2B, 0x6E, 0x1D)

/* Processor Specific: IA64 */

#define CPER_SEC_PROC_IPF                       \

    GUID_INIT(0xE429FAF1, 0x3CB7, 0x11D4, 0x0B, 0xCA, 0x07, 0x00,   \

          0x80, 0xC7, 0x3C, 0x88, 0x81)

/* Processor Specific: ARM */

#define CPER_SEC_PROC_ARM                       \

    GUID_INIT(0xE19E3D16, 0xBC11, 0x11E4, 0x9C, 0xAA, 0xC2, 0x05,   \

          0x1D, 0x5D, 0x46, 0xB0)

/* Platform Memory */

#define CPER_SEC_PLATFORM_MEM                       \

    GUID_INIT(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83,   \

          0xED, 0x7C, 0x83, 0xB1)

#define CPER_SEC_PCIE                           \

    GUID_INIT(0xD995E954, 0xBBC1, 0x430F, 0xAD, 0x91, 0xB4, 0x4D,   \

          0xCB, 0x3C, 0x6F, 0x35)

/* Firmware Error Record Reference */

Section Type=CPER_SEC_PROC_GENERIC 对应到 CPU 的错误结构体

 

 

对于GHES 的错误OS需要使用定时器,BERT 只需要在Kernel 加载时跑一边即可。

OS 下错误解析  ghes.c bert.c  cper.c

GHES 驱动:

static struct platform_driver ghes_platform_driver = {

    .driver     = {

        .name   = "GHES",

    },

    .probe      = ghes_probe,

    .remove     = ghes_remove,

};

ghes_init 加载GHES的驱动 ,系统下的解析策略和Notify 的结构体相关联,BIOS中会设置Notify Type ,Pollinterval

系统下扫描GHES 的驱动 是通过定时器周期性去扫描错误状态,Pollinterval 是定时器的参考时间

 

    switch (generic->notify.type) {

    case ACPI_HEST_NOTIFY_POLLED:

    case ACPI_HEST_NOTIFY_EXTERNAL:

    case ACPI_HEST_NOTIFY_SCI:

    case ACPI_HEST_NOTIFY_GSIV:

    case ACPI_HEST_NOTIFY_GPIO:

        break;

    case ACPI_HEST_NOTIFY_SEA:

        if (!IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {

            pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n",

                generic->header.source_id);

            rc = -ENOTSUPP;

            goto err;

        }

        break;

    case ACPI_HEST_NOTIFY_NMI:

        if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {

            pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",

                generic->header.source_id);

            goto err;

        }

        break;

    case ACPI_HEST_NOTIFY_LOCAL:

        pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",

               generic->header.source_id);

        goto err;

 

 

timer_setup(&ghes->timer, ghes_poll_func, TIMER_DEFERRABLE);

ghes_proc(ghes);

    ghes_read_estatus(ghes, 0);//-->apei_read(&buf_paddr, &g->error_status_address);

    ghes_print_estatus

    cper_estatus_print(pfx_seq, estatus);

 

 

这就对应到Dmesg 中的HardWare error 错误,就可以识别到错误的source id ,既可以大致定位错误信息来源 Source id = 512 对应到PCIE 错误

后续通过Section error type 定位到更加详细的信息

前面的信息都是来自于固定结构体

///

/// Generic Error Data Entry Definition

///

typedef struct {

  UINT8     SectionType[16];

  UINT32    ErrorSeverity;

  UINT16    Revision;

  UINT8     ValidationBits;

  UINT8     Flags;

  UINT32    ErrorDataLength;

  UINT8     FruId[16];

  UINT8     FruText[20];

  UINT8     Timestamp[8];

} EFI_ACPI_6_2_GENERIC_ERROR_DATA_ENTRY_STRUCTURE;

static void

cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,

               int sec_no)

{

    guid_t *sec_type = (guid_t *)gdata->section_type;

    __u16 severity;

    char newpfx[64];

    if (acpi_hest_get_version(gdata) >= 3)

        cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);

    severity = gdata->error_severity;

    printk("%s""Error %d, type: %s\n", pfx, sec_no,

           cper_severity_str(severity));

    if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)

        printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);

    if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)

        printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);

}

 

对于后续的结构体包括内存PCIE CPU 有着不同的结构体主要包括三个函数打印错误信息,通过匹配Section type Guid 判断

  cper_print_proc_generic(); cper_print_mem(); cper_print_pcie()

if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {

        struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);

        printk("%s""section_type: general processor error\n", newpfx);

        if (gdata->error_data_length >= sizeof(*proc_err))

            cper_print_proc_generic(newpfx, proc_err);

        else

            goto err_section_too_small;

    } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {

        struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);

        printk("%s""section_type: memory error\n", newpfx);

        if (gdata->error_data_length >=

            sizeof(struct cper_sec_mem_err_old))

            cper_print_mem(newpfx, mem_err,

                       gdata->error_data_length);

        else

            goto err_section_too_small;

    } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {

        struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);

        printk("%s""section_type: PCIe error\n", newpfx);

        if (gdata->error_data_length >= sizeof(*pcie))

            cper_print_pcie(newpfx, pcie, gdata);

        else

            goto err_section_too_small;

#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)

    } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {

        struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);

        printk("%ssection_type: ARM processor error\n", newpfx);

        if (gdata->error_data_length >= sizeof(*arm_err))

            cper_print_proc_arm(newpfx, arm_err);

        else

            goto err_section_too_small;

 

CPU错误信息结构体:

typedef struct _PLATFORM_PROC_ERR_SEC {

  PROC_ERR_VALID_BIT    ValidBits;              ///< Validation Bits

  UINT64                LocalApicID;            ///< Processor APIC ID

  UINT64                CpuIdInfo_EAX;          ///< CPUID Information output value from EAX

  UINT64                CpuIdInfo_EBX;          ///< CPUID Information output value from EBX

  UINT64                CpuIdInfo_ECX;          ///< CPUID Information output value from ECX

  UINT64                CpuIdInfo_EDX;          ///< CPUID Information output value from EDX

  UINT64                CpuIdInfo_PD1;          ///< CPUID Information Padding 1

  UINT64                CpuIdInfo_PD2;          ///< CPUID Information Padding 2

} PLATFORM_PROC_ERR_SEC;

内存错误信息结构体:

typedef struct _PLATFORM_MEM_ERR_SEC {

  MEM_ERR_VALID_BIT    ValidBits;   ///< Valid bits Bitmp

  UINT64               ErrStatus;   ///< Error Status

  UINT64               PhyAddr;     ///< Physical memory address of detected error

  UINT64               PhyAddrMask; ///< Physical Error Address mask

  UINT16               Node;        ///< Node Number

  UINT16               Card;        ///< Card Number

  UINT16               Module;      ///< Module Number

  UINT16               Bank;        ///< Bank Number

  UINT16               Device;      ///< Device Number

  UINT16               Row;         ///< Row Number

  UINT16               Column;      ///< Column Number

  UINT16               BitPosition; ///< Bit Position

  UINT64               RequestorID; ///< Requestor ID

  UINT64               ResponderID; ///< Responder ID

  UINT64               TargetID;    ///< Target ID

  UINT8                MemErrType;  ///< Memory Error Type

  UINT8                Extend;      ///< Extened

  UINT16               RankNumber;  ///< Rank Number

  UINT16               CardHandle;  ///< Card Number

  UINT16               ModuleHandle;///< Module Number

} PLATFORM_MEM_ERR_SEC;

 

PCIE 错误信息结构体:

///

/// PCIE Error Section

///

typedef struct {

  PCIE_ERR_VALID_BIT    Validation;                                  ///< Validation Bits

  UINT32                PortType;                                    ///< Port Type

  UINT32                Revision;                                    ///< Revision

  UINT32                CommandStatus;                               ///< Command Status

  UINT32                Reserved;                                    ///< Reserved

  DEVICE_ID             DeviceId;                                    ///< Device Id

  UINT8                 SerialNum[8];                                ///< Serial Num

  UINT32                BridgeCtrlStatus;                            ///< Bridge Control Status

  CAP_STRUCTURE         CapabilityStructure;                         ///< Capability Structure

  AER_INFO              AerInfo;                                     ///< AER Info

} PCIE_ERROR_SECTION;

 

对于BERT 错误不需要使用定时器在Kernel 加载的时候会去初始化一遍BERT

BERT   \drivers\acpi\apei\bert.c

bert_init  -->

pr_info_once("Error records from previous boot:\n");

bert_print_all(boot_error_region, region_len);

cper_estatus_print(KERN_INFO HW_ERR, estatus);

错误解析和HEST GHES 类似

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RAS-3072(也称为RSA-3072)是一种非对称加密算法,用于加密和解密数据。以下是使用 C++ 实现 RAS-3072 加密和解密的基本步骤: 1. 生成公钥和私钥 首先,需要生成一个公钥和一个私钥对。公钥用于加密数据,私钥用于解密数据。生成公钥和私钥的步骤如下: - 选择两个大素数 p 和 q,使得它们的积 N = p * q 非常大(通常在几千位以上)。 - 计算欧拉函数 φ(N) = (p-1) * (q-1)。 - 选择一个小于 φ(N) 且与 φ(N) 互质的整数 e,它将作为公钥的一部分。 - 计算 e 的模反元素 d,它将作为私钥的一部分。d 满足以下条件:d * e ≡ 1 (mod φ(N))。 2. 加密数据 一旦公钥和私钥被生成,就可以使用公钥来加密数据。加密的步骤如下: - 将要加密的数据转换为一个整数 m,该整数应小于 N。 - 计算 c ≡ m^e (mod N),其中 e 是公钥中的指数。得到的 c 是加密后的数据。 3. 解密数据 一旦加密的数据需要被解密,就可以使用私钥来解密数据。解密的步骤如下: - 将加密后的数据 c 转换为一个整数。 - 计算 m ≡ c^d (mod N),其中 d 是私钥中的指数。得到的 m 是解密后的数据。 下面是使用 C++ 实现 RAS-3072 加密和解密的示例代码: ```cpp #include <iostream> #include <vector> #include <random> #include <chrono> #include <gmpxx.h> using namespace std; // 生成随机大素数 mpz_class generate_prime(int num_bits) { random_device rd; mt19937 gen(rd()); uniform_int_distribution<mpz_class> dist(mpz_class(1) << (num_bits-1), mpz_class(1) << num_bits); while (true) { auto p = dist(gen); if (mpz_probab_prime_p(p.get_mpz_t(), 25) > 0) { return p; } } } // 生成公钥和私钥 void generate_key(mpz_class& N, mpz_class& e, mpz_class& d, int num_bits) { auto p = generate_prime(num_bits); auto q = generate_prime(num_bits); N = p * q; mpz_class phi = (p - 1) * (q - 1); while (true) { e = generate_prime(num_bits); if (gcd(e, phi) == 1) { break; } } mpz_invert(d.get_mpz_t(), e.get_mpz_t(), phi.get_mpz_t()); } // 加密数据 mpz_class encrypt(mpz_class m, mpz_class N, mpz_class e) { mpz_class c; mpz_powm(c.get_mpz_t(), m.get_mpz_t(), e.get_mpz_t(), N.get_mpz_t()); return c; } // 解密数据 mpz_class decrypt(mpz_class c, mpz_class N, mpz_class d) { mpz_class m; mpz_powm(m.get_mpz_t(), c.get_mpz_t(), d.get_mpz_t(), N.get_mpz_t()); return m; } int main() { // 生成公钥和私钥 mpz_class N, e, d; generate_key(N, e, d, 3072); // 要加密的数据 string plaintext = "Hello, world!"; mpz_class m(plaintext.c_str()); // 加密数据 auto c = encrypt(m, N, e); cout << "Encrypted: " << c.get_str() << endl; // 解密数据 auto decrypted = decrypt(c, N, d); cout << "Decrypted: " << decrypted.get_str() << endl; return 0; } ``` 需要注意的是,RAS-3072 是一种非常复杂的加密算法,实现起来也比较复杂。如果需要使用加密算法来保护敏感数据,请务必仔细考虑安全性和实现细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值