tss.c 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /**
  2. * @brief 安装 TSS 到 GDT,安装用户代码段、数据段到 GDT
  3. * @note 安装后系统 GDT 显示如下:
  4. * gdt (base=0x00000000c0000900, limit=55):
  5. * gdt[0x0000]=<null entry>
  6. * gdt[0x0008]=Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, Accessed, 32-bit
  7. * gdt[0x0010]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
  8. * gdt[0x0018]=Data segment, base=0xc00b8000, limit=0x00007fff, Read/Write, Accessed
  9. * gdt[0x0020]=32-Bit TSS (Busy) at 0xc0005560, length 0x0006b
  10. * gdt[0x0028]=Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, 32-bit
  11. * gdt[0x0030]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
  12. */
  13. #include "tss.h"
  14. #include "../kernel/global.h"
  15. #include "../lib/kernel/print.h"
  16. #include "../lib/string.h"
  17. /// @brief TSS implementation
  18. static Tss tss;
  19. /// @brief 创建 GDT 描述符
  20. /// @param desc_addr 基址
  21. /// @param limit 界限
  22. /// @param attr_low 属性(低位)
  23. /// @param attr_high 属性(低位)
  24. /// @return GdtDescriptor
  25. static GdtDesc make_gdt_desc(uint32_t *desc_addr, uint32_t limit, uint8_t attr_low, uint8_t attr_high);
  26. void update_tss_esp(struct task_struct *pthread)
  27. {
  28. tss.esp0 = (uint32_t *)((uintptr_t)pthread + PG_SIZE); // 0 级线程的 esp0 指向 pthread 的 0 级线程的 ESP
  29. }
  30. static GdtDesc make_gdt_desc(uint32_t *desc_addr, uint32_t limit, uint8_t attr_low, uint8_t attr_high)
  31. {
  32. uint32_t desc_base = (uint32_t)(uintptr_t)desc_addr;
  33. struct gdt_desc desc;
  34. desc.limit_low_word = limit & 0xFFFF;
  35. desc.base_low_word = desc_base & 0xFFFF;
  36. desc.base_middle_byte = ((desc_base & 0x00ff0000) >> 16);
  37. desc.attr_low_byte = (uint8_t)attr_low;
  38. desc.limit_high_attr_high = ((uint8_t)(attr_high) + ((limit & 0x000f0000) >> 16));
  39. desc.base_high_byte = desc_base >> 24;
  40. return desc;
  41. }
  42. /* 在 GDT 中创建 tss 并加载 gdt */
  43. void tss_init(void)
  44. {
  45. put_str("tss_init start\n");
  46. uint32_t tss_size = sizeof(tss);
  47. _memset(&tss, 0, tss_size);
  48. tss.ss0 = SELECTOR_K_STACK;
  49. tss.iomap = tss_size;
  50. /* gdt 段基址为 0x900,把 tss 放到第 4 个位置,也就是 0x900+0x20 的位置 */
  51. // 在 gdt 中添加 dpl 为 0 的 TSS 描述符
  52. *((GdtDesc *)0xc0000920) = make_gdt_desc((uint32_t *)&tss, tss_size - 1, TSS_ATTR_LOW, TSS_ATTR_HIGH);
  53. // 在 gdt 中添加 dpl 为 3 的数据段和代码段描述符
  54. *((GdtDesc *)0xc0000928) = make_gdt_desc((uint32_t *)0, 0xfffff, GDT_CODE_ATTR_LOW_DPL3, GDT_ATTR_HIGH);
  55. *((GdtDesc *)0xc0000930) = make_gdt_desc((uint32_t *)0, 0xfffff, GDT_DATA_ATTR_LOW_DPL3, GDT_ATTR_HIGH);
  56. // gdt 的指针,前 2 个字节(16 位)是 gdt 界限 limit,后 4 字节(32位)是 gdt 起始地址 Base
  57. uint64_t gdt_operand_ptr = (8 * 7 - 1) | ((uint64_t)(uint32_t)0xc0000900 << 16); // 7 个描述符大小
  58. asm volatile("lgdt %0" ::"m"(gdt_operand_ptr));
  59. asm volatile("ltr %w0" ::"r"(SELECTOR_TSS));
  60. put_str("tss_init and ltr done\n");
  61. }