ChCore-exercise/note.org
2021-05-18 18:42:57 +08:00

220 lines
6.6 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

* 实验随记
** Lab 1
*** 练习3
入口就是boot/start.S的_start。
mrs 读取程序状态字寄存器 mpidr_el1
掩码计算处理器位
用 cbz 跳转主核心至主核心代码,剩下代码忙等 secondary_hang
*** 练习4
#+begin_src
Idx Name Size VMA LMA File off Algn
0 init 0000b5b0 0000000000080000 0000000000080000 00010000 2**12
CONTENTS, ALLOC, LOAD, CODE
1 .text 000011dc ffffff000008c000 000000000008c000 0001c000 2**3
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 000000f8 ffffff0000090000 0000000000090000 00020000 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .bss 00008000 ffffff0000090100 0000000000090100 000200f8 2**4
ALLOC
4 .comment 00000032 0000000000000000 0000000000000000 000200f8 2**0
CONTENTS, READONLY
#+end_src
因为内核代码高地址 0xffffff所以 VMA 不同。
使用 MMU 处理这个映射,位于 boot/mmu.c L126-130。
*** 练习6
初始化 fp sp 位于 start_kernel 函数kernel/head.S
内核栈在 main.c 里定义build/kernel.sym 可以查到地址
内核预先分配栈的总大小sp = 栈位置 + 大小)
*** 练习7
使用 info 指令查看地址info address stack_test
断点设置b stack_test / b *0xffffff000008c020
sp 寄存器
FP 寄存器:约定俗成通用寄存器倒数第三:$x29
打印内存,地址是 $x29连续长度108字节一单位x/10g $x29
显示寄存器p/x $x29
调用一次0xffffff0000092100 -> 0xffffff00000920e0 -32
每次压入 4 个 8 字节
*** 练习8
函数 disasmx/30i stack_test
#+begin_src asm
stp x29, x30, [sp, #-32]! ; 开栈帧,保存调用方 FP、LR
mov x29, sp ; 设置 FP = 新SP = 老SP - 32
str x19, [sp, #16] ; 保存寄存器 r19
#+end_src
官方的调用约定https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#611general-purpose-registers
因为这里函数没有局部变量,所以 FP = SP
**** 栈状态
========被调用方栈========
[SP] ---->
栈上数据(这里没有)
[FP] ---->
上一栈帧FP
返回地址LR
----------
局部变量(这里没有)
----------
保存的寄存器(恰好有调用方函数的调用参数,因为调用方传参是寄存器,而这里保存了下来)
空(可能是对齐)
========调用方栈========
上一栈帧栈上数据
-------------
FP
LR
保存的寄存器(之前函数的调用参数)
**** 实验中显然调用参数是通过寄存器传送的,怎么能打印出参数呢?
其实参数就在下个栈帧保存的之前的寄存器状态中。
** Lab 2
*** 问题1哪个文件或代码段中指定了 ChCore 物理内存布局
**** 编译阶段
编译时配置镜像格式的文件为 scripts/linker-aarch64.lds.in
**** 运行阶段
运行阶段在 kernel/mm.c:L70 的 mm_init 设置各个地址
*** 练习1
基本思路就是回收的时候一路尝试向上合并,分配的时候找一个更大的块然后一路向下分裂。
*** 练习2
没啥特别的。不过目前只实现了用户空间的 2k 页分配。
好家伙,循环里面忘记用 va_cur 用了 va。但是测试用例竟然过了 →_
*** 练习3
boot/mmu.c:L80-106 映射了 KBASE~KBASE+256M
boot/mmu.c:L109-110 映射了 KBASE+512M~KBASE+4G
因此只需要类似操作,补全中间的 256M 即可。
注意的是,寄存器保存的地址是 paddr_t
** Lab 3
*** Capability
好像和 MC、Linux 的 Cap 都不太一样。这里的 Cap 是一个可变的描述符,用来指代一个内核资源。
比起 Cap更像是一个对象表。
*** 练习1
**** ELF 读入
ELF Section、Segment 两个概念。
- Section 是程序中的不同节,比如 .text。
- Segment 是程序中实际分配的不同段,包括多个 Section可以用 `readelf -l` 查看关系
主要操作就是计算偏移与复制。
其实连对齐都不用,直接就干上去也行,反正之前页表的时候已经处理了没对齐的情况。
一定注意对齐!竟然在后面实验翻车了,段开头是有可能非 4k 对齐的,复制要加上偏移。
alloc_section = (char *) phys_to_virt(pmo->start) + (p_vaddr & (PAGE_SIZE - 1));
**** 初始化线程上下文
照着文字写就行,初始化 TCB
**** 切换上下文
返回上下文结构体的首地址就行
*** 练习2
process_create_root、thread_create_main 直接写在注释里面了。
*** 练习4
见注释
*** 练习5
基本就是移动参数寄存器然后 svc。注意要先保存 x0 寄存器到另一寄存器。
*** 练习7
主要原因是 libmain 中跳转都是使用 b 指令(没有填写链接寄存器),因此执行到 main 的 ret 时链接寄存器值为 0
程序就返回到 0x0 处执行了。由此触发指令异常。
*** 练习8
这个是最离谱的。所谓退出其实就是输出里出现了“breakpoint”。实际上程序并不会退出评测机倒是会
*** 练习9
这个的关键是分配一页。我直接用了 kernel 统一的 kmalloc反正大小够大肯定是用伙伴堆。
正常情况下还需要调用 commit_page_to_pmo 记录具体的分配物理页,要不然无法回收。但是注释说为了简便起见就不做了。
顺便吐槽一下开了 Debug 日志就没办法通过样例了,因为 brk 样例触发缺页中断会输出一个 Debug正好在"0,[Debug]...1,2,..."。
** Lab 4
*** 练习1
基本流程其实类似。但是对于其他 cpu 并不是单纯死循环,而是等待 bss 段清空、切换权限等级、等待多核准备完成最后进入 c 入口。
*** 练习3
boot 阶段的栈是独立的。函数也没调用几个,我猜测可能是 el1_mmu_activate 函数的问题?
*** 练习6
原因是 unlock_kernel 后才进行从栈恢复,而且函数退出时内核栈还是空的,所以 unlock 的时候无所谓。
*** 练习7
虽然没提,但是其实状态设置、控制很重要。以及 BUG 异步输出基本和乱码一样,希望加个打印锁……
还有一个重点就是 ready_queue 不是结构体开头,所以不可以直接转成 thread *。
sys_yield 要注意必须手动调用切换上下文,不然不会有效果。因为默认的 exception_return 不考虑 current_thread。
*** 练习8
否则将无法再次在该核上进行调度。
*** 练习15
Step A、B 的代码完全没有删干净,而且 A、B 描述都是反的。所以写完练习 14 就可以直接通过 spawn info 了。
我还以为乱码是我又映射错了,结果是码真的是这么设计的,好吧。