「BUAA OS Lab3」名词解释

Posted by saltyfishyjk on 2022-04-26
Words 3.8k and Reading Time 20 Minutes
Viewed Times

「BUAA OS Lab3」名词解释

变量和类型

PCB

进程控制块(Process Conotrol Block),系统感知进程存在的唯一标志。进程和PCB一一对应。


Env

1
2
3
4
5
6
7
8
9
10
11
struct Env {
struct Trapframe env_tf; // Saved registers
LIST_ENTRY(Env) env_link; // Free LIST_ENTRY
u_int env_id; // Unique environment identifier
u_int env_parent_id; // env_id of this env's parent
u_int env_status; // Status of the environment
Pde *env_pgdir; // Kernel virtual address of page dir
u_int env_cr3;
LIST_ENTRY(Env) env_sched_link;
u_int env_pri;
};

Env_list

位置:env.h

1
LIST_HEAD(Env_list, Env);

工厂模式构造Env_list类型,内部含有一个struct type *lh_first的变量,相当于构造了头结点类型Env_list


env_tf

env trapframe

Trapframe结构体的定义在include/trap.h中,在发生进程调度或陷入内核中时,会将当时的进程上下文环境保存在env_tf变量中。

Trapframe结构体内容见下。


Trapframe

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Trapframe { //lr:need to be modified(reference to linux pt_regs) TODO
/* Saved main processor registers. */
unsigned long regs[32];

/* Saved special registers. */
unsigned long cp0_status;
unsigned long hi;
unsigned long lo;
unsigned long cp0_badvaddr;
unsigned long cp0_cause;
unsigned long cp0_epc;
unsigned long pc;
};

env_link的机制类似lab2的pp_link,使用env_linkenv_free_list来构造空闲进程链表。


env_id

每个进程都有区别于其他进行的标识符env_id


env_parent_id

创建本进程的进程称为父进程,env_parent_id记录父进程的进程id,借此可以使进程构成进程树。


env_status

该变量只可能取以下三个值之一:

  • ENV_FREE:表明该进程不活动,即,其处于进程空闲链表中
  • ENV_NOT_RUNNABLE:表明该进程处于阻塞状态,需要经过一定条件转为就绪状态,从而才可以被CPU调度
  • ENV_RUNNABLE:表明该进程处于执行状态或就绪状态,即,可能是正在运行的,也可能在等待调度

env_pgdir

env page directory

保存该进程页目录内核虚拟地址


env_cr3

env

保存该进程页目录的物理地址。


env scheduled link

进程调度队列的链表项。

1
LIST_ENTRY(Env) env_sched_link;

env_pri

env priority

保存该进程的优先级。


env_runs

number of times have been runned

1
u_int env_runs;

LOG2NENV

$ log_{2}{NENV} $

1
#define LOG2NENV  10

一共1024个env,因此是10


UTOPULIM

UTOP之下是用户进程可以自由读写的地址区域,ULIM是用户进程的最高地址,在UTOPULIM的区域与其他用户区相比最大的区别是用户只能读,不能写。


cp0_status

cp0_status就是MIPS R3000中的SR(Status Register)寄存器


KUo & IEo // KUp & IEp // KUc & IEc || rfe

KU(Kernel/User)表示是否位于内核模式下,为1表示位于内核模式下

IE(Interrupt Enable)表示中断是否开启,为1表示开启,否则不开启

KUo & IEoo表示old

KUp & IEpp表示previous

KUc & IEcc表示current

这低6位结构式二重栈,共三组。当中断发生时,硬件会自动将KUpIEp的内容拷贝到KUoIEo;将KUcIEc拷贝到KUpIEp中。

rfe(Return From Exception)指令是上述操作的逆操作,guidebook中介绍如下代码是每个进程每一次被调度的时候都会执行的:

1
2
3
4
lw k0, TF_STATUS(k0) # 恢复CP0_STATUS寄存器
mtc0 k0, CP0_STATUS
j k1
rfe

