南京大学 操作系统 课程总结 2022

课程网站课程视频OSTEPCSAPP

Part 1

资料:The Feynman Lectures on PhysicsENIAC Simulator and Related Material

思考 Why - What - How,为什么 - 是什么 - 怎么做

Operating System: A body of software, in fact, that is responsible for making it easy to run programs (even allowing you to seemingly run many at the same time), allowing programs to share memory, enabling programs to interact with devices, and other fun stuff like that. (OSTEP)

关键问题:操作系统如何发展成现在这样的?(硬件、软件)


工具:gdbstrace。(tldrxxd

资料:Vim help fileslogisim.cseven-seg.pyminimal.S

以下代码是 logisim.c 的简化版,实现数字逻辑电路的模拟器。我们可以在 vim 中使用 !gcc % && ./a.out 命令,运行如下代码。代码中使用 X macro 技巧,我们可以使用 !gcc -E % 命令输出宏展开之后的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <unistd.h>

#define REGS_FOREACH(_) _(X) _(Y)
#define RUN_LOGIC X1 = !X && Y; \
Y1 = !X && !Y;
#define DEFINE(X) static int X, X##1;
#define UPDATE(X) X = X##1;
#define PRINT(X) printf(#X " = %d; ", X);

int main() {
REGS_FOREACH(DEFINE);
while (1) { // clock
RUN_LOGIC;
REGS_FOREACH(PRINT);
REGS_FOREACH(UPDATE);
putchar('\n'); sleep(1);
}
}
1
2
3
4
5
6
7
8
9
int main() {                                      
static int X, X1; static int Y, Y1;;
while (1) {
X1 = !X && Y; Y1 = !X && !Y;;
printf("X" " = %d; ", X); printf("Y" " = %d; ", Y);;
X = X1; Y = Y1;;
putchar('\n'); sleep(1);
}
}

程序 seven-seg.py 使用 ANSI escape code 来控制字符的颜色。\033[37m\033[31m 分别表示,将当前和之后的字符设置为白色、红色,而 \033[0m 表示重置设置。\033[2J 表示清空屏幕同时将光标移至左上角,\033[1;1f 表示将光标移至第 1 行和第 1 列(应该是这样,HVP 和 CUP 的区别没看懂)。最后,我们可以使用管道,将 logisim.c 的输出作为 seven-seg.py 的输入,从而模拟数码管的显示(执行 ./a.out | python3 seven-seg.py 命令)。

彩蛋:telnet towel.blinkenlights.nl(命令行电影),ssh sshtron.zachlatta.com(网络游戏)。(使用 ANSI escape code 实现)

关键概念:程序是状态机。可以从以下两个视角,抽象的理解。

  • 源代码视角:状态 = 栈帧列表(每个栈帧都有 PC)+ 全局变量。

  • 二进制视角:状态 = 寄存器 + 内存,程序 = 计算指令 + syscall 指令。

问题:如何构造一个最小的 “Hello, World” 程序?(RTFM,man syscall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <sys/syscall.h>

.globl _start
_start:
movq $SYS_write, %rax // write(
movq $1, %rdi // fd=1,
movq $st, %rsi // buf=st,
movq $(ed - st), %rdx // count=ed-st
syscall // );

movq $SYS_exit, %rax // exit(
movq $1, %rdi // status=1
syscall // );

st:
.ascii "\033[01;31mHello, OS World\033[0m\n"
ed:

南京大学 计算机系统基础 课程实验 2022

实验网站2020 南京大学计算机系统基础习题课

PA0 - 世界诞生的前夜: 开发环境配置

使用 vimtutor 命令启动 vim 教程。

教程:GNU/LinuxMakefileGDBtmuxGitLinux C编程一站式学习

课程:The Missing Semester of Your CS Education

其他:Visualizing Git Concepts with D3

使用 apt-get install 经常遇到 “The following packages have unmet dependencies” 错误,原因是因为依赖的包和现有的包版本冲突,之前我都是手动 apt-get remove,但是经常遇到该问题。STFW 之后,这里推荐的 aptitude 工具比较方便,发生冲突时会询问是否降级。(apt-getaptitudeapt 的区别,是否有必要使用 aptitude讨论。)

使用 make 经常遇到 “No such file or directory” 之类缺失头文件的错误,目前是遇到两种情况。一种是缺失对应的包,直接 apt-get install 即可解决;另一种是有对应的包,但是当前项目中 .mk 文件配置的程序名称和现有名称不一致(例如,配置的是 llvm-config,而现有的是 llvm-config-11),修改 .mk 文件即可解决。

PA1 - 开天辟地的篇章: 最简单的计算机

手册:riscv-isa-manualriscv-elf-psabi-docetcNEMU ISA API

可以在目标命令之前添加 time 命令,从而计算目标命令的执行时间。使用 make 命令的 -j 选项,可以启用多线程编译。make -j4 表示创建 4 个线程并行编译,具体创建多少个线程,可以根据 lscpu 命令查询得到的系统中的 CPU 数量来确定。使用 ccache 工具可以缓存目标文件,从而加速执行 make clean 之后,再次执行 make 的速度。

如何实现宏 IFDEFMUXDEF。其中 IFDEF 表示,如果定义了 CONFIG_DEVICE 宏,才会调用 init_device() 函数。而 MUXDEF 表示,如果定义了 CONFIG_TRACE 宏,则预处理结果为 ON,否则预处理结果为 OFF

1
2
IFDEF(CONFIG_DEVICE, init_device());
MUXDEF(CONFIG_TRACE, "ON", "OFF")

nemu/include/macro.h 文件中有如下定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// macro concatenation
#define concat_temp(x, y) x ## y
#define concat(x, y) concat_temp(x, y)

// macro testing
// See https://stackoverflow.com/questions/26099745/test-if-preprocessor-symbol-is-defined-inside-macro
#define CHOOSE2nd(a, b, ...) b
#define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b)
#define MUX_MACRO_PROPERTY(p, macro, a, b) MUX_WITH_COMMA(concat(p, macro), a, b)

// define placeholders for some property
#define __P_DEF_0 X,
#define __P_DEF_1 X,

// define some selection functions based on the properties of BOOLEAN macro
#define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y)

// simplification for conditional compilation
#define __IGNORE(...)
#define __KEEP(...) __VA_ARGS__

// keep the code if a boolean macro is defined
#define IFDEF(macro, ...) MUXDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__)

我们可以使用如下代码进行测试,同时给出宏展开的步骤。需要注意的是,只有当 CONFIG_DEVICE 被定义为 0 或 1 时,才会执行函数调用。

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

#define CONFIG_DEVICE 1

void init_device() {
printf("Hello, Linux World!\n");
}

int main(void) {
IFDEF(CONFIG_DEVICE, init_device());
return 0;
}
1
2
3
4
5
6
7
8
9
10
IFDEF(CONFIG_DEVICE, init_device());
IFDEF(1, init_device());
MUXDEF(1, __KEEP, __IGNORE)(init_device());
MUX_MACRO_PROPERTY(__P_DEF_, 1, __KEEP, __IGNORE)(init_device());
MUX_WITH_COMMA(concat(__P_DEF_, 1), __KEEP, __IGNORE)(init_device());
MUX_WITH_COMMA(__P_DEF_1, __KEEP, __IGNORE)(init_device());
MUX_WITH_COMMA(X,, __KEEP, __IGNORE)(init_device());
CHOOSE2nd(X, __KEEP, __IGNORE)(init_device());
__KEEP(init_device());
init_device();