<1> Linux设备底层模型
<2> 设备模型上层容器
<3> sysfs文件系统模型
1. Linux设备底层模型
//sysfs的信息来源是kobject层次结构,读一个sysfs文件就是动态的从kobject结构提取信息生成文件,
//kobject层次结构就是linux的设备模型.
//kobject提供基本的对象管理,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。
struct kobject {
const char *name; //指向对象名称的指针
struct list_head entry; //挂到kset中链表的入口点
struct kobject *parent; //指向父对象的指针
struct kset *kset; //所属kset的指针
struct kobj_type *ktype; //指向其对象类型描述符的指针
struct sysfs_dirent *sd; //sysfs文件系统中与该对象对应的文件节点路径指针
struct kref kref; //对象引用计数
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
//kset最重要的是建立上层(sub_system)和下层的(kobject)的关联性
//kobject 也会利用它了分辨自已是属于那一个类型,,然后在/sys下建立正确的目录位置
//而kset 的优先权比较高,
//kobject会利用自已的*kset找到自已所属的kset,然后把*ktype指定成该kset的ktype,
//除非沒有定义kset,才会用ktype来建立关系。
//kobject通过kset组织成层次化的结构; kset是具有相同类型的kobject的集合.
struct kset {
struct list_head list; //用于连接该kset中所有kobject的链表头
spinlock_t list_lock;
struct kobject kobj; //嵌入的kobject
const struct kset_uevent_ops *uevent_ops; //指向uevent操作表的指针
};
struct kobj_type {
void (*release)(struct kobject *kobj); //用于释放kobject占用的资源
const struct sysfs_ops *sysfs_ops; //sysfs操作表
struct attribute **default_attrs; //sysfs文件系统缺省属性列表
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};
//attribute,它以文件的形式输出到sysfs的目录当中,在kobject对应的目录下面,文件名就是name.
//文件读写的方法对应于kobj_type中的sysfs_ops
struct attribute {
const char *name;
umode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
//包含在kset中的所有kobject被组织成一个双向循环链表,list域正是该链表的头。
//kset数据结构还内嵌了一个kobject对象(由kobj域表示),所有属于这个kset的kobject对象的parent域
//均指向这个内嵌的kobject.
//kset还依赖于kobject维护引用计数: kset的引用计数实际上就是内嵌的kobject对象的引用计数。
@Kobject.c
EXPORT_SYMBOL(kobject_set_name);
EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_add);
EXPORT_SYMBOL(kobject_get);
EXPORT_SYMBOL(kobject_put);
EXPORT_SYMBOL(kobject_del);
EXPORT_SYMBOL(kset_register);
EXPORT_SYMBOL(kset_unregister);
int kobject_add(struct kobject * kobj);
+-- kobject_add_varg(kobj, parent, fmt, args);
+-- kobject_add_internal(kobj);
+-- parent = kobject_get(kobj->parent); //增加父目录各级kobject的引用计数;
+-- if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj); //挂接该kobject对象到kset的list链中;
kobj->parent = parent; //将kobj对象加入Linux设备层次;
}
//在其parent指向的目录下创建文件节点(并启动该类型内核对象的hotplug函数?);
+-- error = create_dir(kobj);