这样可以解释设置status后6位为0的原因:运行进程前,上述代码会运行到rfe,将KUpIEp拷贝回到KUcIEc,这时status变成了 $ 000001 $ ,最后两位KUcIEc为 $ [0, 1] $ ,表示开启了中断。这之后,第一个进程成功运行,我们的操作系统就可以在正常响应中断了。


TIMESTACK

时钟栈,存储时钟中断的时候的trapframe。

1
#define TIMESTACK 0x82000000

exception_handlers

位置:lib/traps.c

异常向量组,在.text.exc.vec3这一异常分发代码结束时会按照exception_handlers这一数组基地址加上Cause寄存器中2-6位得到的ExcCode偏移得到正确的异常处理函数地址。

1
unsigned long exception_handlers[32];

函数和宏函数

env_init()

初始化ene_free_list


mkenvid

返回值:u_int

1
2
3
4
5
u_int mkenvid(struct Env *e) {
u_int idx = e - envs;
u_int asid = asid_alloc();
return (asid << (1 + LOG2NENV)) | (1 << LOG2NENV) | idx;
}

生成一个新的进程标识符。

低10位是idx,即env在envs数组中的索引;第10位是1,为了防止envid为0;11-16位是asid


asid_alloc()

申请一个asid

使用位图法管理asid。

1
2
3
4
5
6
7
8
9
10
11
12
13
static u_int asid_bitmap[2] = {0}; // 位图法管理64个asid
static u_int asid_alloc() {
int i, index, inner;
for (i = 0; i < 64; ++i) {
index = i >> 5; // index标记索引,即具体是哪个asid_bitmap
inner = i & 31; // i&31,即获取低5位,舍弃第6位
if ((asid_bitmap[index] & (1 << inner)) == 0) { // 将管理i对应的位取出,判断是否为0,若为0则说明该asid可以申请。
asid_bitmap[index] |= 1 << inner; // 将对应的位置1,标记这个asid已经被申请
return i;
}
}
panic("too many processes!"); // 若最后也没有找到可以用的asid,返回报错信息
}

envid2env

envid2env(u_int envid, struct Env **penv, int checkperm)

根据envid找到对应的env


env_alloc

返回值:int


env_setup_vm

env_setup_vm(struct Env *e)


env_create

返回值:void

创建进程。以默认优先级申请一个env,实际上是调用env_create_priority

1
2
3
4
5
6
void
env_create(u_char *binary, int size)
{
/* Step 1: Use env_create_priority to alloc a new env with priority 1 */
env_create_priority(binary, size, 1);
}

env_create_priority

返回值:void

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void
env_create_priority(u_char *binary, int size, int priority)
{
struct Env *e;
/* Step 1: Use env_alloc to alloc a new env. */
if (env_alloc(&e, 0) != 0) {
return;
}
/* Step 2: assign priority to the new env. */
e->env_pri = priority;
/* Step 3: Use load_icode() to load the named elf binary,
and insert it into env_sched_list using LIST_INSERT_HEAD. */
load_icode(e, binary, size);
LIST_INSERT_HEAD(&env_sched_list[0], e, env_sched_link);
}

ENV_CREATE

env_create封装起来的宏函数,作用是根据给定参数调用env_create

