2021-05-12 21:53:03 +08:00
|
|
|
|
* 实验随记
|
|
|
|
|
** 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,连续长度10,8字节一单位:x/10g $x29
|
|
|
|
|
|
|
|
|
|
显示寄存器:p/x $x29
|
|
|
|
|
|
|
|
|
|
调用一次:0xffffff0000092100 -> 0xffffff00000920e0 (-32)
|
|
|
|
|
|
|
|
|
|
每次压入 4 个 8 字节
|
|
|
|
|
|
|
|
|
|
*** 练习8
|
|
|
|
|
|
|
|
|
|
函数 disasm:x/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
|
|
|
|
|
|
2021-05-13 00:18:55 +08:00
|
|
|
|
*** 问题1:哪个文件或代码段中指定了 ChCore 物理内存布局
|
2021-05-12 21:53:03 +08:00
|
|
|
|
|
2021-05-13 00:18:55 +08:00
|
|
|
|
**** 编译阶段
|
|
|
|
|
|
|
|
|
|
编译时配置镜像格式的文件为 scripts/linker-aarch64.lds.in
|
|
|
|
|
|
|
|
|
|
**** 运行阶段
|
|
|
|
|
|
|
|
|
|
运行阶段在 kernel/mm.c:L70 的 mm_init 设置各个地址
|
|
|
|
|
|
|
|
|
|
*** 练习1
|
|
|
|
|
|
|
|
|
|
基本思路就是回收的时候一路尝试向上合并,分配的时候找一个更大的块然后一路向下分裂。
|
2021-05-13 20:14:09 +08:00
|
|
|
|
|
|
|
|
|
*** 练习2
|
|
|
|
|
|
|
|
|
|
没啥特别的。不过目前只实现了用户空间的 2k 页分配。
|
|
|
|
|
|
2021-05-15 00:11:01 +08:00
|
|
|
|
好家伙,循环里面忘记用 va_cur 用了 va。但是测试用例竟然过了 →_→
|
|
|
|
|
|
2021-05-13 20:14:09 +08:00
|
|
|
|
*** 练习3
|
|
|
|
|
|
|
|
|
|
boot/mmu.c:L80-106 映射了 KBASE~KBASE+256M
|
|
|
|
|
|
|
|
|
|
boot/mmu.c:L109-110 映射了 KBASE+512M~KBASE+4G
|
|
|
|
|
|
|
|
|
|
因此只需要类似操作,补全中间的 256M 即可。
|
|
|
|
|
|
|
|
|
|
注意的是,寄存器保存的地址是 paddr_t
|
2021-05-13 22:51:39 +08:00
|
|
|
|
|
|
|
|
|
** Lab 3
|
|
|
|
|
|
|
|
|
|
*** Capability
|
|
|
|
|
|
|
|
|
|
好像和 MC、Linux 的 Cap 都不太一样。这里的 Cap 是一个可变的描述符,用来指代一个内核资源。
|
|
|
|
|
|
|
|
|
|
比起 Cap,更像是一个对象表。
|
|
|
|
|
|
|
|
|
|
*** 练习1
|
|
|
|
|
|
|
|
|
|
**** ELF 读入
|
|
|
|
|
|
|
|
|
|
ELF Section、Segment 两个概念。
|
|
|
|
|
|
|
|
|
|
- Section 是程序中的不同节,比如 .text。
|
|
|
|
|
- Segment 是程序中实际分配的不同段,包括多个 Section,可以用 `readelf -l` 查看关系
|
|
|
|
|
|
|
|
|
|
主要操作就是计算偏移与复制。
|
|
|
|
|
|
|
|
|
|
其实连对齐都不用,直接就干上去也行,反正之前页表的时候已经处理了没对齐的情况。
|
|
|
|
|
|
2021-05-18 00:39:56 +08:00
|
|
|
|
一定注意对齐!竟然在后面实验翻车了,段开头是有可能非 4k 对齐的,复制要加上偏移。
|
|
|
|
|
|
|
|
|
|
alloc_section = (char *) phys_to_virt(pmo->start) + (p_vaddr & (PAGE_SIZE - 1));
|
|
|
|
|
|
2021-05-13 22:51:39 +08:00
|
|
|
|
**** 初始化线程上下文
|
|
|
|
|
|
|
|
|
|
照着文字写就行,初始化 TCB
|
|
|
|
|
|
|
|
|
|
**** 切换上下文
|
|
|
|
|
|
|
|
|
|
返回上下文结构体的首地址就行
|
2021-05-13 23:07:46 +08:00
|
|
|
|
|
|
|
|
|
*** 练习2
|
|
|
|
|
|
|
|
|
|
process_create_root、thread_create_main 直接写在注释里面了。
|
2021-05-16 14:00:20 +08:00
|
|
|
|
|
|
|
|
|
*** 练习4
|
|
|
|
|
|
|
|
|
|
见注释
|
|
|
|
|
|
|
|
|
|
*** 练习5
|
|
|
|
|
|
|
|
|
|
基本就是移动参数寄存器然后 svc。注意要先保存 x0 寄存器到另一寄存器。
|
|
|
|
|
|
|
|
|
|
*** 练习7
|
|
|
|
|
|
|
|
|
|
主要原因是 libmain 中跳转都是使用 b 指令(没有填写链接寄存器),因此执行到 main 的 ret 时链接寄存器值为 0,
|
|
|
|
|
程序就返回到 0x0 处执行了。由此触发指令异常。
|
|
|
|
|
|
|
|
|
|
*** 练习8
|
|
|
|
|
|
|
|
|
|
这个是最离谱的。所谓退出其实就是输出里出现了“breakpoint”。实际上程序并不会退出(评测机倒是会)。
|
2021-05-16 17:17:26 +08:00
|
|
|
|
|
|
|
|
|
*** 练习9
|
|
|
|
|
|
|
|
|
|
这个的关键是分配一页。我直接用了 kernel 统一的 kmalloc,反正大小够大肯定是用伙伴堆。
|
|
|
|
|
|
|
|
|
|
正常情况下还需要调用 commit_page_to_pmo 记录具体的分配物理页,要不然无法回收。但是注释说为了简便起见就不做了。
|
|
|
|
|
|
|
|
|
|
顺便吐槽一下开了 Debug 日志就没办法通过样例了,因为 brk 样例触发缺页中断会输出一个 Debug,正好在"0,[Debug]...1,2,..."。
|
2021-05-17 18:51:10 +08:00
|
|
|
|
|
|
|
|
|
** Lab 4
|
|
|
|
|
|
|
|
|
|
*** 练习1
|
|
|
|
|
|
|
|
|
|
基本流程其实类似。但是对于其他 cpu 并不是单纯死循环,而是等待 bss 段清空、切换权限等级、等待多核准备完成最后进入 c 入口。
|
|
|
|
|
|
|
|
|
|
*** 练习3
|
|
|
|
|
|
|
|
|
|
boot 阶段的栈是独立的。函数也没调用几个,我猜测可能是 el1_mmu_activate 函数的问题?
|
|
|
|
|
|
|
|
|
|
*** 练习6
|
|
|
|
|
|
|
|
|
|
原因是 unlock_kernel 后才进行从栈恢复,而且函数退出时内核栈还是空的,所以 unlock 的时候无所谓。
|
2021-05-18 00:39:56 +08:00
|
|
|
|
|
|
|
|
|
*** 练习7
|
|
|
|
|
|
|
|
|
|
虽然没提,但是其实状态设置、控制很重要。以及 BUG 异步输出基本和乱码一样,希望加个打印锁……
|
|
|
|
|
|
|
|
|
|
还有一个重点就是 ready_queue 不是结构体开头,所以不可以直接转成 thread *。
|
|
|
|
|
|
|
|
|
|
sys_yield 要注意必须手动调用切换上下文,不然不会有效果。因为默认的 exception_return 不考虑 current_thread。
|
|
|
|
|
|
|
|
|
|
*** 练习8
|
|
|
|
|
|
|
|
|
|
否则将无法再次在该核上进行调度。
|
2021-05-18 18:42:57 +08:00
|
|
|
|
|
|
|
|
|
*** 练习15
|
|
|
|
|
|
|
|
|
|
Step A、B 的代码完全没有删干净,而且 A、B 描述都是反的。所以写完练习 14 就可以直接通过 spawn info 了。
|
|
|
|
|
|
|
|
|
|
我还以为乱码是我又映射错了,结果是代码真的是这么设计的,好吧。
|