Zephyr -- Kernel Init

Vector_table.S 以arm cortex-M系列的启动流程为例,arch/arm/core/cortex_m: vector_table.S: 定义了中断向量表_vector_table。其中arm cortex-M规定0x0地址存放栈的起始地址(栈顶)。0x4开始存放reset handler,… 没看到定义外部中断的地址 上电后跳转至z_arm_reset函数,进入reset.S。 Reset.S 目前大部分的宏定义都没打开。这里关注下通用的一些流程: movs.n r0, #_EXC_IRQ_DEFAULT_PRIO msr BASEPRI, r0 设置BASEPRI寄存器, 中断的base prioriity, 低于或等于该优先级的中断都会被屏蔽。 这里#_EXC_IRQ_DEFAULT_PRIO宏展开为3,说明中断优先级只能配置为0/1/2。 ldr r0, =z_interrupt_stacks ldr r1, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE adds r0, r0, r1 msr PSP, r0 // write r0 to PSP mrs r0, CONTROL // read CONTROL to r0 movs r1, #2 orrs r0, r1 /* CONTROL_SPSEL_Msk */ msr CONTROL, r0 // write 0x2 to CONTROL isb bl z_arm_prep_c 1....

2024-01-30 · 2 min

Zephyr -- GPIO Subsystem