1
2
3
4
5
6
7
#define ENV_CREATE(x) \
{ \
extern u_char binary_##x##_start[];\
extern u_int binary_##x##_size; \
env_create(binary_##x##_start, \
(u_int)binary_##x##_size); \
}

##是拼接符号,在lab3中我们在init.c中以user_Auser_B为参数分别启动两个进程,可以在/init/code_a.c/init/code_b.c中查看进程的具体配置


ENV_CREATE_PRIORITY

env_create_priority封装起来的宏函数,作用是根据给定参数调用env_create_priority

1
2
3
4
5
6
7
#define ENV_CREATE_PRIORITY(x, y) \
{\
extern u_char binary_##x##_start[]; \
extern u_int binary_##x##_size;\
env_create_priority(binary_##x##_start, \
(u_int)binary_##x##_size, y);\
}

load_icode

返回值:void

特殊类型:static

load image code 加载镜像代码。

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
static void
load_icode(struct Env *e, u_char *binary, u_int size)
{
/* Hint:
* You must figure out which permissions you'll need
* for the different mappings you create.
* Remember that the binary image is an a.out format image,
* which contains both text and data.
*/
struct Page *p = NULL;
u_long entry_point;
u_long r;
u_long perm;

/* Step 1: alloc a page. */
perm = PTE_R;
if ((r = page_alloc(&p)) != 0) {
return;
}
/* Step 2: Use appropriate perm to set initial stack for new Env. */
/* Hint: Should the user-stack be writable? */
if ((r = page_insert(e->env_pgdir, p, USTACKTOP - BY2PG, perm)) != 0) {
return;
}
if ((r = load_elf(binary, size, &entry_point, e, load_icode_mapper)) != 0) {
return;
}

/* Step 3: load the binary using elf loader. */


/* Step 4: Set CPU's PC register as appropriate value. */
e->env_tf.pc = entry_point;
}

load_icode_mapper

返回值:int

特殊类型:static

static int load_icode_mapper(u_long va, u_int32_t sgsize,u_char *bin, u_int32_t bin_size, void *user_data)

位置:lib/env.c

load image code mapper 加载镜像映射


is_elf_format

返回值:int,当判定符合elf格式时返回1,否则返回0

位置:lib/kernel_elfloader.c

1
2
3
4
5
6
7
8
9
10
11
12
int is_elf_format(u_char *binary) {
Elf32_Ehdr *ehdr = (Elf32_Ehdr *) binary;

if (ehdr->e_ident[0] == EI_MAG0 &&
ehdr->e_ident[1] == EI_MAG1 &&
ehdr->e_ident[2] == EI_MAG2 &&
ehdr->e_ident[3] == EI_MAG3) {
return 0;
}

return 1;
}

load_elf

返回值:int

位置:lib/kernenl_elfloader.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
35
36
37
38
39
40
41
42
int load_elf(u_char *binary, int size, u_long *entry_point, void *user_data,
int (*map)(u_long va, u_int32_t sgsize,
u_char *bin, u_int32_t bin_size, void *user_data))
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)binary;
Elf32_Phdr *phdr = NULL;
/* As a loader, we just care about segment,
* so we just parse program headers.
*/
u_char *ptr_ph_table = NULL;
Elf32_Half ph_entry_count;
Elf32_Half ph_entry_size;
int r;

// check whether `binary` is a ELF file.
if (size < 4 || !is_elf_format(binary)) {
return -1;
}

ptr_ph_table = binary + ehdr->e_phoff;
ph_entry_count = ehdr->e_phnum;
ph_entry_size = ehdr->e_phentsize;

while (ph_entry_count--) {
phdr = (Elf32_Phdr *)ptr_ph_table;

if (phdr->p_type == PT_LOAD) {
/* Your task here! */
/* Real map all section at correct virtual address.Return < 0 if error. */
/* Hint: Call the callback function you have achieved before. */
r = map(phdr->p_vaddr, phdr->p_memsz, binary + phdr->p_offset, phdr->p_filesz, user_data);
if (r != 0) {
return r;
}
}

ptr_ph_table += ph_entry_size;
}

*entry_point = ehdr->e_entry;
return 0;
}

kclock_init

位置:lib/kclock.c

初始化时钟,主要调用set_timer


SAVE_ALL

位置:include/stackframe.h


lcontext

汇编函数,更换地址空间,在进程切换时用到

1
2
3
4
5
6
LEAF(lcontext)
.extern mCONTEXT
sw a0,mCONTEXT
jr ra
nop
END(lcontext)

env_pop_tf

位置:lib/env_asm.S

1
extern void env_pop_tf(struct Trapframe *tf, int id);

恢复现场,异常返回

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
58
59
60
61
62
63
LEAF(env_pop_tf)
.set mips1
//1: j 1b
nop
move k0,a0
mtc0 a1,CP0_ENTRYHI


mfc0 t0,CP0_STATUS
ori t0,0x3
xori t0,0x3
mtc0 t0,CP0_STATUS

