首页 > 编程语言 >Qemu源码分析(7)--Apple的学习笔记

Qemu源码分析(7)--Apple的学习笔记

时间:2023-09-24 15:31:36浏览次数:49  
标签:NULL obj Apple -- object 源码 child property log

一,前言

今天继续分析主要的api,包括了print log和属性add及set,因为对于不同对象的操作,主要就是靠属性值设置及判断使用。

二,源码分析

A,关于qemu中自带的-d的log需要传入的参数

主要通过-d 然后传入的参数如下第2个成员,比如out_asmconst QEMULogItem

qemu_log_items[] = {
 { CPU_LOG_TB_OUT_ASM, "out_asm",
 "show generated host assembly code for each compiled TB" },
 { CPU_LOG_TB_IN_ASM, "in_asm",
 "show target assembly code for each compiled TB" },
 { CPU_LOG_TB_OP, "op",
 "show micro ops for each compiled TB" },
 { CPU_LOG_TB_OP_OPT, "op_opt",
 "show micro ops after optimization" },
 { CPU_LOG_TB_OP_IND, "op_ind",
 "show micro ops before indirect lowering" },
 { CPU_LOG_INT, "int",
 "show interrupts/exceptions in short format" },
 { CPU_LOG_EXEC, "exec",
 "show trace before each executed TB (lots of logs)" },
 { CPU_LOG_TB_CPU, "cpu",
 "show CPU registers before entering a TB (lots of logs)" },
 { CPU_LOG_MMU, "mmu",
 "log MMU-related activities" },
 { CPU_LOG_PCALL, "pcall",
 "x86 only: show protected mode far calls/returns/exceptions" },
 { CPU_LOG_RESET, "cpu_reset",
 "show CPU state before CPU resets" },
 { LOG_UNIMP, "unimp",
 "log unimplemented functionality" },
 { LOG_GUEST_ERROR, "guest_errors",
 "log when the guest OS does something invalid (eg accessing a\n"
 "non-existent register)" },
 { CPU_LOG_PAGE, "page",
 "dump pages at beginning of user mode emulation" },
 { CPU_LOG_TB_NOCHAIN, "nochain",
 "do not chain compiled TBs so that \"exec\" and \"cpu\" show\n"
 "complete traces" },
 
#if defined(CONFIG_GNU_ARM_ECLIPSE)
 { LOG_FUNC, "func",
 "log functions entry" },
 { LOG_MR, "mr",
 "log trace messages for memory regions read/writes" },
#endif /* defined(CONFIG_GNU_ARM_ECLIPSE) */
 
 { 0, NULL, NULL },
};

  1. 代码首先获取mask参数
case QEMU_OPTION_d:
 log_mask = optarg;
 break;
  1. 解析完参数后,将参数通过qemu_str_to_log_mask函数获取mask值。

if (log_mask) {
 int mask;
 mask = qemu_str_to_log_mask(log_mask);
 if (!mask) {
 qemu_print_log_usage(stdout);
 exit(1);
 }
 qemu_set_log(mask);
 } else {
 qemu_set_log(0);
}


主要的解析就是通过char **parts = g_strsplit(str, ",", 0);按逗号拆分为字符list。

for (tmp = parts; tmp && *tmp; tmp++) {
…
 for (item = qemu_log_items; item->mask != 0; item++) {
 if (g_str_equal(*tmp, item->name)) {
 goto found;
 }
 }
 goto error;
 found:
 mask |= item->mask;
}
  1. 关于传参-d

我想要打印qemu_log_function_name,只要加-d func即可。由于打印的内容多,所以也可以打印到log文件,用-D qemulogfile

B,关于属性

  1. 最早属性创建函数是在object_new的时候添加的。对应TypeImp中有instance_init则会调用,属性是GHashTable *说明一个object可以挂很多属性。
if (ti->instance_init) {
 ti->instance_init(obj);
}


最后这些注册的函数中会存在object_property_add,添加属性类中的值。
object_property_add_str(obj, "image", machine_get_image, machine_set_image, NULL);

Qemu源码分析(7)--Apple的学习笔记_qemu

另外,我研究下opaqeu主要的作用,他的参数是void *opaque;如下图

object_property_add_str(obj, "image",machine_get_image, machine_set_image, NULL);

prop就是 StringProperty *prop = g_malloc0(sizeof(*prop));所以用了void*后就很灵活,只要malloc申请好空间即可。

Qemu源码分析(7)--Apple的学习笔记_qemu_02


  1. 为属性设置描述

object_property_set_description(obj, "image","Bare-bone image file",NULL);
比如上面的截图image已经创建完成了,然后为description赋值。

