菜单

kaoqi
kaoqi
发布于 2026-07-24 / 7 阅读
0
0

ACPI的namespace结构体

严格意义上说,NameSpace的这种结构在很多代码环境中都可以存在,这里主要是讲kernel或者efi这种轻量级环境中的数据结构体。

命名空间提供了虚拟化的一种轻量级形式,使得我们可以从不同的方面来查看系统的全局属性。该机制类似于Solaris中的Zone或者FreeBSD中的jail。

正是由于kernel内部使用这种namespace作为资源的隔离、调用的方式,特别是诸如ACPI这样的关键硬件资源,是经由namespace后再由各驱动进行调用的,所以不得不品鉴。

kernel源代码位置:The Linux Kernel Archives

概念

命名空间是内核为了隔离资源而诞生的一种数据结构。可以从kernel源代码文件的头文件中看到这个nsproxy的描述:

struct nsproxy {
	refcount_t count;  // 引用计数
	struct uts_namespace *uts_ns;  // UTS命名空间
	struct ipc_namespace *ipc_ns;  // IPC命名空间
	struct mnt_namespace *mnt_ns;  // 挂载命名空间
	struct pid_namespace *pid_ns_for_children;  // PID命名空间
	struct net 	     *net_ns;  // 网络命名空间
	struct time_namespace *time_ns;  // Cgroup命名空间
	struct time_namespace *time_ns_for_children;  // 用户命名空间
	struct cgroup_namespace *cgroup_ns;  // 时间命名空间
};
extern struct nsproxy init_nsproxy;

但这个是进程的namespace,跟本文想讲的ACPI namespace又有点不一样。

namespace应该具备的特征是清晰的:就是作为一个全局可管理的变量存在于内核中,既支持向各个进程传递资源的同时,又支持对资源进行封装隔离,让不同进程对资源的调用互相不感知,造成一种进程对资源独占的假象,这样的数据结构就是namespace。

ACPI命名空间的确立

对于kernel中的ACPI来说,从入口函数start_kernel出发,转到acpi_early_init函数执行时调用具体的acpi_initialize_subsystem函数(位置在/drivers/acpi/acpica/utxfinit.c文件中),并由这个函数开始,完成ACPI的初始化并建立命名空间。

更具体的说,ACPI命名空间的确立是由初始化函数中的acpi_ns_root_initialize函数完成的:

/*******************************************************************************
 *
 * FUNCTION:    acpi_ns_root_initialize
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Allocate and initialize the default root named objects
 *
 * MUTEX:       Locks namespace for entire execution
 *
 ******************************************************************************/
acpi_status acpi_ns_root_initialize(void)
{
	acpi_status status;
	const struct acpi_predefined_names *init_val = NULL;
	struct acpi_namespace_node *new_node;
	struct acpi_namespace_node *prev_node = NULL;
	union acpi_operand_object *obj_desc;
	acpi_string val = NULL;
  
    ......

    for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
		status = AE_OK;

        ......

        new_node =
		    acpi_ns_create_node(*ACPI_CAST_PTR(u32, init_val->name));
		if (!new_node) {
			status = AE_NO_MEMORY;
			goto unlock_and_exit;
		}
		new_node->descriptor_type = ACPI_DESC_TYPE_NAMED;
		new_node->type = init_val->type;
		if (!prev_node) {
			acpi_gbl_root_node_struct.child = new_node;
		} else {
			prev_node->peer = new_node;
		}
		new_node->parent = &acpi_gbl_root_node_struct;
		prev_node = new_node;
		if (init_val->val) {
		    status = acpi_os_predefined_override(init_val, &val);

            ......

            	switch (init_val->type) {
			case ACPI_TYPE_METHOD:

				obj_desc->method.param_count =
				    (u8) ACPI_TO_INTEGER(val);
				obj_desc->common.flags |= AOPOBJ_DATA_VALID;

                ......

                 status = acpi_ns_attach_object(new_node, obj_desc,
						       obj_desc->common.type);

			    /* Remove local reference to the object */

			    acpi_ut_remove_reference(obj_desc);

                ......
              }
        }
    }
}

可以看到,这个函数中输入的核心是acpi_gbl_root_node这个起始搜索点,注意这个函数目前还没有接收DSDT,只是把命名空间的架子搭起来。

这个架子,按照其中注释的描述,时一个类似下面这样的东西:(一个层次化的树状结构)

根节点名称

根节点含义

_PR Scope