2. 设备模型上层容器
2.1 总线
/**
* struct bus_type - The bus type of the device
*
* @name: The name of the bus.
* @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id).
* @dev_root: Default device to use as the parent.
* @bus_attrs: Default attributes of the bus.
* @dev_attrs: Default attributes of the devices on the bus.
* @drv_attrs: Default attributes of the device drivers on the bus.
* @match: Called, perhaps multiple times, whenever a new device or driver
* is added for this bus. It should return a nonzero value if the
* given device can be handled by the given driver.
* @uevent: Called when a device is added, removed, or a few other things
* that generate uevents to add the environment variables.
* @probe: Called when a new device or driver add to this bus, and callback
* the specific driver's probe to initial the matched device.
* @remove: Called when a device removed from this bus.
* @shutdown: Called at shut-down time to quiesce the device.
* @suspend: Called when a device on this bus wants to go to sleep mode.
* @resume: Called to bring a device on this bus out of sleep mode.
* @pm: Power management operations of this bus, callback the specific
* device driver's pm-ops.
* @iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU
* driver implementations to a bus and allow the driver to do
* bus-specific setup
* @p: The private data of the driver core, only the driver core can
* touch this.
*
* A bus is a channel between the processor and one or more devices. For the
* purposes of the device model, all devices are connected via a bus, even if
* it is an internal, virtual, "platform" bus. Buses can plug into each other.
* A USB controller is usually a PCI device, for example. The device model
* represents the actual connections between buses and the devices they control.
* A bus is represented by the bus_type structure. It contains the name, the
* default attributes, the bus' methods, PM operations, and the driver core's
* private data.
*/
struct bus_type {
const char *name;
const char *dev_name;
struct device *dev_root;
struct bus_attribute *bus_attrs;
struct device_attribute *dev_attrs;
struct driver_attribute *drv_attrs;
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
struct iommu_ops *iommu_ops;
struct subsys_private *p; //bus关联的设备驱动链表都在这里面
};
/**
* struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
*
* @subsys - the struct kset that defines this subsystem
* @devices_kset - the subsystem's 'devices' directory
* @interfaces - list of subsystem interfaces associated
* @mutex - protect the devices, and interfaces lists.
*
* @drivers_kset - the list of drivers associated
* @klist_devices - the klist to iterate over the @devices_kset
* @klist_drivers - the klist to iterate over the @drivers_kset
* @bus_notifier - the bus notifier list for anything that cares about things
* on this bus.
* @bus - pointer back to the struct bus_type that this structure is associated
* with.
*
* @glue_dirs - "glue" directory to put in-between the parent device to
* avoid namespace conflicts
* @class - pointer back to the struct class that this structure is associated
* with.
*
* This structure is the one that is the actual kobject allowing struct
* bus_type/class to be statically allocated safely. Nothing outside of the
* driver core should ever touch these fields.
*/
struct subsys_private {
struct kset subsys;
struct kset *devices_kset; //devices_kset
struct list_head interfaces;
struct mutex mutex;
struct kset *drivers_kset; //drivers_kset
struct klist klist_devices; //总线上所挂的设备的链表
struct klist klist_drivers; //总线上设备对应的驱动的链表
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
struct kset glue_dirs;
struct class *class;
};
2.2 设备
//通常device结构不单独使用,而是内嵌在更大的结构中作为一个子结构使用
/**
* struct device - The basic device structure
* @parent: The device's "parent" device, the device to which it is attached.
* In most cases, a parent device is some sort of bus or host
* controller. If parent is NULL, the device, is a top-level device,
* which is not usually what you want.
* @p: Holds the private data of the driver core portions of the device.
* See the comment of the struct device_private for detail.
* @kobj: A top-level, abstract class from which other classes are derived.
* @init_name: Initial name of the device.
* @type: The type of device.
* This identifies the device type and carries type-specific
* information.
* @mutex: Mutex to synchronize calls to its driver.
* @bus: Type of bus device is on.
* @driver: Which driver has allocated this
* @platform_data: Platform data specific to the device.
* Example: For devices on custom boards, as typical of embedded
* and SOC based hardware, Linux often uses platform_data to point
* to board-specific structures describing devices and how they
* are wired. That can include what ports are available, chip
* variants, which GPIO pins act in what additional roles, and so
* on. This shrinks the "Board Support Packages" (BSPs) and
* minimizes board-specific #ifdefs in drivers.
* @power: For device power management.
* See Documentation/power/devices.txt for details.
* @pm_domain: Provide callbacks that are executed during system suspend,
* hibernation, system resume and during runtime PM transitions
* along with subsystem-level and driver-level callbacks.
* @numa_node: NUMA node this device is close to.
* @dma_mask: Dma mask (if dma'ble device).
* @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
* hardware supports 64-bit addresses for consistent allocations
* such descriptors.
* @dma_parms: A low level driver may set these to teach IOMMU code about
* segment limitations.
* @dma_pools: Dma pools (if dma'ble device).
* @dma_mem: Internal for coherent mem override.
* @archdata: For arch-specific additions.
* @of_node: Associated device tree node.
* @devt: For creating the sysfs "dev".
* @id: device instance
* @devres_lock: Spinlock to protect the resource of the device.
* @devres_head: The resources list of the device.
* @knode_class: The node used to add the device to the class list.
* @class: The class of the device.
* @groups: Optional attribute groups.
* @release: Callback to free the device after all references have
* gone away. This should be set by the allocator of the
* device (i.e. the bus driver that discovered the device).
*
* At the lowest level, every device in a Linux system is represented by an
* instance of struct device. The device structure contains the information
* that the device model core needs to model the system. Most subsystems,
* however, track additional information about the devices they host. As a
* result, it is rare for devices to be represented by bare device structures;
* instead, that structure, like kobject structures, is usually embedded within
* a higher-level representation of the device.
*/
struct device {
struct device *parent;
struct device_private *p; //特定于设备的私有数据
//内嵌的kobject对象,用于引用计数管理并通过它实现设备层次结构
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to its driver.*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this device */
void *platform_data; /* Platform specific data,
device core doesn't touch it */
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask; /* Like dma_mask, but for alloc_coherent mappings
as not all hardware supports 64 bit addresses
for consistent allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
/*
* The type of device, "struct device" is embedded in. A class
* or bus can contain devices of different types
* like "partitions" and "disks", "mouse" and "event".
* This identifies the device type and carries type-specific
* information, equivalent to the kobj_type of a kobject.
* If "name" is specified, the uevent will contain it in
* the DEVTYPE variable.
*/
struct device_type {
const char *name;
const struct attribute_group **groups;
int (*uevent) (struct device *dev, struct kobj_uevent_env *env);
char *(*devnode)(struct device *dev, umode_t *mode);
void (*release)(struct device *dev);
const struct dev_pm_ops *pm;
};
struct device *
device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata,
const char *fmt, ...)
+-- device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
+-- dev->devt = devt;
+-- dev->class = class;
+-- dev->parent = parent;
+-- dev->release = device_create_release;
+-- dev_set_drvdata(dev, drvdata);
+-- device_register(dev); /*将一个新的device对象插入设备模型;*/
+-- device_initialize(dev);
+-- device_add(dev);
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
+-- client->dev.parent = &client->adapter->dev;
+-- client->dev.bus = &i2c_bus_type; //predefined bus_type
+-- client->dev.type = &i2c_client_type; //predefined device_type
+-- client->dev.of_node = info->of_node;
+-- status = device_register(&client->dev);
+-- device_initialize(dev);
+-- device_add(dev);
int device_add(struct device *dev)
+-- device_private_init(dev);
+-- dev_set_name(dev, "%s", dev->init_name);
+-- if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
+-- kobject_add(&dev->kobj, dev->kobj.parent, NULL);
+-- device_create_file(dev, &uevent_attr);
+-- device_create_file(dev, &devt_attr);
+-- device_create_sys_dev_entry(dev);
+-- devtmpfs_create_node(dev);
+-- device_add_class_symlinks(dev);
+-- device_add_attrs(dev);
+-- struct class *class = dev->class;
+-- const struct device_type *type = dev->type; //拿到predefined的device_type
+-- if (class) {
device_add_attributes(dev, class->dev_attrs);
device_add_bin_attributes(dev, class->dev_bin_attrs);
}
+-- if (type)
device_add_groups(dev, type->groups); //用拿到的device_type初始化设备
+-- device_add_groups(dev, dev->groups);
+-- bus_add_device(dev);
+-- dpm_sysfs_add(dev);
+-- device_pm_add(dev);
+-- if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
+-- kobject_uevent(&dev->kobj, KOBJ_ADD); //通知user space,有内核对象加入
+-- bus_probe_device(dev); //在总线的设备/驱动链表上搜索,这里导致probe函数的调用
2.3 驱动
/**
* struct device_driver - The basic device driver structure
* @name: Name of the device driver.
* @bus: The bus which the device of this driver belongs to.
* @owner: The module owner.
* @mod_name: Used for built-in modules.
* @suppress_bind_attrs: Disables bind/unbind via sysfs.
* @of_match_table: The open firmware table.
* @probe: Called to query the existence of a specific device,
* whether this driver can work with it, and bind the driver
* to a specific device.
* @remove: Called when the device is removed from the system to
* unbind a device from this driver.
* @shutdown: Called at shut-down time to quiesce the device.
* @suspend: Called to put the device to sleep mode. Usually to a
* low power state.
* @resume: Called to bring a device from sleep mode.
* @groups: Default attributes that get created by the driver core
* automatically.
* @pm: Power management operations of the device which matched
* this driver.
* @p: Driver core's private data, no one other than the driver
* core can touch this.
*
* The device driver-model tracks all of the drivers known to the system.
* The main reason for this tracking is to enable the driver core to match
* up drivers with new devices. Once drivers are known objects within the
* system, however, a number of other things become possible. Device drivers
* can export information and configuration variables that are independent
* of any specific device.
*/
struct device_driver {
const char *name;
struct bus_type *bus; //驱动所属的总线
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;
int (*probe) (struct device *dev); //设备探测函数,用于探测设备是否可以被该驱动程序管理
int (*remove) (struct device *dev);
void (*shutdown)(struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p; //驱动管理的设备的链表在这里面
};
struct driver_private {
struct kobject kobj;
struct klist klist_devices; //该驱动所管理的设备链表头
struct klist_node knode_bus;
struct module_kobject *mkobj;
struct device_driver *driver;
};
3. sysfs文件系统模型
3.1 文件系统
所谓"文件", 就是按一定的形式存储在介质上的信息,所以一个文件其实包含了两方面的信息,一是存储的数据本身,二是有关该文件的元数据(文件的组织和管理的信息)。在内存中, 每个文件都有一个dentry(目录项)和inode(索引节点)结构,dentry记录着文件名,上级目录等信息,正是它形成了我们所看到的树状结构;而有关文件的组织和管理的信息主要存放inode里面,它记录着文件在存储介质上的位置与分布。同时dentry->d_inode指向相应的inode结构。dentry与inode是多对一的关系,因为有可能一个文件有好几个文件名。所有的dentry用d_parent和d_child连接起来,就形成了我们熟悉的树状结构。
inode代表的是物理意义上的文件,通过inode可以得到一个数组,这个数组记录了文件内容的位置,如该文件位于硬盘的第3,8,10块,那么这个数组的内容就是3,8,10。其索引节点号inode->i_ino,在同一个文件系统中是唯一的,内核只要根据i_ino,就可以计算出它对应的inode在介质上的位置。就硬盘来说,根据i_ino就可以计算出它对应的inode属于哪个块(block),从而找到相应的inode结构。但对于某一种特定的文件系统而言,仅仅用inode还是无法描述出所有的文件系统(比如ext3,在内存中用ext3_inode_info描述。他是一个包含inode的"容器")。
struct inode {
umode_t i_mode;
unsigned short i_opflags;
uid_t i_uid;
gid_t i_gid;
unsigned int i_flags;
const struct inode_operations *i_op;
struct super_block *i_sb;
struct address_space *i_mapping;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
/* Stat data, not accessed from path walking */
unsigned long i_ino;
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink;
unsigned int __i_nlink;
};
dev_t i_rdev;
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes;
blkcnt_t i_blocks;
loff_t i_size;
/* Misc */
unsigned long i_state;
struct mutex i_mutex;
unsigned long dirtied_when; /* jiffies of first dirtying */
struct hlist_node i_hash;
struct list_head i_wb_list; /* backing dev IO list */
struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
union {
struct list_head i_dentry;
struct rcu_head i_rcu;
};
atomic_t i_count;
unsigned int i_blkbits;
u64 i_version;
atomic_t i_dio_count;
atomic_t i_writecount;
/* former ->i_op->default_file_ops */
const struct file_operations *i_fop;
struct file_lock *i_flock;
struct address_space i_data;
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];
#endif
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
};
__u32 i_generation;
……
void *i_private; /* fs or device private pointer */
};
struct dentry {
/* RCU lookup touched fields */
unsigned int d_flags; /* protected by d_lock */
seqcount_t d_seq; /* per dentry seqlock */
struct hlist_bl_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
/* Ref lookup also touches following */
unsigned int d_count; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
const struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
unsigned long d_time; /* used by d_revalidate */
void *d_fsdata; /* fs-specific data */
struct list_head d_lru; /* LRU list */
/* d_child and d_rcu can share memory */
union {
struct list_head d_child; /* child of parent list */
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
};
我们要实现一种文件系统就是要实现VFS所定义的一系列接口: file_operations, dentry_operations, inode_operations等,供上层调用。file_operations是对每个具体文件的读写操作; dentry_operations, inode_operations则是对文件的属性(如改名字)建立或删除的操作。
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
……
unsigned int (*poll) (struct file *, struct poll_table_struct *);
……
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
……
};
struct dentry_operations {
int (*d_revalidate)(struct dentry *, struct nameidata *);
int (*d_hash)(const struct dentry *, const struct inode *,
struct qstr *);
int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *);
void (*d_prune)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
int (*d_manage)(struct dentry *, bool);
} ____cacheline_aligned;
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
……
int (*create) (struct inode *,struct dentry *,umode_t,struct nameidata *);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);
int (*symlink) (struct inode *,struct dentry *,const char *);
int (*mkdir) (struct inode *,struct dentry *,umode_t);
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
……
} ____cacheline_aligned;
在2.4时代,不同文件系统索引节点的内存映像(ext3_inode_info,reiserfs_inode_info,msdos_inode_info ...)都是用一个union内嵌在inode数据结构中的. 但inode作为一种非常基本的数据结构而言,这样搞太大了,不利于快速的分配和回收。但是后来发明了container_of(...)这种方法后,就把union移到了外部,我们可以用类似container of(inode, struct ext3_inode_info, vfs_inode),从inode出发,得到其的"容器"。
//创建/sys/devices、/sys/dev 、/sys/dev/block、/sys/dev/char、/sys/bus、/sys/devices/system...
do_basic_setup(void)
+-- driver_init();
+-- devices_init();
+-- devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
+-- dev_kobj = kobject_create_and_add("dev", NULL);
+-- sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
+-- sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
+-- buses_init();
+-- bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
+-- system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
+-- classes_init();
+-- class_kset = kset_create_and_add("class", NULL, NULL);
+-- firmware_init();
+-- firmware_kobj = kobject_create_and_add("firmware", NULL);
+-- hypervisor_init();
+-- hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);
+-- platform_bus_init();
+-- device_register(&platform_bus);
+-- bus_register(&platform_bus_type);
+-- cpu_dev_init();
+-- subsys_system_register(&cpu_subsys, cpu_root_attr_groups)
+-- memory_dev_init();
+-- subsys_system_register(&memory_subsys, NULL);