lw v1,TF_LO(k0)
mtlo v1
lw v0,TF_HI(k0)
lw v1,TF_EPC(k0)
mthi v0
mtc0 v1,CP0_EPC
lw $31,TF_REG31(k0)
lw $30,TF_REG30(k0)
lw $29,TF_REG29(k0)
lw $28,TF_REG28(k0)
lw $25,TF_REG25(k0)
lw $24,TF_REG24(k0)
lw $23,TF_REG23(k0)
lw $22,TF_REG22(k0)
lw $21,TF_REG21(k0)
lw $20,TF_REG20(k0)
lw $19,TF_REG19(k0)
lw $18,TF_REG18(k0)
lw $17,TF_REG17(k0)
lw $16,TF_REG16(k0)
lw $15,TF_REG15(k0)
lw $14,TF_REG14(k0)
lw $13,TF_REG13(k0)
lw $12,TF_REG12(k0)
lw $11,TF_REG11(k0)
lw $10,TF_REG10(k0)
lw $9,TF_REG9(k0)
lw $8,TF_REG8(k0)
lw $7,TF_REG7(k0)
lw $6,TF_REG6(k0)
lw $5,TF_REG5(k0)
lw $4,TF_REG4(k0)
lw $3,TF_REG3(k0)
lw $2,TF_REG2(k0)
lw $1,TF_REG1(k0)

lw k1,TF_PC(k0)

lw k0,TF_STATUS(k0)
nop
mtc0 k0,CP0_STATUS



j k1
rfe # 这里也可以看到进程被调度运行之前一定会执行rfe指令
nop


END(env_pop_tf)

GET_ENV_ASID

对给定的envid,解析ASID

1
#define GET_ENV_ASID(envid) (((envid)>> 11)<<6)

env_run

位置:lib/env.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
void
env_run(struct Env *e)
{
/* Step 1: save register state of curenv. */
/* Hint: if there is an environment running,
* you should switch the context and save the registers.
* You can imitate env_destroy() 's behaviors.*/
if (curenv) {
struct Trapframe *old = (struct Trapframe *)(TIMESTACK - sizeof(struct Trapframe));
bcopy(old, &(curenv->env_tf), sizeof(struct Trapframe));
curenv->env_tf.pc = curenv->env_tf.cp0_epc;
}

/* Step 2: Set 'curenv' to the new environment. */
curenv = e;

/* Step 3: Use lcontext() to switch to its address space. */
lcontext(curenv->env_pgdir);

/* Step 4: Use env_pop_tf() to restore the environment's
* environment registers and return to user mode.
*
* Hint: You should use GET_ENV_ASID there. Think why?
* (read <see mips run linux>, page 135-144)
*/
env_pop_tf(&(curenv->env_tf), GET_ENV_ASID(curenv->env_id));
}

env_destroy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void
env_destroy(struct Env *e)
{
/* Hint: free e. */
env_free(e);

/* Hint: schedule to run a new environment. */
if (curenv == e) {
curenv = NULL;
/* Hint: Why this? */
bcopy((void *)KERNEL_SP - sizeof(struct Trapframe),
(void *)TIMESTACK - sizeof(struct Trapframe),
sizeof(struct Trapframe));
printf("i am killed ... \n");
sched_yield();
}
}

set_except_vector

返回值:void *

1
2
3
4
5
6
void *set_except_vector(int n, void *addr) {
unsigned long handler = (unsigned long) addr;
unsigned long old_handler = exception_handlers[n];
exception_handlers[n] = handler;
return (void *) old_handler;
}

设置异常向量组偏移为n的内容为addr指向的函数;若偏移量为n的地方原来有数,则将其以void *形式返回。

这里我们可以将代码和寄存器结构对应上:

1
2
3
4
5
set_except_vector(0, handle_int);
set_except_vector(1, handle_mod);
set_except_vector(2, handle_tlb);
set_except_vector(3, handle_tlb);
set_except_vector(8, handle_sys);

image-20220509184223967

image-20220509184233622

由此进一步软硬件互相印证。


handle_int

0号异常的处理函数,表示中断,由时钟中断、控制台中断等中断造成。

位置:lib/genex.S

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
NESTED(handle_int, TF_SIZE, sp)
//.set noat

//1: j 1b
nop

SAVE_ALL
CLI
.set at
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2

