xv6_lab5 COW

Problem xv6 中的 fork() 系统调用会将父进程的所有用户空间内存复制到子进程中,如果父进程很大,复制过程可能会花费很长时间。 更糟糕的是,这项工作通常是多余的:子进程 fork() 后面通常跟着 exec(),会丢弃复制的内存,通常不会使用其中的大部分。 另一方面,如果父进程和子进程都使用复制的页面,并且其中一个或两个都对其进行了写入,则复制确实是必要的。 Analysis 实现 copy-on-write (COW) fork() 的目标是推迟 allocating 和 copying 物理内存页面,直到实际需要复制为止(如果有的话)。 COW fork() 只会为子进程创建一个页表,其中用户内存的 PTE 指向父进程的物理页面。COW fork() 将父进程和子进程中的所有用户 PTE 标记为只读。当任何一个进程尝试写入其中一个 COW 页面时,CPU 都会强制触发 page fault。内核 page fault handler 会检测到这种情况,为发生错误的进程分配 a page of physical memory,将 original page 复制到 new page 中,并修改发生错误的进程中相关的 PTE 指向 new page,此时 PTE 标记为可写。当 page fault handler 返回时,用户进程将能够写入 page。 这边父进程和子进程都需要将 pte 标记为只读,这样在写任意一个进程发生 page fault 时,内核都会分配一个新页,并复制原始页的内容到新页,做到进程隔离。 如果只标记子进程的 pte 为只读,那么如果父进程先写入,则不会触发 page fault,从而不会分配新页,而在原来的页上修改。而此时子进程的 virtual address 还指向原来的页,内容也被修改了。...

2025-07-30 · 3 min

xv6_chapter7 Scheduling

graph TD A[用户进程运行] --> B{时间片到期/系统调用/中断} B --> C[进入内核态 usertrap] C --> D[保存用户寄存器到trapframe] D --> E{需要切换进程?} E -->|是| F[调用yield函数] E -->|否| G[处理完毕返回用户态] F --> H[获取进程锁 p->lock] H --> I[设置进程状态为RUNNABLE] I --> J[调用sched函数] J --> K[检查锁状态和中断状态] K --> L[保存中断状态] L --> M[调用swtch函数进行上下文切换] M --> N[保存当前进程的callee-saved寄存器到p->context] N --> O[恢复调度器的callee-saved寄存器从cpu->context] O --> P[返回到scheduler函数] P --> Q[scheduler循环查找RUNNABLE进程] Q --> R{找到可运行进程?} R -->|否| Q R -->|是| S[设置进程状态为RUNNING] S --> T[再次调用swtch函数] T --> U[保存调度器寄存器到cpu->context] U --> V[恢复新进程寄存器从p->context] V --> W[返回到新进程的内核栈] W --> X[释放进程锁] X --> Y[恢复中断状态] Y --> Z[返回到usertrapret] Z --> AA[恢复用户寄存器从trapframe] AA --> BB[切换到用户页表] BB --> CC[返回用户态继续执行] G --> AA style A fill:#e1f5fe style CC fill:#e8f5e8 style M fill:#fff3e0 style T fill:#fff3e0 style P fill:#f3e5f5 style Q fill:#f3e5f5 重要的数据结构: // 保存内核上下文切换时的寄存器 struct context { uint64 ra; // 返回地址 uint64 sp; // 栈指针 // callee-saved 寄存器 s0-s11 uint64 s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; }; // 每个进程的状态 struct proc { struct spinlock lock; enum procstate state; // 进程状态 struct context context; // 上下文切换时保存的寄存器 struct trapframe *trapframe; // 用户态寄存器保存区 // ....

2025-06-19 · 2 min

CS61A Project2 Cats

