Zephyr -- Watchdog Driver

Consumer // config watchdog static inline int wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg); // enable watchdog __syscall int wdt_setup(const struct device *dev, uint8_t options); // disable watchdog __syscall int wdt_disable(const struct device *dev); // feed wathdog __syscall int wdt_feed(const struct device *dev, int channel_id); wdt_install_timeout()需要在wdt_setup()之前。 示例code: //samples/drivers/watchdog/src/main.c struct wdt_timeout_cfg wdt_config = { /* Reset SoC when watchdog timer expires. */ .flags = WDT_FLAG_RESET_SOC, /* Expire watchdog after max window */ ....

2024-04-28 · 1 min

Zephyr -- Condition Variables and Semaphores

Condition Variables Concept 条件变量基本上是一个线程队列,当某些执行状态不符合预期时,线程可以将自己放入该队列中。 k_condvar_wait(): Releases the last acquired mutex. Puts the current thread in the condition variable queue. 其他某个线程在更改所述状态时,可以唤醒一个(或多个)等待线程,通过k_condvar_signal() or k_condvar_broadcast(): Re-acquires the mutex previously released. Returns from k_condvar_wait(). Implementation Defining a Condition Variable struct k_condvar my_condvar; k_condvar_init(&my_condvar); // 或 K_CONDVAR_DEFINE(my_condvar); Waiting on a Condition Variable k_mutex_lock(&mutex, K_FOREVER); /* block this thread until another thread signals cond. While * blocked, the mutex is released, then re-acquired before this * thread is woken up and the call returns....

2024-04-26 · 3 min

Zephyr -- Mutex

Mutex Zephyr Mutex有下面几个重要特性: lock count。该线程lock了mutux的次数。为0的时候表示unlock。 owning thread。 当一个线程拥有锁,其他线程在都在等待锁释放。一旦锁释放后,等待时间最长优先级最高的线程将被调度。 Zephyr中ISRs中不允许使用Mutex。 Reetrant Locking Zephyr Mutex是可重入锁,可多次加锁。 这样拥有锁的线程可以访问相关资源,不用管是否上锁。 可重入锁的目的就是防止死锁,导致同一个线程不可重入上锁代码段,目的就是让同一个线程可以重新进入上锁代码段。 Priority Inheritance 优先级继承。如果当前线程拥有锁,此时来了一个优先级更高的线程想获取锁,该线程会开始block等待。 此时系统会把拥有锁的线程优先级提高到和等待的线程相同,来尽快完成临界区的任务。一旦释放了锁,线程优先级又会调回去。 CONFIG_PRIORITY_CEILING用来配置最高提高到的优先级等级,默认为0为无限制。 Implementation Defining a Mutex struct k_mutex my_mutex; k_mutex_init(&my_mutex); //或 K_MUTEX_DEFINE(my_mutex); Locking a Mutex k_mutex_lock(&my_mutex, K_FOREVER); // 无限阻塞等待获取锁 if (k_mutex_lock(&my_mutex, K_MSEC(100)) == 0) { // 等待100ms,没获取到返回 /* mutex successfully locked */ } else { printf("Cannot lock XYZ display\n"); } Unlocking a Mutex k_mutex_unlock(&my_mutex); Futex Futex(fast userspace mutex)是比Mutex更轻量级的互斥访问原语。是一种用于用户空间应用程序的通用同步工具。 int k_futex_wait(struct k_futex *futex, int expected, k_timeout_t timeout) int k_futex_wake(struct k_futex *futex, bool wake_all) API Reference User Space Mutex API 把k_xxx前缀换成sys_xxx,比如sys_mutex_lock()。...

2024-04-11 · 3 min

Zephyr -- Threads