void object_property_set_description(Object *obj, const char *name,
 const char *description, Error **errp)
{
 ObjectProperty *op;

 op = object_property_find(obj, name, errp);
 if (!op) {
 return;
 }

 g_free(op->description);
 op->description = g_strdup(description);
}

关于object_property_add_child函数,其实就是添加属性,而且可以看到object_property_add的倒数第二个参数是child(object*类型的),其实就是opaque。

而resolve的函数是object_resolve_child_property,其实就是返回opaque。

static Object *object_resolve_child_property(Object *parent, void *opaque, const gchar *part)
{
 return opaque;
}

那么如下object_resolve_path_component返回的其实就是opaque,也就是child的object*。

Qemu源码分析(7)--Apple的学习笔记_qemu_03

再回到最早,我添加了一些注释

CortexMBoardState *cortexm_board_get(void)
{
 if (board == NULL) {
 board = container_get(object_get_root(), "/machine");
 }
 if (board == NULL) {
 return NULL;
 }
 return CORTEXM_BOARD_STATE(board);
}
Object *object_get_root(void)
{
//是首个节点地址
 if (!root) {
 root = object_new("container"); //root赋值为container
 }
 return root;
}
/*从main函数开始最早调用*object_get_root的是如下,也就是创建了一个machine part到属性表,挂载在container节点后面。
 object_property_add_child(object_get_root(), "machine",
 OBJECT(current_machine), &error_abort);
所以才有之后的container_get函数去找这个OBJECT(current_machine)的object指针。*/
Object *container_get(Object *root, const char *path)
{
 Object *obj, *child;
 gchar **parts;
 int i;
 parts = g_strsplit(path, "/", 0);
 assert(parts != NULL && parts[0] != NULL && !parts[0][0]);
 obj = root; // obj设置为root
for (i = 1; parts[i] != NULL; i++, obj = child) {
 // 在root中的属性中找parts名字一样的child object。
 child = object_resolve_path_component(obj, parts[i]);
//若没有找到这个parts,那么在root中添加一个节点container
if (!child) { child = object_new("container");
 object_property_add_child(obj, parts[i], child, NULL);
 }
 }
 g_strfreev(parts);
 return obj;
}
Object *object_resolve_path_component(Object *parent, const gchar *part)
{
 ObjectProperty *prop = object_property_find(parent, part, NULL);
 if (prop == NULL) {
 return NULL;
 }
 //属性找到后就调用注册函数返回child object对象指针
 if (prop->resolve) {
 return prop->resolve(parent, prop->opaque, part);
 } else {
 return NULL;
 }
}
ObjectProperty *object_property_find(Object *obj, const char *name,
 Error **errp)
{
 ObjectProperty *prop;
 ObjectClass *klass = object_get_class(obj);
 // 先在Klass的父类的属性表中找name是否有匹配的
 prop = object_class_property_find(klass, name, NULL);
 if (prop) {
 return prop;
 }
 // 就在当前object中的属性表中找name
 prop = g_hash_table_lookup(obj->properties, name);
 if (prop) {
 return prop;
 }
 error_setg(errp, "Property '.%s' not found", name);
 return NULL;
}
  1. 分析过如上关于object属性,再看下图247行就很容易理解了

其实就是调用了object_property_add_child,刚刚都已经分析过了。

void cm_object_property_add_child(Object *obj, const char *node_name,
 Object *child)
{
 Error *err = NULL;
 object_property_add_child(obj, node_name, child, &err);
 if (err) {
 error_report("Adding child %s for %s failed: %s.", node_name,
 object_get_typename(obj), error_get_pretty(err));
 exit(1);
 }
}
  1. 接着看set属性值

接着会看到

cm_object_property_set_int(mcu, 8000000, "hse-freq-hz"); // 8.0 MHz

Set了hse-freq-hz,那么之前一定add过这个属性,所以能找到stm32_mcu_instance_init_callback函数中有add这个属性,最后一个参数等于设置这个属性的默认值,也就是为opaque成员赋值。

cm_object_property_add_uint32(obj, "hse-freq-hz", &state->hse_freq_hz);

这些instance_init都是object_New的TypeImp初始化的时候创建的,也就是我这块虚拟board的父类对象创建过程中创建的。

5.cm_object_realize(mcu);我本来以为也就是设置一个mcu对象的属性

void cm_object_realize(Object *obj)
{
 Error *err = NULL;

 object_property_set_bool(obj, true, "realized", &err);
 if (err) {
 error_report("Realization of object %s failed: %s",
 object_get_typename(obj), error_get_pretty(err));
 exit(1);
 }
}

结果可以看到调用了很多注册的函数实现了虚拟mcu创建的功能。