Overview 使用如下命令对每个 question 检查正确性: python3 ok -q [question number] -i 使用 ok 系统允许的 debug 打印: print("DEBUG:", x) 运行 cats GUI 系统: python3 cats_gui.py Problem 1 实现 pick 函数,其中函数接受的参数: paragraphs: 表示 paragraphs 的字符串 list select: 一个对字符串的判断函数,return True or False k: 第 k 个满足 select 的 paragraphs 返回 paragraphs 中第 k 个满足 select 的字符串,没有满足的返回空字符串。 def pick(paragraphs, select, k): """Return the Kth paragraph from PARAGRAPHS for which the SELECT returns True. If there are fewer than K such paragraphs, return an empty string....

2024-09-29 · 4 min

CSAPP - Cache Lab

实验说明 在 cache lab 实验中,包含两个部分: 第一部分要求我们写一个 C program 来模拟 cache memory。 第二部分要求我们通过减少 cache miss 来优化一个矩阵转置函数。 对应的文件分别为csim.c, trans.c 可通过make和make clean来编译和删除编译文件。 PartA Writing a Cache Simulator 准备工作 我们利用valgrind生成的 trace files 作为我们 cache simulator 的 input。 格式为[space]operation address, size: I 0400d7d4,8 M 0421c7f0,4 L 04f6b868,8 S 7ff0005c8,8 I 加载指令 L 加载数据 S 存储数据 M 内存数据修改(先加载数据,再存储数据) I 前面不跟空格,L/S/M 前面需要加一个空格。 csim-ref是一个参考的 cache simulator 实现。使用LRU替换算法。 用法: Usage: ./csim-ref [-hv] -s <s> -E <E> -b <b> -t <tracefile>...

2024-08-05 · 3 min

CSAPP - Attack Lab

文件说明 ctarget: An executable program vulnerable to code-injection(CI) attacks. rtarget: An executable program vulnerable to return-oriented-programming(ROP) attacks. cookie.txt: An 8-digit hex code that you will use as a unique identifier in your attack farm.c: 用来生成 ROP 攻击的代码。 hex2raw: 生成攻击字符串的工具。 输入ctarget -h查看帮助信息: Usage: [-hq] ./ctarget -i <infile> -h Print help information -q Don't submit result to server -i <infile> Input file 我们在本地跑的话必须加上-q选项,否则会提示Running on an illegal host错误。 工具使用 hex2raw hex2raw 可以将文本中保存的 ascii 码值转化成字符串。注意每个 ascii 需要以空格分开,可以加注释(注释/* */前后需要空格)。...

2024-07-05 · 10 min

CSAPP - Data Lab

Build ./dlc bits.c: 用来检查是否符合coding guidelines. ./dlc -e bits.c: 显示每个函数用了多少个操作符。 make btest: 编译btest。 make clean Rules Each "Expr" is an expression using ONLY the following: 1. Integer constants 0 through 255 (0xFF), inclusive. You are not allowed to use big constants such as 0xffffffff. 2. Function arguments and local variables (no global variables). 3. Unary integer operations ! ~ 4. Binary integer operations & ^ | + << >> You are expressly forbidden to: 1....

2024-06-25 · 1 min

CSAPP - Bomb Lab

Setup 新建solution.txt保存答案, 运行./bomb solution.txt进行测试。 gdb bomb (gdb) r solution.txt 注意如果solution.txt 每行的结尾需要是LF结尾,否则无法正确解析。 objdump -t bomb > bomb_symbol_table.txt: 生成符号表。 objdump -d bomb > bomb.txt: 生成反汇编文件。 Answer Bomb1 首先根据bomb.txt找到bomb的执行入口main函数。 400e32: e8 67 06 00 00 call 40149e <read_line> # 读取输入的一行 400e37: 48 89 c7 mov %rax,%rdi # 把读取的字符串地址传入%rdi 400e3a: e8 a1 00 00 00 call 400ee0 <phase_1> # 调用phase_1,传入的第一个参数为%rdi 400e3f: e8 80 07 00 00 call 4015c4 <phase_defused> 400e44: bf a8 23 40 00 mov $0x4023a8,%edi 400e49: e8 c2 fc ff ff call 400b10 <puts@plt> 400e4e: e8 4b 06 00 00 call 40149e <read_line> 400e53: 48 89 c7 mov %rax,%rdi 400e56: e8 a1 00 00 00 call 400efc <phase_2> 400e5b: e8 64 07 00 00 call 4015c4 <phase_defused> 400e60: bf ed 22 40 00 mov $0x4022ed,%edi 400e65: e8 a6 fc ff ff call 400b10 <puts@plt> //....

2024-06-13 · 11 min

xv6_lab4 trap

Q1 RISC-V assembly C 代码: int g(int x) { return x+3; } int f(int x) { return g(x); } void main(void) { printf("%d %d\n", f(8)+1, 13); exit(0); } 生成的汇编代码: 000000000000001c <main>: void main(void) { 1c: 1141 addi sp,sp,-16 // 分配栈空间 1e: e406 sd ra,8(sp) // 保存 main 的返回地址,因为接下来要调用 printf 20: e022 sd s0,0(sp) // 保存前一个函数的 frame pointer 22: 0800 addi s0,sp,16 // 现在 frame pointer 要增加 16Bytes printf("%d %d\n", f(8)+1, 13); 24: 4635 li a2,13 26: 45b1 li a1,12 28: 00000517 auipc a0,0x0 2c: 7a050513 addi a0,a0,1952 # 7c8 <malloc+0xe8> // "%d %d\n"字符串地址 30: 00000097 auipc ra,0x0 // ra=pc=0x30 34: 5f8080e7 jalr 1528(ra) # 628 <printf> // 0x30 + 0x5f8 = 0x628 exit(0); 38: 4501 li a0,0 // exit 的参数,传入 0 3a: 00000097 auipc ra,0x0 3e: 274080e7 jalr 628(ra) # 2ae <exit> 1....

2024-06-04 · 3 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