andi t1, t0, STATUSF_IP4
bnez t1, timer_irq
nop
END(handle_int)

handle_mod

1号异常的处理函数

位置:lib/genex.Slib/traps.c

通过genex.S中的汇编宏函数和traps.c中的代码实现来组合完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.macro	BUILD_HANDLER exception handler clear
.align 5
NESTED(handle_\exception, TF_SIZE, sp)
//.set noat

nop

SAVE_ALL
__build_clear_\clear
.set at
move a0, sp
jal \handler
nop
j ret_from_exception
nop
END(handle_\exception)
.endm
BUILD_HANDLER mod page_fault_handler cli
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}

handle_tlb

位置:lib/genex.S

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.macro	BUILD_HANDLER exception handler clear
.align 5
NESTED(handle_\exception, TF_SIZE, sp)
//.set noat

nop

SAVE_ALL
__build_clear_\clear
.set at
move a0, sp
jal \handler
nop
j ret_from_exception
nop
END(handle_\exception)
.endm
BUILD_HANDLER tlb do_refill cli
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
58
59
60
61
62
63
64
65
66
67
NESTED(do_refill,0 , sp)
//li k1, '?'
//sb k1, 0x90000000
.extern mCONTEXT
//this "1" is important
1: //j 1b
nop
lw k1,mCONTEXT
and k1,0xfffff000
mfc0 k0,CP0_BADVADDR
srl k0,20
and k0,0xfffffffc
addu k0,k1

lw k1,0(k0)
nop
move t0,k1
and t0,0x0200
beqz t0,NOPAGE
nop
and k1,0xfffff000
mfc0 k0,CP0_BADVADDR
srl k0,10
and k0,0xfffffffc
and k0,0x00000fff
addu k0,k1

or k0,0x80000000
lw k1,0(k0)
nop
move t0,k1
and t0,0x0200
beqz t0,NOPAGE
nop
move k0,k1
and k0,0x1
beqz k0,NoCOW
nop
and k1,0xfffffbff
NoCOW:
mtc0 k1,CP0_ENTRYLO0
nop
tlbwr

j 2f
nop
NOPAGE:
//3: j 3b
nop
mfc0 a0,CP0_BADVADDR
lw a1,mCONTEXT
nop

sw ra,tlbra
jal pageout
nop
//3: j 3b
nop
lw ra,tlbra
nop

j 1b
2: nop

jr ra
nop
END(do_refill)

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
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)
addiu t0, t0, 4
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 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 a0, 0(sp)
sw a1, 4(sp)
sw a2, 8(sp)
sw a3, 12(sp)
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)

kclock_init

位置:lib/kclock.c

kernel clock init,时钟初始化

1
2
3
4
void kclock_init(void)
{
set_timer();
}

set_timer

位置:kclock_asm.S

设置时钟

1
2
3
4
5
6
7
8
9
10
LEAF(set_timer)

li t0, 0xc8
sb t0, 0xb5000100
sw sp, KERNEL_SP
setup_c0_status STATUS_CU0|0x1001 0
jr ra

nop
END(set_timer)

timer_irq

timer InterRupt Request,时钟中断请求

1
2
3
4
5
6
7
8
9
10
11
12
timer_irq:

1: j sched_yield
nop
/*li t1, 0xff
lw t0, delay
addu t0, 1
sw t0, delay
beq t0,t1,1f
nop*/
j ret_from_exception
nop

跳转到sched_yield


sched_yield

