Ver código fonte

定义并初始化化 TSS

simon 1 ano atrás
pai
commit
539d256ffc
7 arquivos alterados com 189 adições e 3 exclusões
  1. 60 0
      kernel/global.h
  2. 2 0
      kernel/init.c
  3. 4 1
      makefile
  4. 0 2
      thread/thread.c
  5. 1 0
      thread/thread.h
  6. 71 0
      userprog/tss.c
  7. 51 0
      userprog/tss.h

+ 60 - 0
kernel/global.h

@@ -2,6 +2,29 @@
 #define __KERNEL_GLOBAL_H
 #include "../lib/stdint.h"
 
+// ---------------------------------------------- GDT 描述符属性 ----------------------------------------------
+#define DESC_G_4K 1
+#define DESC_D_32 1
+#define DESC_L 0   // 64 位代码标记,此处标记为 0 便可
+#define DESC_AVL 0 // cpu 不用此位,暂设置为 0
+#define DESC_P 1
+#define DESC_DPL_0 0
+#define DESC_DPL_1 1
+#define DESC_DPL_2 2
+#define DESC_DPL_3 3
+
+/*********************************************************
+ * 代码段和数据段属于存储段,tss 和各种门描述符属于系统段
+ * s 为 1 时表示存储段,为 0 时表示系统段
+ *********************************************************/
+#define DESC_S_CODE 1           // 存储段
+#define DESC_S_DATA DESC_S_CODE // 存储段
+#define DESC_S_SYS 0            // 系统段
+
+#define DESC_TYPE_CODE 0x8 // 代码段(x=1,c=0,r=0,a=0) 可执行、非依从、不可读、已访问位 a 清 0
+#define DESC_TYPE_DATA 0x2 // 数据段(x=0,e=0,w=1,a=0) 不可执行、向上扩展、可写、已访问位 a 清 0
+#define DESC_TYPE_TSS 0x9  // 任务状态段 B 位为 0, 不忙
+
 #define RPL0 0
 #define RPL1 1
 #define RPL2 2
@@ -16,6 +39,22 @@
 #define SELECTOR_K_DATA ((2 << 3) + (TI_GDT << 2) + RPL0)
 #define SELECTOR_K_STACK SELECTOR_K_DATA
 #define SELECTOR_K_GS ((3 << 3) + (TI_GDT << 2) + RPL0)
+/* 第 3 个段描述符是显存,第 4 个是 tss */
+#define SELECTOR_TSS ((4 << 3) + (TI_GDT << 2) + RPL0) // GDT 中第 4 个
+#define SELECTOR_U_CODE ((5 << 3) + (TI_GDT << 2) + RPL3)
+#define SELECTOR_U_DATA ((6 << 3) + (TI_GDT << 2) + RPL3)
+#define SELECTOR_U_STACK SELECTOR_U_DATA
+
+#define GDT_ATTR_HIGH ((DESC_G_4K << 7) + (DESC_D_32 << 6) + (DESC_L << 5) + (DESC_AVL << 4))
+#define GDT_CODE_ATTR_LOW_DPL3 ((DESC_P << 7) + (DESC_DPL_3 << 5) + (DESC_S_CODE << 4) + DESC_TYPE_CODE)
+#define GDT_DATA_ATTR_LOW_DPL3 ((DESC_P << 7) + (DESC_DPL_3 << 5) + (DESC_S_DATA << 4) + DESC_TYPE_DATA)
+
+/*---------------------- TSS 描述符属性 -----------------------------------------*/
+#define TSS_DESC_D 0
+
+#define TSS_ATTR_HIGH ((DESC_G_4K << 7) + (TSS_DESC_D << 6) + (DESC_L << 5) + (DESC_AVL << 4) + 0x0)
+#define TSS_ATTR_LOW ((DESC_P << 7) + (DESC_DPL_0 << 5) + (DESC_S_SYS << 4) + DESC_TYPE_TSS)
+//! 上面已经定义 #define SELECTOR_TSS ((4 << 3) + (TI_GDT << 2) + RPL0)
 
 /*---------------------- IDT 描述符属性 -----------------------------------------*/
 #define IDT_DESC_P 1
@@ -27,4 +66,25 @@
 #define IDT_DESC_ATTR_DPL0 ((IDT_DESC_P << 7) + (IDT_DESC_DPL0 << 5) + IDT_DESC_32_TYPE)
 #define IDT_DESC_ATTR_DPL3 ((IDT_DESC_P << 7) + (IDT_DESC_DPL3 << 5) + IDT_DESC_32_TYPE)
 