Threads CONFIG_MULTITHREADING打开Zephyr多线程功能。 Zephyr线程有下面几个关键的特性: Stack area。 线程的栈大小可修改。 thread control block k_thread。用来保存线程的一些metadata。 entry point function。线程开始执行运行的函数。 scheduling priority。支持配置调度优先级。 thread option。提供线程的一些特殊配置。 execution mode。Supervisor/User mode。依赖于CONFIG_USERSPACE。 Lifecycle k_thread_create(): 创建线程。 k_thread_join(): 阻塞等待线程终止。 k_thread_abort(): 发生异常情况,线程可以由自己或其他线程来终结。 k_thread_suspend(), k_thread_resume(): 线程suspend后只有通过resume才能重新调度。 Thread States Thread Stack objects 初始化线程栈相关属性,如果线程只在内核运行,用K_KERNEL_STACK_XXX。 如果是user space线程,用K_THREAD_STACK_XXX。 如果CONFIG_USERSPACE没打开,那么K_THREAD_STACK等于K_KERNEL_STACK。 Thread Priorities 优先级数字越小,优先级越高。 cooperative thread可配置的优先级为 -CONFIG_NUM_COOP_PRIORITIES到-1。 preemptible thread可配置的优先级为0到 (CONFIG_NUM_PREEMPT_PRIORITIES-1)。 可见cooperative thread的优先级肯定比preemptible thread高。 Cooperative thread是需要主动交出CPU控制权的,否则会一直执行该线程。 Preemptible thread是根据时间片轮转调度的,会自动切换线程。 Meta-IRQ Priorities // TODO: APIs 创建线程: 方法1: k_tid_t k_thread_create(struct k_thread *new_thread, k_thread_stack_t *stack, size_t stack_size, k_thread_entry_t entry, void *p1, void *p2, void *p3, int prio, uint32_t options, k_timeout_t delay) 线程栈必须使用 K_THREAD_STACK_DEFINE or K_KERNEL_STACK_DEFINE定义。 线程栈大小必须是传入给K_THREAD_STACK or K_KERNEL_STACK宏的大小。或者利用K_THREAD_STACK_SIZEOF()/K_KERNEL_STACK_SIZEOF(),对用K_THREAD_STACK/K_KERNEL_STACK创建线程返回的结构体。 e....

2024-04-11 · 2 min

Operating Systems Three Easy Pieces(OSTEP) - Concurrency

Chapter26 Concurrency: Introduction 线程和进程类似,但多线程程序,共享 address space 和 data。 多线程各自独享寄存器组,切换进程的时候需要上下文切换。 进程上下文切换的时候把上一个进程的寄存器组保存到 PCB(Process Control Block)中,线程切换需要定义一个或更多新的结构体 TCBs(Thread Control Blocks)来保存每个线程的状态。 线程切换 Page table 不用切换,因为线程共享地址空间。 线程拥有自己的栈。 26.1 Why use threads? Parallelism。单线程程序只能利用一个 CPU 核,多线程程序可以并行利用多个 CPU 核,提高效率。 防止 I/O 操作导致程序 block。即使是单核 CPU,多线程程序可以在一个线程执行 I/O 操作的时候,其他线程继续利用 CPU。 如果是 CPU 密集型工作,单核 CPU 跑多线程对效率提升不大 26.2~26.4 Problem of Shared data 创建两个线程,分别对全局变量 counter 加 1e7, 最后结果会不等于 2e7。 #include <stdio.h> #include <pthread.h> #include "common.h" #include "common_threads.h" static volatile int counter = 0; void *mythread(void *arg) { printf("%s: begin\n", (char *) arg); int i; for (i = 0; i < 1e7; i++) counter = counter + 1; printf("%s: done\n", (char *) arg); return NULL; } int main(int argc, char *argv[]) { pthread_t p1, p2; printf("main: begin (counter = %d)\n", counter); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done with both (counter = %d)\n", counter); return 0; } pthread_create: 创建线程。 pthread_join: 阻塞等待线程终止。...

2024-04-01 · 12 min

USB_Reset_Suspend_Resume

Reset 整个reset过程,host需要拉低D+的时间\(T_{DRST}\) 至少 > 10ms。 High-speed capable hubs and devices在reset过程中还会执行一套reset protocol: Hub确认接的设备不是Low-speed, 如果是low-speed,不会有下面的reset握手协议。 Hub把D+拉低,进入SE0状态。 Device检测到SE0: 如果device是从suspend状态进入reset,那么device在不少于2.5us后进行high-speed detection handshake。 如果device是从non-suspend full-speed状态进入reset,那么device需要在2.5us~3ms之间进入handshake。 如果device是从non-suspend high-speed状态进入reset,那么device必须在3ms~3.125ms之间恢复full-spped,通过断开高速终端电阻以及重新接上D+的上拉电阻。接着在100us-875us内开始检测SE0状态,进入handshake。 Device往D-灌电流,形成一个800mv左右的ChripK信号, 该信号保持1~7ms。 Hub检测到ChripK信号后,100us内需要发送三对KJ(k-J-K-J-K-J)。每个单独的J或K都要保持40~60us。KJ对打完之后,在500us内断开D+上拉电阻,使能高速终端电阻,进入高速状态。 Suspend Device有两种进入suspend的方式: 如果连续3帧没有收到SOF包(1ms一帧),device会进入suspend状态。 host driver发送SET_PORT_FEATURE(PORT_SUSPEND)给hub,hub再发送给指定的device。 Resume 从suspend状态resume起来需要保持ChripK状态20ms以上,也有两种方式: Device remote wakeup,device drive K-state 1~15ms。Hub会在1ms内,接管D+, D-,继续产生resume信号直到20ms。 host发送CLEAR_PORT_FEATURE( PORT_SUSPSEND)给hub,hub drive K-state 20ms。 Reference Reset, Suspend, and Resume Commands USB全速设备的挂起、唤醒Resume USB2.0设备从全速模式到高速模式的识别过程及速率协商 USB spec 7.1.7.5~7.1.7.7, 11.9

