「BUAA OS Lab4」名词解释

Posted by saltyfishyjk on 2022-05-11
Words 1.5k and Reading Time 8 Minutes
Viewed Times

「BUAA OS Lab4」名词解释

变量和类型

__SYSCALL_BASE

位置:include/unisted.h

系统调用号基址。内核确定是哪类系统调用的唯一依据。

1
#define __SYSCALL_BASE 9527

SYS_putchar

位置:include/unisted.h

1
#define SYS_putchar 		((__SYSCALL_BASE ) + (0 ) )

TF_*

TrapFrame相关宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define TF_REG0		0
#define TF_REG1 ((TF_REG0) + 4)
#define TF_REG2 ((TF_REG1) + 4)
#define TF_REG3 ((TF_REG2) + 4)
#define TF_REG4 ((TF_REG3) + 4)
#define TF_REG5 ((TF_REG4) + 4)
#define TF_REG6 ((TF_REG5) + 4)
#define TF_REG7 ((TF_REG6) + 4)
#define TF_REG8 ((TF_REG7) + 4)
#define TF_REG9 ((TF_REG8) + 4)
#define TF_REG10 ((TF_REG9) + 4)
#define TF_REG11 ((TF_REG10) + 4)
#define TF_REG12 ((TF_REG11) + 4)
#define TF_REG13 ((TF_REG12) + 4)
#define TF_REG14 ((TF_REG13) + 4)
#define TF_REG15 ((TF_REG14) + 4)
#define TF_REG16 ((TF_REG15) + 4)
#define TF_REG17 ((TF_REG16) + 4)
#define TF_REG18 ((TF_REG17) + 4)
#define TF_REG19 ((TF_REG18) + 4)
#define TF_REG20 ((TF_REG19) + 4)
#define TF_REG21 ((TF_REG20) + 4)
#define TF_REG22 ((TF_REG21) + 4)
#define TF_REG23 ((TF_REG22) + 4)
#define TF_REG24 ((TF_REG23) + 4)
#define TF_REG25 ((TF_REG24) + 4)
/*
* $26 (k0) and $27 (k1) not saved
*/
#define TF_REG26 ((TF_REG25) + 4)
#define TF_REG27 ((TF_REG26) + 4)
#define TF_REG28 ((TF_REG27) + 4)
#define TF_REG29 ((TF_REG28) + 4)
#define TF_REG30 ((TF_REG29) + 4)
#define TF_REG31 ((TF_REG30) + 4)

#define TF_STATUS ((TF_REG31) + 4)

#define TF_HI ((TF_STATUS) + 4)
#define TF_LO ((TF_HI) + 4)

#define TF_BADVADDR ((TF_LO)+4)
#define TF_CAUSE ((TF_BADVADDR) + 4)
#define TF_EPC ((TF_CAUSE) + 4)
#define TF_PC ((TF_EPC) + 4)
/*
* Size of stack frame, word/double word alignment
*/
#define TF_SIZE ((TF_PC)+4)

COW

Copy On Write,写时复制。

当fork后的父子进程中有修改内存(一般是数据段或栈)的行为发生时,内核会捕获页写入异常,并哎异常处理时为修改内存的进程的地址空间中相应地址分配新的物理页面。


env

用户进程用以访问自身进程块的指针。其值在fork时会被更新。

位置:user/libos.c


函数和宏函数

handle_sys

位置:lib/syscall.S

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
NESTED(handle_sys,TF_SIZE, sp)
SAVE_ALL // Macro used to save trapframe
CLI // Clean Interrupt Mask
nop
.set at // Resume use of $at

// TODO: Fetch EPC from Trapframe, calculate a proper value and store it back to trapframe.

lw t0, TF_EPC(sp)
lw t1, TF_CAUSE(sp)
lui t2, 0x8000
and t1, t1, t2
bnez t1, IS_BD
nop
addiu t0, t0, 4
j BD_IF_END
nop
IS_BD:
BD_IF_END:
sw t0, TF_EPC(sp)

// TODO: Copy the syscall number into $a0.

lw a0, TF_REG4(sp)

addiu a0, a0, -__SYSCALL_BASE // a0 <- relative syscall number
sll t0, a0, 2 // t0 <- relative syscall number times 4
la t1, sys_call_table // t1 <- syscall table base
addu t1, t1, t0 // t1 <- table entry of specific syscall
lw t2, 0(t1) // t2 <- function entry of specific syscall

lw t0, TF_REG29(sp) // t0 <- user's stack pointer
lw t3, 16(t0) // t3 <- the 5th argument of msyscall
lw t4, 20(t0) // t4 <- the 6th argument of msyscall

// TODO: Allocate a space of six arguments on current kernel stack and copy the six arguments to proper location

lw a0, TF_REG4(sp)
lw a1, TF_REG5(sp)
lw a2, TF_REG6(sp)
lw a3, TF_REG7(sp)
addiu sp, sp, -24
sw t3, 16(sp)
sw t4, 20(sp)

jalr t2 // Invoke sys_* function
nop

// TODO: Resume current kernel stack

addiu sp, sp, 24

sw v0, TF_REG2(sp) // Store return value of function sys_* (in $v0) into trapframe

j ret_from_exception // Return from exeception
nop
END(handle_sys)

msyscall

位置:user/syscall_wrap.S

1
2
3
4
5
6
7
LEAF(msyscall)
// TODO: you JUST need to execute a `syscall` instruction and return from msyscall
syscall
nop
jr ra
nop
END(msyscall)

sys_env_alloc

位置:lib/syscall_all.c

1
2
3
4
5
6
7
8
9
```

***

### `sys_set_env_status`

位置:`lib/syscall_all.c`

```C

sys_set_pgfault_handler

