const int *p,定义一个指向常量的指针,怎么用呢?如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 看一个可以修改指针变量的情况
int main0(){
int a = 0;
int *p = &a;
*p = 10;
printf("a = %d\n", a);
printf("*p is %d\n", *p); // 很容易通过*p修改a的值,理所当然
}
int main(){
main0();
int b = 0;
const int *p = &b; // 此时的p指向了一个类型的地址,但不可以通过*p的方式来修改a的值
//*p = 20; test.c:25:8: error: assignment of read-only location ‘*p’
b = 20;
printf("b is %d\n", *p); // b is 20. 此时的*p可读不可写
// 另一个实验
const int c = 100;
int *p1;
p1 = &c; // warning: assignment discards ‘const’ qualifier from pointer target type
*p1 = 0; // 消除这个warning,可以使用 p1 = (int *)&c;
printf("c = %d\n", c);
}
看到没有,也就是在c中,可以有办法修改const修饰的常量。 我现在有一个代码:
static char *brd_type = "dvt";
...
const char *cbd_type = of_get_property(root, "carrier_board_type", NULL);
// 这里就会报warning: assignment discards ‘const’ qualifier from pointer
// 需要修改 static const char *brd_type = "dvt";
而of_get_property
的实现为:
static inline const void *of_get_property(const struct device_node *node,
const char *name,
int *lenp)
{
return NULL;
}
链接这块是系统编程的一个大头,当然,csapp
至于什么是链接?我想大部分人可能和我想的一样: 只有在需要动态链接库才需要。其实,这种观点实在太片面。
csapp在本章的第一页就说明了: 链接是贯穿于程序的整个生命周期,存在于编译时(compile time),也就是将源代码转换为汇编代码; 存在于加载(load time),也就是loader加载到内存并执行;甚至存在于运行时(run time),也就是由应用程序来执行。在现代计算机系统中, 链接的工作都是由一个叫做链接器(linker)的工具完成。
linux ld是静态链接器(static linker)以 一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的、可以加载和运行的可执行目标文件作为输出。
为了构造可执行文件,链接器必须完成两个主要的任务:
有三种:
可重定位目标文件
可执行目标文件
共享目标文件
https://stackoverflow.com/questions/824234/what-is-a-callback-function
callback两个主要的作用:
callback最初听说,可以将socket的lib中的函数服复用,当时是处于懵懂的状态,现在重新整理一下。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int a(int (*callback)(void)){
printf("inside parent function\n");
callback();
}
int test(){
printf("inside the callback function\n");
}
int main(){
a(&test);
return 0;
}
打印下,这就是最基本的callback的使用。下面是log:
vimer@user-HP:~/test_local_ota$ ./test
inside parent function
inside the callback function
再来举一个简单的例子:
#include<stdio.h>
int func(int, int);
int main(void)
{
int result1,result2;
/* declaring a pointer to a function which takes
two int arguments and returns an integer as result */
int (*ptrFunc)(int,int);
/* assigning ptrFunc to func's address */
ptrFunc=func;
/* calling func() through explicit dereference */
result1 = (*ptrFunc)(10,20);
/* calling func() through implicit dereference */
result2 = ptrFunc(10,20);
printf("result1 = %d result2 = %d\n",result1,result2);
return 0;
}
int func(int x, int y)
{
return x+y;
}
看到没有,如果我们仅仅知道了func的函数原型,就可以通过callback再次使用它了,而且参数必须指定,这样,容易理解callback的用法了吧。 其实如果我们再一次确认上面的代码,注意里面有一个 explicit 和 implicit dereference,这里确实有点有点意思。
其实,以上的代码就是通过函数指针 callback.
The kernel’s callback mechanism provides a general way for drivers to request and provide notification when certain conditions are satisfied.
所以驱动里使用的比较多呢。
https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/callback-objects
下面以几个更具体的例子进行说明:
// cat callback.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "reg_callback.h"
void my_callback(void){
printf("inside my_callback\n");
}
int main(){
/* initilalize function pointer to my_callback */
callback ptr_my_callback = my_callback;
printf("This is a program demonstrating function callback\n");
/* regitster our callback func */
register_callback(ptr_my_callback);
printf("back inside main program\n");
return 0;
}
cat reg_callback.h
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);
cat reg_callback.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "reg_callback.h"
/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
printf("inside register_callback\n");
/* calling our callback function my_callback */
(*ptr_reg_callback)();
}
gcc -Wall -o callback callback.c reg_callback.c
vimer@user-system:~/test_yubo$ ./callback
This is a program demonstrating function callback
inside register_callback
inside my_callback
back inside main program
以上几个代码段是比较复杂的使用callback的方法,但是概括了一般的使用场景。
工作需要,需要对qemu进行一些改动,先从最简单的添加machine
字段开始吧。
然后最简单,但是还是遇到了一些问题。
我也不太确定是哪一版本(2020年8月), qemu开始使用meson构建build系统,反正这个东西和njnia配合使用,具体怎么使用还真有点 摸不清头脑。但是可以照虎画猫,可以参考下这个git :
https://github.com/qemu/qemu/commit/7a261bafc8ee01294cc709366810798bec4fe2f7#diff-daf90e57f0bba07d67bc8e697f7737c1f2f52cf65a0b8fb44d4f871652f2b860
特殊说明,以下操作基于qemu代码 6.0.0.
---
default-configs/devices/riscv64-softmmu.mak | 1 +
hw/riscv/meson.build | 1 +
hw/riscv/win2030.c | 4 +-
include/hw/riscv/win2030.h | 157 ++++++++++
其实根据已有的code,然后在对应的文件中添加自己的改动,再重新编译即可打印相关字段。
重点可以参考这个: https://qemu.readthedocs.io/en/latest/devel/build-system.html
在meson.build文件中,可以指定要编译的对象。主要是位于 hw 目录下。还有一个 target的meson.build,目前ye不清楚他的作用。
default-configs/devices/*.mak控制板子,show the code:
include arm-softmmu.mak
CONFIG_XLNX_ZYNQMP_ARM=y
CONFIG_XLNX_VERSAL=y
These files mostly define symbols that appear in the *-config-target.h file for each emulator [1]. However, the TARGET_ARCH and TARGET_BASE_ARCH will also be used to select the hw/ and target/ subdirectories that are compiled into each target.
实际上,包括 Rusty Russell 大佬在内,也有自己的一套kernel学习笔记。
https://01.org/linuxgraphics/gfx-docs/drm/kernel-hacking/hacking.html#introduction
自己零零碎碎也记录了不少,但始终没有成体系的总结或者使用的场所。另外一个观点就是, 某个知识自己没有用到过,那么这个知识就不属于你。
加油吧!
使用mount挂载img到一个目录上,需要先知道img的文件类型。
vimer@user-HP:~$ fdisk -l sd-blob.img
Disk sd-blob.img: 13.4 GiB, 14414774272 bytes, 28153856 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 2734708E-E386-4057-ABE7-3260FDA31366
Device Start End Sectors Size Type
sd-blob.img1 870400 28137471 27267072 13G Linux filesystem
sd-blob.img2 2048 133119 131072 64M Linux filesystem
sd-blob.img3 133120 264191 131072 64M Linux filesystem
sd-blob.img4 264192 265087 896 448K Linux filesystem
sd-blob.img5 266240 267135 896 448K Linux filesystem
sd-blob.img6 268288 397311 129024 63M Linux filesystem
sd-blob.img7 397312 398335 1024 512K Linux filesystem
sd-blob.img8 399360 399871 512 256K Linux filesystem
sd-blob.img9 401408 401919 512 256K Linux filesystem
sd-blob.img10 403456 608255 204800 100M Linux filesystem
sd-blob.img11 608256 870399 262144 128M Linux filesystem
我的本意是使用img1的那个分区,那个是一个正常的rootfs, 我现在做的就是把他们copy 出来。
sudo mkdir /mnt/rootfs && sudo mount -o loop,offset=445644800 sd-blob.img /mnt/rootfs
这里面的offset选项需要我值得特别注意,这块我也不是特别熟悉。
https://www.linuxquestions.org/questions/linux-software-2/how-to-mount-dos-img-file-4175430554/
这里需要配合 /etc/fstab
去实现开机自动挂载的功能, 同时,由于 fstab
的改动会影响正常的启动, 所以需要要有一个 mount 的检查过程, 如这个链接说明的这样:
https://blog.csdn.net/bandaoyu/article/details/123806859