2024-03-29 · 1 min

Operating Systems Three Easy Pieces(OSTEP) - Memory Virtualization

Chapter14 Memory API 14.2 The malloc() call 分配字符串长度的时候要注意:malloc(strlen(s) + 1),多分配一个byte给\0。strlen函数计算长度不会统计\0。 14.4 Common Errors Not Allocating Enough Memory char *src = "hello"; char *dst = (char *) malloc(strlen(src)); // wrong!!! char *dst = (char *) malloc(strlen(src) + 1); strcpy(dst, src); // work properly strcpy拷贝的时候会把\0也拷贝过去,所以分配长度的时候要strlen()+1。 否则多拷贝的一个byte,会写到heap的其他变量所属的地址,可能会导致fault。 Forgetting to Initialize Allocated Memory malloc分配出来的内存,需要初始化,否则可能是随机内存值。 Forgetting To Free Memory malloc分配出来的内存需要free掉。不然长时间运行的进程会导致内存泄漏。 短时间运行就结束的进程可能不会有这个问题,在进程结束后系统会自动回收内存,但free掉不使用的内存仍然是一个好习惯。 Freeing Memory Before You Are Done With It Freeing Memory Repeatedly Chapter15 Address Translation 地址转换 Chapter16 Segmentation 分段 16....

2024-03-27 · 1 min

Operating Systems Three Easy Pieces(OSTEP) - CPU Virtualization

这篇文章是阅读 OSTEP 3~11 的笔记,主要讲的是 Virtualization 中 Virtualize CPU 的部分。 Chapter4 Process 4.2 Process API 一般 OS 会提供以下的进程 API 来操作进程: Create: 创建进程。 Destroy: 结束进程。 Wait: Wait a process to stop running. 等待进程结束。 Miscellaneous Control: Suspend/Resume… 休眠,唤醒等等。 Status: 查看进程状态。 4.3 Process Creation 首先 OS 将存储在 disk or SSD 的 program 程序加载进 memory 内存。 这边有两种方式,一种是在运行前把 code 和 static data 全部加载进内存。现代操作系统一般会使用第二种方式,懒加载,只加载即将使用的 code 和 data。 分配栈。 分配堆。 分配三个文件描述符,标准输入 0,标准输出 1,错误 2。 4.4 Process Status 进程的状态有:...

2024-03-21 · 5 min

xv6_chapter4 Traps

Lecture gdb调试shell write函数的syscall过程: (gdb) b *0xdec # 在0xde8地址设置断点 (gdb) c (gdb) delete 1 # 删除断点 (gdb) print $pc $1 = (void (*)()) 0xdec (gdb) info r (gdb) x/3i 0xde8 # 打印0xdfe开始的三条指令 0xdfe: li a7,16 0xe00: ecall 0xe04: ret (gdb) p/x $stvec $2 = 0x3ffffff000 # user space virtual address顶部一个page,trampoline page对应kernel trap handler. (gdb) stepi warning Book Traps: system call. 通过ecall进入kernel exception. 除0,invalid virtual address. interrupt. 进入kernel device driver. 根据处理代码不同,可分为三种traps: traps from user space traps from kernel space timer interrupts 4....

2024-02-26 · 2 min

xv6 calling conventions and stack frames RISC-V

caller: not preserved across fn call. 需要调用函数来保存寄存器。参考下面例子中的ra寄存器值。 callee: preserved across fn call. 被调用函数来保存寄存器。

2024-02-25 · 1 min