/** * @brief 安装 TSS 到 GDT,安装用户代码段、数据段到 GDT * @note 安装后系统 GDT 显示如下: * gdt (base=0x00000000c0000900, limit=55): * gdt[0x0000]= * gdt[0x0008]=Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, Accessed, 32-bit * gdt[0x0010]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed * gdt[0x0018]=Data segment, base=0xc00b8000, limit=0x00007fff, Read/Write, Accessed * gdt[0x0020]=32-Bit TSS (Busy) at 0xc0005560, length 0x0006b * gdt[0x0028]=Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, 32-bit * gdt[0x0030]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write */ #include "tss.h" #include "../kernel/global.h" #include "../lib/kernel/print.h" #include "../lib/string.h" /// @brief TSS implementation static Tss tss; /// @brief 创建 GDT 描述符 /// @param desc_addr 基址 /// @param limit 界限 /// @param attr_low 属性(低位) /// @param attr_high 属性(低位) /// @return GdtDescriptor static GdtDesc make_gdt_desc(uint32_t *desc_addr, uint32_t limit, uint8_t attr_low, uint8_t attr_high); void update_tss_esp(struct task_struct *pthread) { tss.esp0 = (uint32_t *)((uintptr_t)pthread + PG_SIZE); // 0 级线程的 esp0 指向 pthread 的 0 级线程的 ESP } static GdtDesc make_gdt_desc(uint32_t *desc_addr, uint32_t limit, uint8_t attr_low, uint8_t attr_high) { uint32_t desc_base = (uint32_t)(uintptr_t)desc_addr; struct gdt_desc desc; desc.limit_low_word = limit & 0xFFFF; desc.base_low_word = desc_base & 0xFFFF; desc.base_middle_byte = ((desc_base & 0x00ff0000) >> 16); desc.attr_low_byte = (uint8_t)attr_low; desc.limit_high_attr_high = ((uint8_t)(attr_high) + ((limit & 0x000f0000) >> 16)); 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; tss.iomap = tss_size; /* gdt 段基址为 0x900,把 tss 放到第 4 个位置,也就是 0x900+0x20 的位置 */ // 在 gdt 中添加 dpl 为 0 的 TSS 描述符 *((GdtDesc *)0xc0000920) = make_gdt_desc((uint32_t *)&tss, tss_size - 1, TSS_ATTR_LOW, TSS_ATTR_HIGH); // 在 gdt 中添加 dpl 为 3 的数据段和代码段描述符 *((GdtDesc *)0xc0000928) = make_gdt_desc((uint32_t *)0, 0xfffff, GDT_CODE_ATTR_LOW_DPL3, GDT_ATTR_HIGH); *((GdtDesc *)0xc0000930) = make_gdt_desc((uint32_t *)0, 0xfffff, GDT_DATA_ATTR_LOW_DPL3, GDT_ATTR_HIGH); // gdt 的指针,前 2 个字节(16 位)是 gdt 界限 limit,后 4 字节(32位)是 gdt 起始地址 Base uint64_t gdt_operand_ptr = (8 * 7 - 1) | ((uint64_t)(uint32_t)0xc0000900 << 16); // 7 个描述符大小 asm volatile("lgdt %0" ::"m"(gdt_operand_ptr)); asm volatile("ltr %w0" ::"r"(SELECTOR_TSS)); put_str("tss_init and ltr done\n"); }