处理器域

_SB Device

总线设备

_SI Scope

系统指示灯域

_TZ Device

热插拔设备

_GPE Scope

通用事件作用域,用于存放通用设备相关的对象

_OS String

描述操作系统名字的字符串

_REV Integer

描述ACPI规范版本号的数值

_GL Mutex

全局锁互斥体,这是一个互斥锁对象,用于协调操作系统核固件对共享硬件资源的访问。

_OSI Method

操作系统接口查询方法

相应的,这个namespace的结构体在/drivers/acpi/acpica/aclocal.h头文件中有明确定义:

/*
 * The Namespace Node describes a named object that appears in the AML.
 * descriptor_type is used to differentiate between internal descriptors.
 *
 * The node is optimized for both 32-bit and 64-bit platforms:
 * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case.
 *
 * Note: The descriptor_type and Type fields must appear in the identical
 * position in both the struct acpi_namespace_node and union acpi_operand_object
 * structures.
 */
struct acpi_namespace_node {
	union acpi_operand_object *object;	/* Interpreter object */
	u8 descriptor_type;	/* Differentiate object descriptor types */
	u8 type;		/* ACPI Type associated with this name */
	u16 flags;		/* Miscellaneous flags */
	union acpi_name_union name;	/* ACPI Name, always 4 chars per ACPI spec */
	struct acpi_namespace_node *parent;	/* Parent node */
	struct acpi_namespace_node *child;	/* First child */
	struct acpi_namespace_node *peer;	/* First peer */
	acpi_owner_id owner_id;	/* Node creator */

	/*
	 * The following fields are used by the ASL compiler and disassembler only
	 */
#ifdef ACPI_LARGE_NAMESPACE_NODE
	union acpi_parse_object *op;
	void *method_locals;
	void *method_args;
	u32 value;
	u32 length;
	u8 arg_count;

#endif
};

在注释中也明确提及,acpi的命名空间就是由AML解释器对二进制文件进行解释时,产生的一个又一个遵循上述namespace链表结构的具体实例。

在/include/acpi/actypes.h头文件中,具体阐述了acpi的namespace节点可以拥有的类型:

/*
 * Types associated with ACPI names and objects. The first group of
 * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition
 * of the ACPI object_type() operator (See the ACPI Spec). Therefore,
 * only add to the first group if the spec changes.
 *
 * NOTE: Types must be kept in sync with the global acpi_ns_properties
 * and acpi_ns_type_names arrays.
 */
typedef u32 acpi_object_type;

#define ACPI_TYPE_ANY                   0x00
#define ACPI_TYPE_INTEGER               0x01	/* Byte/Word/Dword/Zero/One/Ones */
#define ACPI_TYPE_STRING                0x02
#define ACPI_TYPE_BUFFER                0x03
#define ACPI_TYPE_PACKAGE               0x04	/* byte_const, multiple data_term/Constant/super_name */
#define ACPI_TYPE_FIELD_UNIT            0x05
#define ACPI_TYPE_DEVICE                0x06	/* Name, multiple Node */
#define ACPI_TYPE_EVENT                 0x07
#define ACPI_TYPE_METHOD                0x08	/* Name, byte_const, multiple Code */
#define ACPI_TYPE_MUTEX                 0x09
#define ACPI_TYPE_REGION                0x0A
#define ACPI_TYPE_POWER                 0x0B	/* Name,byte_const,word_const,multi Node */
#define ACPI_TYPE_PROCESSOR             0x0C	/* Name,byte_const,Dword_const,byte_const,multi nm_o */
#define ACPI_TYPE_THERMAL               0x0D	/* Name, multiple Node */
#define ACPI_TYPE_BUFFER_FIELD          0x0E
#define ACPI_TYPE_DDB_HANDLE            0x0F
#define ACPI_TYPE_DEBUG_OBJECT          0x10

#define ACPI_TYPE_EXTERNAL_MAX          0x10
#define ACPI_NUM_TYPES                  (ACPI_TYPE_EXTERNAL_MAX + 1)

可以看出,命名空间中的资源,除了基本的对象、字符等可被定义的描述外,主要存在如下类型:

1、设备类型

2、事件类型

3、方法类型

4、互斥体类型

5、操作区域类型(一段可以被AML访问的地址空间)

6、电源资源类型

7、处理器类型

8、热区类型

而在acpi_ns_root_initialize函数中,则会根据namespace表做具体的动作展开。


评论