如何从内存中找acpi子表,以iort为例.

本文介绍如何在Linux内核中使用ACPI表进行SMMU V3设备的初始化过程。从获取ACPI表到扫描IORT节点查找指定类型节点,详细解释了相关函数的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在kernel中一般通过acpi_get_table的方式找到某个子table的head
例如可以同下面这段code找到iort的head,然后将其赋值给iort_table,下面这段code可以当模板适用于acpi的个个子表
    acpi_status status;

    status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
    if (ACPI_FAILURE(status)) {
        if (status != AE_NOT_FOUND) {
            const char *msg = acpi_format_exception(status);

            pr_err("Failed to get table, %s\n", msg);
        }

        return;
    }


acpi_status
acpi_get_table(char *signature,
           u32 instance, struct acpi_table_header **out_table)
{
    acpi_size tbl_size;

    return acpi_get_table_with_size(signature,
               instance, out_table, &tbl_size);
}

acpi_status
acpi_get_table_with_size(char *signature,
           u32 instance, struct acpi_table_header **out_table,
           acpi_size *tbl_size)
{
    u32 i;
    u32 j;
    acpi_status status;

    /* Parameter validation */

    if (!signature || !out_table) {
        return (AE_BAD_PARAMETER);
    }

    /* Walk the root table list */

    for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
         i++) {
        if (!ACPI_COMPARE_NAME
            (&(acpi_gbl_root_table_list.tables[i].signature),
             signature)) {
            continue;
        }

        if (++j < instance) {
            continue;
        }

        status =
            acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
        if (ACPI_SUCCESS(status)) {
            *out_table = acpi_gbl_root_table_list.tables[i].pointer;
            *tbl_size = acpi_gbl_root_table_list.tables[i].length;
        }

        if (!acpi_gbl_permanent_mmap) {
            acpi_gbl_root_table_list.tables[i].pointer = NULL;
        }

        return (status);
    }

    return (AE_NOT_FOUND);
}
可见bios传递给kernel的ACPI表在kernel中是用acpi_gbl_root_table_list.table 这个数组表示的。
回到最开始的问题,我们通过acpi_get_table 找到iort 子表后,就可以通过iort_node_match 来找这个iort子表中是否包含ACPI_IORT_NODE_SMMU_V3
static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
{
    if (iort_node_match(ACPI_IORT_NODE_SMMU_V3))
        return arm_smmu_init();

    return 0;
}

而iort_node_match 实现如下:
static acpi_status
iort_match_type_callback(struct acpi_iort_node *node, void *context)
{
    return AE_OK;
}

bool iort_node_match(u8 type)
{
    struct acpi_iort_node *node;

    node = iort_scan_node(type, iort_match_type_callback, NULL);

    return node != NULL;
}
可见iort_match_type_callback 只是返回AE_OK 而已,最重要的是通过iort_scan_node 返回acpi_iort_node *node。
static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
                         iort_find_node_callback callback,
                         void *context)
{
    struct acpi_iort_node *iort_node, *iort_end;
    struct acpi_table_iort *iort;
    int i;

    if (!iort_table)
        return NULL;

    /* Get the first IORT node */
    iort = (struct acpi_table_iort *)iort_table;
    iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
                 iort->node_offset);
    iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
                iort_table->length);

    for (i = 0; i < iort->node_count; i++) {
        if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
                   "IORT node pointer overflows, bad table!\n"))
            return NULL;

        if (iort_node->type == type &&
            ACPI_SUCCESS(callback(iort_node, context)))
            return iort_node;

        iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
                     iort_node->length);
    }

    return NULL;
}
在iort_scan_node 中会遍历之前找到iort在内存中的代表iort_table,然后遍历看是否有ACPI_IORT_NODE_SMMU_V3
if (iort_node->type == type &&  ACPI_SUCCESS(callback(iort_node, context)))
    return iort_node;
如果找到的话,就返回iort_node。这样就可以开始smmu v3的初始化.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值