xv6_lab3 pgtbl

Q1 Speed up system call 这个实验的目的是将用户程序的虚拟地址USYSCALL映射到保存有进程pid的物理地址。 这样不用通过系统调用getpid()的方式,直接通过ugetpid()访问虚拟地址就可以直接得到映射的进程pid。 #define USYSCALL (TRAPFRAME - PGSIZE) // USYSCALL位于虚拟地址顶部Trapframe下面一个page int ugetpid(void) { struct usyscall *u = (struct usyscall *)USYSCALL; // 直接访问虚拟地址 return u->pid; } 在struct proc进程结构体中增加struct usyscall *usyscall, 在分配进程函数allocproc中初始化, 分配p->pid给p->usyscall->pid: if ((p->usyscall = (struct usyscall *)kalloc()) == 0) { freeproc(p); release(&p->lock); return 0; } p->usyscall->pid = p->pid; 在给进程分配页表的函数proc_pagetable()中映射指定的虚拟地址。 注意要加上PTE_U p->pagetable = proc_pagetable(p); pagetable_t proc_pagetable(struct proc *p) { // ... // map the USYSCALL just below trapframe....

2024-02-01 · 2 min

Zephyr -- Misc

生成compile_commands.json 执行如下命令, 再编译后, build目录下生成 compile_commands.json, 可以帮忙IDE进行代码的诊断, 补全和跳转: west config build.cmake-args -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 编译过程保留.i文件 west build -- -DCMAKE_C_FLAGS="-save-temps=obj" 会保存到build/目录下各层级的CMakeFiles中。 全局变量分析 利用puncover工具,build完之后运行: west build -t puncover Test命令 编译检查: west twister -p rts5816 -T fingerprint/apps/usbfp 在板子上运行测试(需要host和板子连接): west twister -p rts5816 -T fingerprint/tests --device-testing --device-serial /dev/ttyUSB0 --device-serial-baud 57600 单元测试: west twister -p unit_testing -T fingerprint/tests

2024-01-31 · 1 min

Zephyr -- Kconfig

Setting Kconfig configuration values 生成的配置文件: zephyr/build/.config: for CMake use. zephyr/build/zephyr/include/generated/autoconf.h: for c file use. 所有的Kconfig配置会merge如下路径的Kconfig files: board/<arch>/<BOARD>/<BOARD>_defconfig CMake中定义的CONFIG_XXX Application configuration(APP 目录下的Kconfig相关文件) 第三点Application configuration又会从如下路径获取Kconfig,默认使用prj.conf: 如果定义了CONF_FILE, 会把该文件的Kconfig merge进来。CONF_FILE可以在如下定义 App的CMakeLists.txt, 在find_package(zephyr)前定义。 west直接传入-DCONF_FILE=<conf file(s)> From the CMake variable cache 如果未定义CONF_FILE, 如果存在prj_<BOARD>.conf,merge进prj.conf。 如果存在board/<BOARD>.conf,merge进prj.conf。 如果存在board/<BOARD>_<revision>.conf,merge进prj.conf。 merge必须有的prj.conf。 如果board/下的<BOARD>_defconfig和APP/下的Kconfig冲突了,以APP的为准。

2024-01-31 · 1 min

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

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" }, "[cpp]": { "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" }, "clangd.arguments": [ "--log=error", "--header-insertion=never", // 是否需要自动插入头文件 "--compile-commands-dir=....

2024-01-23 · 2 min

SICP_Chapter1 Building Abstractions with Functions

1.2 Elements of Programming 1.2.6 The Non-Pure Print Function >>> print(print(1), print(2)) 1 2 None None 注意 print(1)和 print(2)的返回值是 None。 1.4 Designning Functions 1.4.1 Documentation docstring。在函数名后在``````中描述函数信息。第一行用来描述函数,接着空一行,接着可以描述参数等。 help(pressure)可以查看函数帮助信息。 >>> def pressure(v, t, n): """Compute the pressure in pascals of an ideal gas. Applies the ideal gas law: http://en.wikipedia.org/wiki/Ideal_gas_law v -- volume of gas, in cubic meters t -- absolute temperature in degrees kelvin n -- particles of gas """ k = 1....

2024-01-22 · 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.1 Abstracting physical resources 2.2 User mode, supervisor mode, and system calls 2.3 Kernel Organization monolithic kernel vs microkernel xv6 和 Unix-like OS 属于 monolithic kernel. 2.4 Code: xv6 organization kernel 接口都在 def.h 中声明. 2.5 Process overview 进程的地址空间: RISC-V 64 只使用 64 位地址中的 39 位, 所以用户空间和内核空间各占 2^39 字节. xv6 只使用 39 位地址中的 38 位, 所以最大地址为 2^38 - 1 = 0x3fffffffff, MAXVA 在 riscv.h 中定义. 每个进程都有两个栈, 一个是内核栈, 一个是用户栈. 2.6 Code: starting xv6, the first process and system call bootloader 把 xv6 kernel code 加载到内存 0x80000000 地址, 首先执行的代码为entry....

2024-01-04 · 2 min