cortexm_mcu_realize_callback
cm_device_parent_realize
stm32_mcu_realize_callback
cm_device_by_name_realize
stm32_mcus_realize_callback
device_set_realized
property_set_bool
object_property_set
object_property_set_qobject
object_property_set_bool
cm_object_realize
stm32f4_discovery_board_init_callback
qemu_main
main

主要就是有摄像动态的钩子函数在起作用,导致了千变万化的效果。比如 property_set_bool中的prop->set(obj, value, errp);

比较关键是device_set_realized和cm_device_parent_realize主要是填充CortexMState对象,包括Flash,中断和内存,最后加载客户端elf。

三,小结

本次主要学习了*void的成员的多样化设计思路,另外就是发现钩子函数的妙用,我平时基本仅用一层钩子函数,所以功能单一,但是多种钩子函数组合后,变化的效果就很多了,主要还是qemu面向对象的抽象结构体设计的好。





标签:NULL,obj,Apple,--,object,源码,child,property,log
From: https://blog.51cto.com/u_16247275/7586221

相关文章

  • 2023湖南省赛 E.ytree (线段树)
    传送门大致思路:1.将操作1拆分为两个部分x(-1)^d+kd(-1)^d。对于操作1中的x(-1)^d部分而言。我们可以对式子进行拆分,把x拆出来,我们会发现和v号点距离为奇数的点会减去x,为偶数的点会加上x,所以我们可以在线段树上用一个sum1维护应该减去的值,sum2维护加上的值即可。2.随即就是......
  • django初学
    其实还有个drf框架#django把框架分为一个项目包含很多应用pythonmanage.pystartapppolls该命令在在manage.py同级下创建应用目录polls是应用的名字!!!!!!!!!!!!!!!!#应用创建完之后需要在setting里面注册 #编写url和views函数的对应关系 页面的话,#映射网页的话,在应......
  • crash —— 查看当前系统每个page的信息
    linux中page数据结构可以通过mem_map数组访问,下面的方法可以输出每个page的相关成员。通用版本下面这个命令可以显示每个page的一些关键成员的值。crash>kmem-pPAGEPHYSICALMAPPINGINDEXCNTFLAGSffffea000000000000......
  • 基于go语言gin框架的web项目骨架
    该骨架每个组件之间可单独使用,组件之间松耦合,高内聚,组件的实现基于其他三方依赖包的封装。目前该骨架实现了大多数的组件,比如事件,中间件,日志,配置,参数验证,命令行,定时任务等功能,目前可以满足大多数开发需求,后续会持续维护更新功能。github地址:https://github.com/czx-lab/sk......
  • Java语言基础知识全总结
    一.Java的优点1.      跨平台性。一次编译,到处运行。Java编译器会将Java代码编译成能在JVM上直接运行的字节码文件,C++会将源代码编译成可执行的二进制代码文件,所以C++执行速度快2.      纯面向对象。Java所有的代码都必须在类中书写。C++兼具面向对象和面向过程的特......
  • 学习笔记3
    第十章:sh编程介绍第十章的主要内容是研究sh编程。对于sh编程的介绍分为以下几个方面:1.sh脚本的编写脚本格式以#!/bin/bash开头(指向解释器)2.sh控制语句2.1脚本格式脚本格式以#!/bin/bash开头(指向解释器)2.2第一个shell脚本,helloworld.sh,输出helloworld!2.3执行方式方......
  • ADYCGP-Nmerical Reports
     ......
  • Markdown的一些基础用法
    Markdown学习标题三级标题四级标题字体Hello,word!Hello,word!Hello,word!Hello,word!引用孤独的鲸分割线图片超链接Typora最后一个免费版本-KoiC-博客园(cnblogs.com)学习时搜到的,觉得实用便保留下来不妥,可删列表ABCABC表格名字性别......
  • 攻防世界MISC练习题[中等] QR1
    下载附件得到一张空白的图片直接打开放大后发现有很多黑点,观察其的分布位置看起来像是二维码因为全是小黑点的分布也不能直接扫描出来,拿去KALI看一下。虚拟鸡启动!binwalk没内容zstegnothing。现在想起来题目是QR,在想会不会是和二维码有关,决定再去看看图片。放大图片后......
  • E - Complete Binary Tree
    E-CompleteBinaryTree完全二叉树三个值N,X,K,分别表示点的个数,点的编号,求到X点的距离为K点的个数。首先,我们对以X为根的子树进行分析,可以知道到X点距离为K的点的个数为2^k。这里需要特判,深度为K时最左边的编号不能大于N,点的个数就等于min(r,n)-l+1。然后再对它的父亲进行......