位置:lib/syscall_all.c

设置pgfault handler(异常处理函数)的函数入口和xstacktop(异常处理栈)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int sys_set_pgfault_handler(int sysno, u_int envid, u_int func, u_int xstacktop)
{
// Your code here.
struct Env *env;
int ret;
ret = envid2env(envid, &env, 0);
if (ret) {
return ret;
}
env->env_pgfault_handler = func;
env->env_xstacktop = xstacktop;

return 0;
// panic("sys_set_pgfault_handler not implemented");
}

page_fault_handler

位置:lib/traps.c

负责完成写时复制处理前的相关设置,返回前将cp0_epc指向env_pgfault_handler函数入口。env_pgfault_handler指向的函数就是pgfault,这是真正处理缺页异常的函数。这里我们也可以看到,写时复制的实现依赖于缺页异常实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void
page_fault_handler(struct Trapframe *tf)
{
struct Trapframe PgTrapFrame;
extern struct Env *curenv;

bcopy(tf, &PgTrapFrame, sizeof(struct Trapframe));

if (tf->regs[29] >= (curenv->env_xstacktop - BY2PG) &&
tf->regs[29] <= (curenv->env_xstacktop - 1)) {
tf->regs[29] = tf->regs[29] - sizeof(struct Trapframe);
bcopy(&PgTrapFrame, (void *)tf->regs[29], sizeof(struct Trapframe));
} else {
tf->regs[29] = curenv->env_xstacktop - sizeof(struct Trapframe);
bcopy(&PgTrapFrame,(void *)curenv->env_xstacktop - sizeof(struct Trapframe),sizeof(struct Trapframe));
}
// TODO: Set EPC to a proper value in the trapframe
tf->cp0_epc = curenv->env_pgfault_handler;
return;
}

fork

位置:user/fork.c

创建一个子进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int
fork(void)
{
// Your code here.
u_int newenvid;
extern struct Env *envs;
extern struct Env *env;
u_int i;


//The parent installs pgfault using set_pgfault_handler
set_pgfault_handler(pgfault);
//alloc a new alloc
/* syscall_env_alloc return different values in parent process ans subprocess */
newenvid = syscall_env_alloc();
if (newenvid) {
/* copy address space for subprocess */
for (i = 0; i < VPN(USTACKTOP); i++) {
if (((*vpd)[i >> 10] & PTE_V) && ((*vpt)[i] & PTE_V)) {
duppage(newenvid, i);
}
}
/* alloc user exception stack for subprocess at UXSTACKTOP - BY2PG */
syscall_mem_alloc(newenvid, UXSTACKTOP - BY2PG, PTE_V | PTE_R);
/* set exception handler func for subprocess */
syscall_set_pgfault_handler(newenvid, __asm_pgfault_handler, UXSTACKTOP);
/* set subprocess as RUNNABLE */
syscall_set_env_status(newenvid, ENV_RUNNABLE);
} else { // in subprocess, just return
env = envs + ENVX(syscall_getenvid());
}

return newenvid;
}

pgfault

位置:user/fork.c

page fault

写时复制函数处理函数,是page_fault_handler后续会调用的函数,负责对PTE_COW标志的页面进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static void
pgfault(u_int va)
{
u_int *tmp;
u_long perm;
// writef("fork.c:pgfault():\t va:%x\n",va);

/* get bit 0-11 as perm bits */
perm = (*vpt)[VPN(va)] & (BY2PG - 1);
/* if the page has NOT PTE_COW perm, something might be wrond */
if ((perm & PTE_COW) == 0) {
user_panic("`va` is not a copy-on-write page.");
}
/* remove PTE_COW perm for when this func finished, we have two seperate pages which has no connection with each other */
perm -= PTE_COW;
tmp = USTACKTOP;

//map the new page at a temporary place

syscall_mem_alloc(0, tmp, perm);

//copy the content

user_bcopy(ROUNDDOWN(va, BY2PG), tmp, BY2PG);

//map the page on the appropriate place

syscall_mem_map(0, tmp, 0, va, perm);

//unmap the temporary place

syscall_mem_unmap(0, tmp);
}

duppage

位置:user/fork.c

父进程对子进程页面空间进行映射以及相关标志设置的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
duppage(u_int envid, u_int pn)
{
u_int addr;
u_int perm;

int flag = 0;
addr = pn << PGSHIFT; // PGSHIFT = 12
perm = (*vpt)[pn] & (BY2PG - 1);
if (perm & PTE_R) {
if (!(perm & PTE_LIBRARY)) {
flag = 1;
perm |= PTE_COW;
}
}
syscall_mem_map(0, addr, envid, addr, perm);
if (flag) {
syscall_mem_map(0, addr, 0, addr, perm);
}

// user_panic("duppage not implemented");
}

set_pgfault_handler

位置:user/pgfault.c

父进程为子进程设置页错误处理函数的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void
set_pgfault_handler(void (*fn)(u_int va)) {
if (__pgfault_handler == 0) {
// Your code here:
// map one page of exception stack with top at UXSTACKTOP
// register assembly handler and stack with operating system
if (syscall_mem_alloc(0, UXSTACKTOP - BY2PG, PTE_V | PTE_R) < 0 ||
syscall_set_pgfault_handler(0, __asm_pgfault_handler, UXSTACKTOP) < 0) {
writef("cannot set pgfault handler\n");
return;
}

// panic("set_pgfault_handler not implemented");
}

// Save handler pointer for assembly to call.
__pgfault_handler = fn;
}

文件

entry.S

用户进程的入口


libos.c

用户进程入口的C语言部分,负责完成执行用户程序 umain 前后的准备和清理工作


genex.S

实现了 MOS 的中断处理流程


This is copyright.