Device Tree dts/binding/gpio/gpio-controller.yaml描述了设备树中支持的属性。 gpio-controller节点: 其中gpio-controller和gpio-cells两个属性是必须的。 前者表示gpio controller节点,后者表示其他节点使用gpio specifier需要几个item来描述。 gpio: gpio@0x400ff000 { compatible = "nxp, kinetis-gpio"; status = "disabled"; reg = <0x400ff000 0x40>; interrupts = <59 2>; gpio-controller; #gpio-cells = <2>; ngpios = <32>; // optional, default 32 gpio-reserved-ranges = <3 2>, <10, 1>; // optional, <index size>表示第<index>起<size>个gpio不能使用。 }; consumer节点: xxx-gpios/gpios = <&<gpio-controller节点> <gpio_number> <配置属性>> xxx-gpios = <&gpio 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, <&gpio 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>; GPIO_ACTIVE_LOW表示逻辑电平和实际电平相反,逻辑1代表低电平。 配置属性可在include/zephyr/dt-bindings/gpio/gpio.h中查找。 Interrupt相关flags查阅gpio.h,是多个bit的组合,上图没有完全列出。 Consumer 方法一: 设备树API...

2024-01-26 · 5 min

Zephyr -- Interrupt Subsystem

Overview https://docs.zephyrproject.org/latest/kernel/services/interrupts.html Multi-level Interrupt Handling 如果要支持中断嵌套,需要打开CONFIG_MULTI_LEVEL_INTERRUPTS。CONFIG_2ND_LEVEL_INTERRUPTS, CONFIG_3RD_LEVEL_INTERRUPTS也需要根据硬件架构来选择是否打开。 9 4 2 0 _ _ _ _ _ _ _ _ _ _ _ _ _ (LEVEL 1) 5 3 | A | 2 _ _ _ _ _ _ _ _ _ _ _ _ _ _ (LEVEL 2) | C B _ _ _ _ _ _ _ (LEVEL 3) D Level 1第一级中断控制器有12条interrupt lines, 其中第2条和第9条接到了Level2优先级更高的中断控制器。第4条上接了设备A。 Level 2有两个中断控制器,左边的第3条interrupt line接了设备C, 第5条接到Level3中断控制器。 右边的第二条接了设备B。...

2024-01-26 · 2 min

Clash如何开启终端代理

MacOS&Linux 参考: https://weilining.github.io/294.html 临时方法: export http_proxy=http://127.0.0.1:7890 export https_proxy=$http_proxy 可以把命令写进.bash_profile或.zprofile永久生效: 7890为端口号。 function proxy_on() { export http_proxy=http://127.0.0.1:7890 export https_proxy=$http_proxy echo -e "终端代理已开启。" } function proxy_off(){ unset http_proxy https_proxy echo -e "终端代理已关闭。" } source .bash_profile后输入proxy_on开启,proxy_off关闭。 Windows下在git bash中操作一样。 git clone ssh走代理 MacOS/Linux/Windows: ~/.ssh/config # 全局 ProxyCommand connect -S 127.0.0.1:7890 %h %p # 只为特定域名设定 Host github.com ProxyCommand connect -S 127.0.0.1:7890 %h %p git 有两种协议,一种是https,还有一种是ssh。 如果是用https,设置终端代理即可,参考上面MacOS&Linux的配置方法。如果是ssh,需要单独配置代理。 SSH 通过443端口连接github 有时候ssh的默认端口22被封了, 但443端口仍然可以访问。 只需要修改~/.ssh/config: Host github.com HostName ssh.github.com User git Port 443 VMware虚拟机开启终端代理 参考:https://www....

2024-01-24 · 1 min

Vscode备忘录

keybindings.json: 键盘快捷方式 json 文件。 setting.json: vscode 设置文件。 块选择:shift+箭头 / shift+Alt+鼠标 增加光标:Ctrl+Alt+上/下箭头 / Alt+click 复制一行:Shift+Alt+上/下箭头 移动一行:Alt+箭头 删除一行:Ctrl+Shift+K F2 可以代码重构,对 project 下所有的函数名替换名称 格式化文档:Shift+Alt+F 格式化整个文档 / Ctrl+K → Ctrl+F 格式化某一行 Ctrl+Shift+[ / Ctrl+Shift+] 折叠函数 alt + <n> 切换标签页 自定义的一些快捷键 在 vscode 键盘快捷方式中自定义的一些快捷键: alt + ↑/↓:调整终端大小。 Clangd 插件 配置 .clang-format 配置 compile_commands.json clangd 默认会在 project 目录下寻找compile_commands.json,如果compile_commands.json在 project 目录之外,那么需要通过在settings.json中指定clangd.arguments->--compile-commands-dir=xxx中compile_commands.json的位置。 settings.json: { "[c]": { "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" }, "clangd.arguments": [ "--log=error", "--header-insertion=never", // 是否需要自动插入头文件 "--compile-commands-dir=../../../../out/rts3916_evb_nand" ], "editor.inlayHints.enabled": "offUnlessPressed", "C_Cpp....

2024-01-23 · 2 min

xv6_chapter3 Page tables

3.1 Paging hardware xv6 runs on Sv39 RISC-V, 使用低39位来表示虚拟内存, 高25位没有使用。 39位中27位用作index来寻找PTE(Page table entry), 低12位表示在某个页表中的偏移地址, 正好对应4KB。每个PTE包含44bits的PPN(physical page number)和一些控制位。 实际的RISC-V CPU翻译虚拟地址到物理地址使用了三层。每层存储512个PTE,分别使用9个bit来索引。上一层的一个PTE对应下一层包含512个PTE的Page table地址。所以总共有512*512*512=2^27 PTE。每个pte占8bytes,所以需要占用的内存最多是2^30=1G, 因为没有访问到的pte是不会分配pagetable的,所以实际占用的内存会更少。 每个CPU需要把顶层的page directory物理地址加载到 satp 寄存器中, 第一个Page Directory的地址是已知的。 然后通过L2索引到第一个Page directory的PTE,读出PTE的PPN, 即第二个Page directory的起始物理地址。再根据L1索引到第二个Page directory的PTE, 以此类推。 3.2 Kernel address space 上图PHYSTOP为0x88000000, 见memlayout.h QEMU模拟RAM从0x80000000物理地址开始,至多到0x80000000+12810241024=0x88000000,xv6称这个地址为PHYSTOP。 Kernel使用RAM和device registers是直接映射的,虚拟地址和物理地址相等。 不过有一部分kernel虚拟地址不是直接映射的: Trampoline page. 在虚拟地址的最顶部。这边有意思的是物理内存中的trampoline code被映射到了两个地方,一个对应直接映射的虚拟内存中的kernel text,另一个是虚拟地址最顶部地址的一个page size。有关Trampoline page请参考第四章。 Kernel stack pages. 每个进程都有自己的kernel stack。如果访问超过了自己的kernel stack。会有guard page保护,guard page的PTE valid位置为0,导致访问异常。 3.3 Code: creating an address space TLB. 每个进程有自己的页表,切换进程时需要flush TLB, 因为之前VA-PA对应已经不成立了。通过RISC-V指令sfence.vma可以flush TLB。...

2024-01-11 · 1 min

xv6_chapter2 Operating system organization

2.6 Code: starting xv6, the first process and system call 启动代码: entry.S 为每个CPU设置堆栈,然后跳进start.c的start函数。 # qemu -kernel loads the kernel at 0x80000000 # and causes each CPU to jump there. # kernel.ld causes the following code to # be placed at 0x80000000. .section .text .global _entry _entry: # set up a stack for C. # stack0 is declared in start.c, # with a 4096-byte stack per CPU. # sp = stack0 + (hartid * 4096) la sp, stack0 li a0, 1024*4 csrr a1, mhartid # CPUs 0~7 has hartid from 0~7 addi a1, a1, 1 mul a0, a0, a1 add sp, sp, a0 # jump to start() in start....

2024-01-04 · 2 min

xv6_lab2 System calls

Trace 实现系统调用int trace(int mask);, 当调用mask中包含的系统调用号,打印出来。 在Makefile中增加trace用户程序的编译 UPROGS=\ ... $U/_trace 在user/user.h中增加函数声明 int trace(int); 在usys.pl中增加user space trace函数的入口。可以看到user space调用的系统调用, 是由这个脚本生成的函数。 以trace为例, 提供了trace函数的入口.global trace, 随后将定义在syscall.h中的SYS_trace编号存入寄存器a7, 通过ecall命令进入内核态。 sub entry { my $name = shift; print ".global $name\n"; print "${name}:\n"; print " li a7, SYS_${name}\n"; print " ecall\n"; print " ret\n"; } entry("trace"); 在syscall.c的syscall函数中通过获取a7寄存器中的编号,找到我们添加的系统调用函数,sys_trace。 函数具体实现如下: // 在proc结构体中增加mask成员 struct proc { //... int mask; } // 将user space传入的mask,传递给当前进程的mask变量 uint64 sys_trace(void) { if(argint(0, &myproc()->mask) < 0) return -1; return 0; } // 随后执行的系统调用number如果 (1 << num == mask), 则打印 syscall(void) { // ....

2024-01-04 · 1 min

xv6_chapter1 Operating system interfaces

XV6 实现的所有系统调用: int fork() //Create a process, return child’s PID. void exit(int status) //Terminate the current process; status reported to wait(). No return. int wait(int *status) //Wait for a child to exit; exit status in *status; returns child PID. int kill(int pid) //Terminate process PID. Returns 0, or -1 for error. int getpid() //Return the current process’s PID. int sleep(int n) //Pause for n clock ticks. int exec(char *file, char *argv[]) //Load a file and execute it with arguments; only returns if error....

2023-12-30 · 3 min

Zephyr -- Pinctrl Subsystem

Device Tree Pinctrl controller节点: 所有可选的支持属性可以查阅/dts/bindings/pinctrl/pincfg-node.yaml,支持配置上下拉,驱动能力等等。具体支持属性要参考soc的yaml文件/dts/bindings/pinctrl/xxx.yaml 当设备节点调用perip0_default的时候,group1~N都会被apply。 /* board-pinctrl.dtsi */ #include <vnd-soc-pkgxx.h> &pinctrl { /* Node with pin configuration for default state */ periph0_default: periph0_default { group1 { /* Mappings: PERIPH0_SIGA -> PX0, PERIPH0_SIGC -> PZ1 */ pinmux = <PERIPH0_SIGA_PX0>, <PERIPH0_SIGC_PZ1>; /* Pins PX0 and PZ1 have pull-up enabled */ bias-pull-up; }; ... groupN { /* Mappings: PERIPH0_SIGB -> PY7 */ pinmux = <PERIPH0_SIGB_PY7>; }; }; }; 使用pinctrl的设备节点: &uart0 { pinctrl-0 = <&uart0_default>; pinctrl-1 = <&uart0_sleep>; pinctrl-names = "default", "sleep"; }; 默认支持default, sleep两种属性,也可以自定义属性,比如slow, fast,这样需要在具体driver中自定义PINCTRL_STATE_XXX, 比如...

2023-12-25 · 3 min