位置:lib/sched.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
35
36
37
38
39
40
41
42
43
44
45
46
void sched_yield(void)
{
static int count = 0; // remaining time slices of current env
static int point = 0; // current env_sched_list index
static struct Env *e = NULL;
//printf("\ncurenv->env_id : %d\n", e->env_id);
/* hint:
* 1. if (count==0), insert `e` into `env_sched_list[1-point]`
* using LIST_REMOVE and LIST_INSERT_TAIL.
* 2. if (env_sched_list[point] is empty), point = 1 - point;
* then search through `env_sched_list[point]` for a runnable env `e`,
* and set count = e->env_pri
* 3. count--
* 4. env_run()
*
* functions or macros below may be used (not all):
* LIST_INSERT_TAIL, LIST_REMOVE, LIST_FIRST, LIST_EMPTY
*/
if (count == 0 || e == NULL || e->env_status != ENV_RUNNABLE) {
if (e != NULL) {
LIST_REMOVE(e, env_sched_link);
if (e->env_status != ENV_FREE) {
LIST_INSERT_TAIL(&env_sched_list[1 - point], e, env_sched_link);
}
}
while (1) {
while(LIST_EMPTY(&env_sched_list[point])) {
point = 1 - point;
}
e = LIST_FIRST(&env_sched_list[point]);
if (e->env_status == ENV_FREE) {
LIST_REMOVE(e, env_sched_link);
} else if (e->env_status == ENV_NOT_RUNNABLE) {
LIST_REMOVE(e, env_sched_link);
LIST_INSERT_TAIL(&env_sched_list[1 - point], e, env_sched_link);
} else {
count = e->env_pri;
break;
}
}
}
count--;
e->env_runs++;
// printf("\n%d\n",e->env_id);
env_run(e);
}

SAVE_ALL

位置:include/stackframe.h

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
58
59
60
61
62
63
64
65
66
67
.macro SAVE_ALL    
/* 保存SR寄存器 */
mfc0 k0,CP0_STATUS
/* sll 逻辑左移3位,使得CU0在最高位(符号位) */
sll k0,3 /* extract cu0 bit */
/* 判断如果CU0为1跳转到1处 */
/* 1f即标签1,可以参考https://blog.csdn.net/lamdoc/article/details/8979243*/
bltz k0,1f
nop
/*
* Called from user mode, new stack
*/
//lui k1,%hi(kernelsp)
//lw k1,%lo(kernelsp)(k1) //not clear right now

1: /* 保存sp到k0 */
move k0,sp
/* 调用宏get_sp */
get_sp
move k1,sp
subu sp,k1,TF_SIZE
sw k0,TF_REG29(sp)
sw $2,TF_REG2(sp)
mfc0 v0,CP0_STATUS
sw v0,TF_STATUS(sp)
mfc0 v0,CP0_CAUSE
sw v0,TF_CAUSE(sp)
mfc0 v0,CP0_EPC
sw v0,TF_EPC(sp)
mfc0 v0, CP0_BADVADDR
sw v0, TF_BADVADDR(sp)
mfhi v0
sw v0,TF_HI(sp)
mflo v0
sw v0,TF_LO(sp)
sw $0,TF_REG0(sp)
sw $1,TF_REG1(sp)
//sw $2,TF_REG2(sp)
sw $3,TF_REG3(sp)
sw $4,TF_REG4(sp)
sw $5,TF_REG5(sp)
sw $6,TF_REG6(sp)
sw $7,TF_REG7(sp)
sw $8,TF_REG8(sp)
sw $9,TF_REG9(sp)
sw $10,TF_REG10(sp)
sw $11,TF_REG11(sp)
sw $12,TF_REG12(sp)
sw $13,TF_REG13(sp)
sw $14,TF_REG14(sp)
sw $15,TF_REG15(sp)
sw $16,TF_REG16(sp)
sw $17,TF_REG17(sp)
sw $18,TF_REG18(sp)
sw $19,TF_REG19(sp)
sw $20,TF_REG20(sp)
sw $21,TF_REG21(sp)
sw $22,TF_REG22(sp)
sw $23,TF_REG23(sp)
sw $24,TF_REG24(sp)
sw $25,TF_REG25(sp)
sw $26,TF_REG26(sp)
sw $27,TF_REG27(sp)
sw $28,TF_REG28(sp)
sw $30,TF_REG30(sp)
sw $31,TF_REG31(sp)
.endm

get_sp

位置:include/stackframe.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.macro get_sp
mfc0 k1, CP0_CAUSE
andi k1, 0x107C
xori k1, 0x1000
bnez k1, 1f
nop
li sp, 0x82000000
j 2f
nop
1:
bltz sp, 2f
nop
lw sp, KERNEL_SP
nop

2: nop


.endm

This is copyright.