什么是陷阱框架? trap frame 和 task_struct 有什么区别?
What is trap frame? And what is difference between trap frame and task_struct?
task_struct用来存储CPU的状态,trap frame做同样的事情,它们有什么区别?而trap frame是一个data struct还是一个just and的概念?
cpu 状态 - 是关于上下文切换的,而 trapframe 在异常或 irq 出现后保存在 tcb 中的用户空间状态。
我的解释将基于self-written OS for raspberry pi 2 (ARMv7)
这是任务结构体,它存储上下文和陷阱帧:
class task {
private:
public:
uint32_t pid;
pde_t *pgd;
tstate state;
uint32_t *kstack;
context *ctx;
trapframe *tf;
task() {};
void init_vm();
int load_binary(char *binary_obj);
};
上下文是一组被调用者保存的寄存器,代表任务在被其他任务抢占(上下文切换)之前的状态
struct context {
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t lr;
};
当调度程序中的上下文切换发生时,当前任务将其寄存器保存到 *ctx in class task
,并从下一个任务加载新的寄存器组:
注意下例中的R0是THIS指针,因为我们调用的是特定对象的方法。所以参数是 R1 和 R2
void scheduler::swtch(struct context **oldctx, struct context *newctx)
{
/* r0-r3 are not preserved during call, no need to save them */
asm volatile("push {r4-r12, lr}");
/* save current kernel thread sp to oldctx */
asm volatile("str r13, [r1]");
/* Load newctx (new sp) to sp register */
asm volatile("mov r13, r2");
/* Load all other registers from new ctx,
* refer struct context format for details */
asm volatile("pop {r4-r12, lr}");
}
现在关于 trapframe:
struct trapframe {
uint32_t sp_usr; // user mode sp
uint32_t lr_usr; // user mode lr
uint32_t sp_svc;
uint32_t lr_svc;
uint32_t spsr;
uint32_t r[N_GEN_REGS];
uint32_t pc; // (lr on entry) instruction to resume execution
};
Trapframe 存储在异常期间保存的寄存器集,因此使用 trapframe 我们可以 return 返回并继续执行(当异常或 irq 将被处理时)
澄清一下,task_struct
包含进程的信息,而不是 cpu。 OS 可以管理多个进程,因此 task_struct
可能有多个实例
Trapframe
保存用户空间寄存器。当 cpu 从用户模式更改为内核模式(例如 supervisor mode in xv6-riscv)时,它会保存用户空间寄存器。
trapframe当然是数据结构了
您可以在下面的 link 中查看 trapframe 的外观,请参阅 proc.h
和 proc.c
task_struct用来存储CPU的状态,trap frame做同样的事情,它们有什么区别?而trap frame是一个data struct还是一个just and的概念?
cpu 状态 - 是关于上下文切换的,而 trapframe 在异常或 irq 出现后保存在 tcb 中的用户空间状态。
我的解释将基于self-written OS for raspberry pi 2 (ARMv7)
这是任务结构体,它存储上下文和陷阱帧:
class task {
private:
public:
uint32_t pid;
pde_t *pgd;
tstate state;
uint32_t *kstack;
context *ctx;
trapframe *tf;
task() {};
void init_vm();
int load_binary(char *binary_obj);
};
上下文是一组被调用者保存的寄存器,代表任务在被其他任务抢占(上下文切换)之前的状态
struct context {
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t lr;
};
当调度程序中的上下文切换发生时,当前任务将其寄存器保存到 *ctx in class task
,并从下一个任务加载新的寄存器组:
注意下例中的R0是THIS指针,因为我们调用的是特定对象的方法。所以参数是 R1 和 R2
void scheduler::swtch(struct context **oldctx, struct context *newctx)
{
/* r0-r3 are not preserved during call, no need to save them */
asm volatile("push {r4-r12, lr}");
/* save current kernel thread sp to oldctx */
asm volatile("str r13, [r1]");
/* Load newctx (new sp) to sp register */
asm volatile("mov r13, r2");
/* Load all other registers from new ctx,
* refer struct context format for details */
asm volatile("pop {r4-r12, lr}");
}
现在关于 trapframe:
struct trapframe {
uint32_t sp_usr; // user mode sp
uint32_t lr_usr; // user mode lr
uint32_t sp_svc;
uint32_t lr_svc;
uint32_t spsr;
uint32_t r[N_GEN_REGS];
uint32_t pc; // (lr on entry) instruction to resume execution
};
Trapframe 存储在异常期间保存的寄存器集,因此使用 trapframe 我们可以 return 返回并继续执行(当异常或 irq 将被处理时)
澄清一下,task_struct
包含进程的信息,而不是 cpu。 OS 可以管理多个进程,因此 task_struct
Trapframe
保存用户空间寄存器。当 cpu 从用户模式更改为内核模式(例如 supervisor mode in xv6-riscv)时,它会保存用户空间寄存器。
trapframe当然是数据结构了
您可以在下面的 link 中查看 trapframe 的外观,请参阅 proc.h
和 proc.c