严格意义上说,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,只是把命名空间的架子搭起来。
这个架子,按照其中注释的描述,时一个类似下面这样的东西:(一个层次化的树状结构)
相应的,这个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表做具体的动作展开。