《操作系统真象还原》 第十四篇:定义并初始化TSS

第十四篇:定义并初始化TSS

任务状态段(TSS)的介绍

TSS由程序员提供,由CPU来维护。用于进程切换时,保存进程的上下文环境。

在现代操作系统中,TSS仅用于为0特权级的任务提供栈指针

当CPU由地特权级进入高特权级时,会自动从TSS中获取对应特权级的栈指针

TSS结构如下:

在这里插入图片描述

为了访问到TSS,需要在GDT中注册TSS描述符,并将其选择子写入tr(task register)寄存器

TSS描述符结构如下:

在这里插入图片描述

写入tr寄存器的命令如下:ltr “16位通用寄存器” 或 “16位内存单元”

TSS的定义

//任务状态段tss结构
struct tss {
	uint32_t backlink;
	uint32_t* esp0;
	uint32_t ss0;
	uint32_t* esp1;
	uint32_t ss1;
	uint32_t* esp2;
	uint32_t ss2;
	uint32_t cr3;
	uint32_t (*eip) (void);
	uint32_t eflags;
	uint32_t eax;
	uint32_t ecx;
	uint32_t edx;
	uint32_t ebx;
	uint32_t esp;
	uint32_t ebp;
	uint32_t esi;
	uint32_t edi;
	uint32_t es;
	uint32_t cs;
	uint32_t ss;
	uint32_t ds;
	uint32_t fs;
	uint32_t gs;
	uint32_t ldt;
	uint32_t trace;
	uint32_t io_base;
};

TSS的初始化

//更新tss中的esp0字段的值为pthread的0级栈
void update_tss_esp(struct task_struct* pthread) {
	tss.esp0 = (uint32_t*)((uint32_t)pthread + PG_SIZE);
}

//创建gdt描述符
struct gdt_desc make_gdt_desc(uint32_t* desc_addr, uint32_t limit, uint8_t attr_low, uint8_t attr_high) {
	uint32_t desc_base = (uint32_t)desc_addr;
	struct gdt_desc desc;
	desc.limit_low_word = limit & 0x0000ffff;
	desc.base_low_word = desc_base & 0x0000ffff;
	desc.base_mid_byte = ((desc_base & 0x00ff0000) >> 16);
	desc.attr_low_byte = (uint8_t)(attr_low);
	desc.limit_high_attr_high = ((limit & 0x000f0000) >> 16) + (uint8_t)(attr_high);
	desc.base_high_byte = desc_base >> 24;
	return desc;
}

//在gdt中创建tss并重新加载gdt
void tss_init(void) {
	put_str("tss_init start\n");
	
	uint32_t tss_size = sizeof(tss);
	memset(&tss, 0, tss_size);
	tss.ss0 = SELECTOR_K_STACK;
	//没有io位图
	tss.io_base = tss_size;
	
	//在gdt中添加dpl为0的TSS描述符
	*((struct gdt_desc*)0xc0000920) = make_gdt_desc((uint32_t*)&tss, tss_size - 1, TSS_ATTR_LOW, TSS_ATTR_HIGH);
	
	//在gdt中添加dpl为3的数据段和代码段描述符
	*((struct gdt_desc*)0xc0000928) = make_gdt_desc((uint32_t*)0, 0xfffff, GDT_CODE_ATTR_LOW_DPL3, GDT_ATTR_HIGH);
	
	*((struct gdt_desc*)0xc0000930) = make_gdt_desc((uint32_t*)0, 0xfffff, GDT_DATA_ATTR_LOW_DPL3, GDT_ATTR_HIGH);
	
	uint64_t gdt_ptr = (8 * 7 - 1) | ((uint64_t)(uint32_t)0xc0000900 << 16);
	
	//重新载入gdt指针
	asm volatile ("lgdt %0" : : "m" (gdt_ptr));
	//载入tr寄存器
	asm volatile ("ltr %w0" : : "r" (SELECTOR_TSS));
	
	put_str("tss_init done\n");
}