+/* 定义 GDT 中描述符的结构 */
+// ! 段描述符格式
+// !  31~24  23  22  21  20  19~16   15  14~13 12  11~8   7~0
+// !  ----------------------------------------------------------
+// ! |Base | G | D | L |AVL| Limit | P | DPL | S | TYPE | Base |
+// !  ----------------------------------------------------------
+
+// !        31~16                           15~0
+// !  ----------------------------------------------------------
+// ! |         Base                |        Limit              |
+// !  ----------------------------------------------------------
+typedef struct gdt_desc
+{
+    uint16_t limit_low_word; // 低 16 位
+    uint16_t base_low_word;
+    uint8_t base_middle_byte;
+    uint8_t attr_low_byte;
+    uint8_t limit_high_attr_high;
+    uint8_t base_high_byte;
+} GdtDesc;
+
 #endif // __KERNEL_GLOBAL_H

+ 2 - 0
kernel/init.c

@@ -6,6 +6,7 @@
 #include "../device/keyboard.h"
 #include "memory.h"
 #include "../thread/thread.h"
+#include "../userprog/tss.h"
 
 void init_all(void)
 {
@@ -16,4 +17,5 @@ void init_all(void)
     timer_init();    // 初始化定时器
     console_init();  // 初始化 console
     keyboard_init(); // 键盘初始化
+    tss_init();      // tss_init
 }

+ 4 - 1
makefile

@@ -15,7 +15,7 @@ OBJS = $(BUILD_O_DIR)/main.o $(BUILD_O_DIR)/init.o $(BUILD_O_DIR)/interrupt.o  \
 	$(BUILD_O_DIR)/debug.o $(BUILD_O_DIR)/string.o $(BUILD_O_DIR)/bitmap.o  \
 	$(BUILD_O_DIR)/memory.o $(BUILD_O_DIR)/thread.o $(BUILD_O_DIR)/list.o  \
 	$(BUILD_O_DIR)/switch.o $(BUILD_O_DIR)/sync.o $(BUILD_O_DIR)/console.o \
-	$(BUILD_O_DIR)/keyboard.o $(BUILD_O_DIR)/ioqueue.o
+	$(BUILD_O_DIR)/keyboard.o $(BUILD_O_DIR)/ioqueue.o $(BUILD_O_DIR)/tss.o
 
 ################################ C 代码编译 ################################
 $(BUILD_O_DIR)/main.o: kernel/main.c lib/kernel/print.h lib/stdint.h kernel/init.h
@@ -60,6 +60,9 @@ $(BUILD_O_DIR)/keyboard.o: device/keyboard.c device/keyboard.h
 $(BUILD_O_DIR)/ioqueue.o: device/ioqueue.c device/ioqueue.h
 	$(CC) $(CFLAGS) $< -o $@
 
+$(BUILD_O_DIR)/tss.o: userprog/tss.c userprog/tss.h
+	$(CC) $(CFLAGS) $< -o $@
+
 ################################ 汇编代码编译 ################################
 $(BUILD_O_DIR)/kernel.o: kernel/kernel.S
 	$(AS) $(ASFLAGS) $< -o $@

+ 0 - 2
thread/thread.c

@@ -6,8 +6,6 @@
 #include "../lib/kernel/list.h"
 #include "../lib/kernel/print.h"
 
-#define PG_SIZE 4096
-
 struct task_struct *main_thread;     // 主线程 PCB
 struct list thread_ready_list;       // 就绪队列
 struct list thread_all_list;         // 所有任务队列

+ 1 - 0
thread/thread.h

@@ -3,6 +3,7 @@
 #include "../lib/stdint.h"
 #include "../lib/kernel/list.h"
 
+#define PG_SIZE 4096
 // 通用函数类型,它将在很多线程函数中作为参数类型
 typedef void thread_func(void *);
 

+ 71 - 0
userprog/tss.c

@@ -0,0 +1,71 @@
+/**
+ * @brief 安装 TSS 到 GDT,安装用户代码段、数据段到 GDT
+ * @note 安装后系统 GDT 显示如下:
+ *      gdt (base=0x00000000c0000900, limit=55):
+ *      gdt[0x0000]=<null entry>
+ *      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 = (((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;
+    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");
+}

+ 51 - 0
userprog/tss.h

@@ -0,0 +1,51 @@
+#ifndef __USERPROG_TSS_H__
+#define __USERPROG_TSS_H__
+#include "../thread/thread.h"
+#include "../lib/stdint.h"
+
+/**
+ * @file tss.h
+ * @brief Header file for the Task State Segment (TSS) structure.
+ *
+ * This file contains the definition of the TSS structure used in the
+ * operating system kernel's user program module. The TSS is used to
+ * store information about a task, such as stack pointers and segment
+ * selectors, which are essential for task switching in protected mode.
+ */
+typedef 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 trap;
+    uint32_t iomap;
+} Tss;
+
+/// @brief 更新 tss 中 esp0 字段的值为 pthread 的 0 级线程
+/// @param pthread
+void update_tss_esp(struct task_struct *pthread);
+void tss_init(void);
+
+#endif // !__USERPROG_TSS_H__