Forráskód Böngészése

bug: AP处理器发生异常时无法正确处理

fslongjin 2 éve
szülő
commit
32b8a163bb

+ 7 - 1
kernel/common/cpu.h

@@ -2,7 +2,7 @@
 
 #include "glib.h"
 
-#define CPU_NUM 8 
+#define MAX_CPU_NUM 32 // 操作系统支持的最大处理器数量
 
 // cpu支持的最大cpuid指令的基础主功能号
 uint Cpu_cpuid_max_Basic_mop;
@@ -53,3 +53,9 @@ void cpu_cpuid(uint mop, uint sop, uint *eax, uint*ebx, uint*ecx, uint*edx)
  * 
  */
 void cpu_init(void);
+
+struct cpu_core_info
+{
+    uint64_t stack_start;   // 栈基地址
+    uint64_t tss_vaddr; // tss地址
+}cpu_core_info[MAX_CPU_NUM];

+ 1 - 0
kernel/common/glib.h

@@ -16,6 +16,7 @@
 #define cli() __asm__ __volatile__("cli\n\t" :: \
                                        : "memory") //关闭外部中断
 #define nop() __asm__ __volatile__("nop\n\t")
+#define hlt() __asm__ __volatile__("hlt\n\t")
 
 //内存屏障
 #define io_mfence() __asm__ __volatile__("mfence\n\t" :: \

+ 1 - 1
kernel/driver/acpi/acpi.c

@@ -80,7 +80,7 @@ bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_da
     //*(struct acpi_Multiple_APIC_Description_Table_t *)_data = *(struct acpi_Multiple_APIC_Description_Table_t *)_iter_data;
     // 返回MADT的虚拟地址
     *(ul *)_data = (ul)_iter_data;
-    acpi_madt_vaddr = _iter_data;
+    acpi_madt_vaddr = (ul)_iter_data;
     return true;
 }
 

+ 48 - 7
kernel/driver/interrupt/apic/apic.c

@@ -102,6 +102,46 @@ void apic_io_apic_init()
            */
 }
 
+/**
+ * @brief 初始化AP处理器的Local apic
+ *
+ */
+void apic_init_ap_core_local_apic()
+{
+    kinfo("Initializing AP-core's local apic...");
+    uint eax, edx;
+    // 启用xAPIC 和x2APIC
+    __asm__ __volatile__("movq  $0x1b, %%rcx   \n\t" // 读取IA32_APIC_BASE寄存器
+                         "rdmsr  \n\t"
+                         "bts $10,   %%rax  \n\t"
+                         "bts $11,   %%rax   \n\t"
+                         "wrmsr  \n\t"
+                         "movq $0x1b,    %%rcx   \n\t"
+                         "rdmsr  \n\t"
+                         : "=a"(eax), "=d"(edx)::"memory");
+
+    // kdebug("After enable xAPIC and x2APIC: edx=%#010x, eax=%#010x", edx, eax);
+
+    // 检测是否成功启用xAPIC和x2APIC
+    if (eax & 0xc00)
+        kinfo("xAPIC & x2APIC enabled!");
+    // 设置SVR寄存器,开启local APIC、禁止EOI广播
+
+    __asm__ __volatile__("movq $0x80f, %%rcx    \n\t"
+                         "rdmsr  \n\t"
+                         "bts $8, %%rax  \n\t"
+                         "bts $12, %%rax \n\t"
+                         "movq $0x80f, %%rcx    \n\t"
+                         "wrmsr  \n\t"
+                         "movq $0x80f , %%rcx   \n\t"
+                         "rdmsr \n\t"
+                         : "=a"(eax), "=d"(edx)::"memory", "rcx");
+
+    if (eax & 0x100)
+        kinfo("APIC Software Enabled.");
+    if (eax & 0x1000)
+        kinfo("EOI-Broadcast Suppression Enabled.");
+}
 /**
  * @brief 初始化local apic
  *
@@ -114,7 +154,7 @@ void apic_local_apic_init()
 
     cpu_cpuid(1, 0, &a, &b, &c, &d);
 
-    //kdebug("CPUID 0x01, eax:%#010lx, ebx:%#010lx, ecx:%#010lx, edx:%#010lx", a, b, c, d);
+    // kdebug("CPUID 0x01, eax:%#010lx, ebx:%#010lx, ecx:%#010lx, edx:%#010lx", a, b, c, d);
 
     // 判断是否支持APIC和xAPIC
     if ((1 << 9) & d)
@@ -152,7 +192,7 @@ void apic_local_apic_init()
                          "rdmsr  \n\t"
                          : "=a"(eax), "=d"(edx)::"memory");
 
-    //kdebug("After enable xAPIC and x2APIC: edx=%#010x, eax=%#010x", edx, eax);
+    // kdebug("After enable xAPIC and x2APIC: edx=%#010x, eax=%#010x", edx, eax);
 
     // 检测是否成功启用xAPIC和x2APIC
     if (eax & 0xc00)
@@ -174,7 +214,7 @@ void apic_local_apic_init()
     __asm__ __volatile__("movq $0x80f, %%rcx    \n\t"
                          "rdmsr  \n\t"
                          "bts $8, %%rax  \n\t"
-                         "bts $12, %%rax \n\t"
+                         //                         "bts $12, %%rax \n\t"
                          "movq $0x80f, %%rcx    \n\t"
                          "wrmsr  \n\t"
                          "movq $0x80f , %%rcx   \n\t"
@@ -194,7 +234,7 @@ void apic_local_apic_init()
                 :
                 :"memory");
                 */
-    //kdebug("After setting SVR: edx=%#010x, eax=%#010x", edx, eax);
+    // kdebug("After setting SVR: edx=%#010x, eax=%#010x", edx, eax);
 
     if (eax & 0x100)
         kinfo("APIC Software Enabled.");
@@ -205,12 +245,13 @@ void apic_local_apic_init()
     //                          Table 10-6. Local APIC Register Address Map Supported by x2APIC
     // 获取 Local APIC ID
     // 0x802处是x2APIC ID 位宽32bits 的 Local APIC ID register
+    /*
     __asm__ __volatile__("movq $0x802, %%rcx    \n\t"
                          "rdmsr  \n\t"
                          : "=a"(eax), "=d"(edx)::"memory");
-
-    //kdebug("get Local APIC ID: edx=%#010x, eax=%#010x", edx, eax);
-    //kdebug("local_apic_id=%#018lx", *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ID));
+    */
+    // kdebug("get Local APIC ID: edx=%#010x, eax=%#010x", edx, eax);
+    // kdebug("local_apic_id=%#018lx", *(uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_ID));
 
     // 获取Local APIC Version
     // 0x803处是 Local APIC Version register

+ 7 - 0
kernel/driver/interrupt/apic/apic.h

@@ -269,6 +269,13 @@ ul apic_ioapic_read_rte(unsigned char index);
  */
 void apic_ioapic_write_rte(unsigned char index, ul value);
 
+
+/**
+ * @brief 初始化AP处理器的Local apic
+ * 
+ */
+void apic_init_ap_core_local_apic();
+
 /**
  * @brief 初始化apic控制器
  *

+ 17 - 16
kernel/exception/gate.h

@@ -3,7 +3,7 @@
  * @author longjin
  * @brief 门定义
  * @date 2022-01-24
- * 
+ *
  */
 
 #pragma once
@@ -20,11 +20,10 @@ struct gate_struct
     unsigned char x[16];
 };
 
-extern struct desc_struct GDT_Table[]; //GDT_Table是head.S中的GDT_Table
-extern struct gate_struct IDT_Table[]; //IDT_Table是head.S中的IDT_Table
+extern struct desc_struct GDT_Table[]; // GDT_Table是head.S中的GDT_Table
+extern struct gate_struct IDT_Table[]; // IDT_Table是head.S中的IDT_Table
 extern unsigned int TSS64_Table[26];
 
-
 /**
  * @brief 初始化中段描述符表内的门描述符(每个16B)
  * @param gate_selector_addr IDT表项的地址
@@ -35,7 +34,7 @@ extern unsigned int TSS64_Table[26];
 
 void set_gate(ul *gate_selector_addr, ul attr, unsigned char ist, ul *code_addr)
 {
-    ul __d0=0, __d1=0;
+    ul __d0 = 0, __d1 = 0;
     ul tmp_code_addr = *code_addr;
     __d0 = attr << 40; //设置P、DPL、Type
 
@@ -52,14 +51,16 @@ void set_gate(ul *gate_selector_addr, ul attr, unsigned char ist, ul *code_addr)
 
     __d1 = (0xffffffff & tmp_code_addr); //设置段内偏移[63:32]
 
-
     *gate_selector_addr = __d0;
     *(gate_selector_addr + 1) = __d1;
 }
 
+void set_tss_descriptor(unsigned int n, void *addr)
+{
 
-
-
+    *(unsigned long *)(GDT_Table + n) = (103UL & 0xffff) | (((unsigned long)addr & 0xffff) << 16) | (((unsigned long)addr >> 16 & 0xff) << 32) | ((unsigned long)0x89 << 40) | ((103UL >> 16 & 0xf) << 48) | (((unsigned long)addr >> 24 & 0xff) << 56); /////89 is attribute
+    *(unsigned long *)(GDT_Table + n + 1) = ((unsigned long)addr >> 32 & 0xffffffff) | 0;
+}
 
 /**
  * @brief 加载任务状态段寄存器
@@ -69,48 +70,48 @@ void set_gate(ul *gate_selector_addr, ul attr, unsigned char ist, ul *code_addr)
 #define load_TR(n)                                      \
     do                                                  \
     {                                                   \
-        __asm__ __volatile__("ltr %%ax" ::"a"(n << 3)); \
+        __asm__ __volatile__("ltr %%ax" ::"a"((n)<< 3)); \
     } while (0)
 
 /**
  * @brief 设置中断门
- * 
+ *
  * @param n 中断号
  * @param ist ist
  * @param addr 服务程序的地址
  */
 void set_intr_gate(unsigned int n, unsigned char ist, void *addr)
 {
-    set_gate((ul*)(IDT_Table + n), 0x8E, ist, (ul*)(&addr)); // p=1,DPL=0, type=E
+    set_gate((ul *)(IDT_Table + n), 0x8E, ist, (ul *)(&addr)); // p=1,DPL=0, type=E
 }
 
 /**
  * @brief 设置64位,DPL=0的陷阱门
- * 
+ *
  * @param n 中断号
  * @param ist ist
  * @param addr 服务程序的地址
  */
 void set_trap_gate(unsigned int n, unsigned char ist, void *addr)
 {
-    set_gate((ul*)(IDT_Table + n), 0x8F, ist, (ul*)(&addr)); // p=1,DPL=0, type=F
+    set_gate((ul *)(IDT_Table + n), 0x8F, ist, (ul *)(&addr)); // p=1,DPL=0, type=F
 }
 
 /**
  * @brief 设置64位,DPL=3的陷阱门
- * 
+ *
  * @param n 中断号
  * @param ist ist
  * @param addr 服务程序的地址
  */
 void set_system_trap_gate(unsigned int n, unsigned char ist, void *addr)
 {
-    set_gate((ul*)(IDT_Table + n), 0xEF, ist, (ul*)(&addr)); // p=1,DPL=3, type=F
+    set_gate((ul *)(IDT_Table + n), 0xEF, ist, (ul *)(&addr)); // p=1,DPL=3, type=F
 }
 
 /**
  * @brief 初始化TSS表的内容
- * 
+ *
  */
 void set_TSS64(ul rsp0, ul rsp1, ul rsp2, ul ist1, ul ist2, ul ist3, ul ist4, ul ist5, ul ist6, ul ist7)
 {

+ 2 - 2
kernel/head.S

@@ -381,7 +381,7 @@ switch_seg:
 
     .quad entry64
 
-.global entry64
+
 entry64:
 
     movq $0x10, %rax
@@ -590,7 +590,7 @@ GDT_Table:
     .quad 0x0000f20000000000 // 6 用户64位数据段描述符 0x30
     .quad 0x00cf9a000000ffff // 7 内核32位代码段描述符 0x38
     .quad 0x00cf92000000ffff // 8 内核32位数据段描述符 0x40
-    .fill 10, 8, 0           // 10-11 TSS(跳过了第9段)  重复十次填充8字节的空间,赋值为0
+    .fill 100, 8, 0           // 10-11 TSS(跳过了第9段)  重复十次填充8字节的空间,赋值为0   长模式下,每个TSS长度为128bit
 GDT_END:
 
 GDT_POINTER:

+ 10 - 3
kernel/main.c

@@ -12,6 +12,7 @@
 #include "mm/slab.h"
 #include "process/process.h"
 #include "syscall/syscall.h"
+#include "smp/smp.h"
 
 #include "driver/multiboot2/multiboot2.h"
 #include "driver/acpi/acpi.h"
@@ -148,9 +149,12 @@ void system_initialize()
     load_TR(10); // 加载TR寄存器
     ul tss_item_addr = 0x7c00;
 
-    set_TSS64(_stack_start, _stack_start, _stack_start, tss_item_addr, tss_item_addr,
+    set_TSS64((ul)TSS64_Table, _stack_start, _stack_start, tss_item_addr, tss_item_addr,
               tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr, tss_item_addr);
 
+    cpu_core_info[0].stack_start = _stack_start;
+    cpu_core_info[0].tss_vaddr = (ul)TSS64_Table;
+
     // 初始化中断描述符表
     sys_vector_init();
 
@@ -161,6 +165,9 @@ void system_initialize()
     // 初始化中断模块
     irq_init();
 
+    smp_init();
+
+    hlt();
     // 先初始化系统调用模块
     syscall_init();
 
@@ -170,13 +177,13 @@ void system_initialize()
     // ata_init();
     pci_init();
     ahci_init();
-
-    smp_init();
+    
     // test_slab();
     // test_mm();
 
     //  再初始化进程模块。顺序不能调转
     // process_init();
+    
 }
 
 //操作系统内核从这里开始执行

+ 2 - 2
kernel/process/process.h

@@ -154,7 +154,7 @@ struct thread_struct initial_thread;
 // 初始化 初始进程的union ,并将其链接到.data.init_proc段内
 union proc_union initial_proc_union __attribute__((__section__(".data.init_proc_union"))) = {INITIAL_PROC(initial_proc_union.pcb)};
 
-struct process_control_block *initial_proc[CPU_NUM] = {&initial_proc_union.pcb, 0};
+struct process_control_block *initial_proc[MAX_CPU_NUM] = {&initial_proc_union.pcb, 0};
 
 struct mm_struct initial_mm = {0};
 struct thread_struct initial_thread =
@@ -211,7 +211,7 @@ struct tss_struct
 		.io_map_base_addr = 0                                             \
 	}
 // 为每个核心初始化初始进程的tss
-struct tss_struct initial_tss[CPU_NUM] = {[0 ... CPU_NUM - 1] = INITIAL_TSS};
+struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_TSS};
 
 // 获取当前的pcb
 struct process_control_block *get_current_pcb()

+ 46 - 17
kernel/smp/smp.c

@@ -1,11 +1,14 @@
 #include "smp.h"
 #include "../common/kprint.h"
 #include "../driver/interrupt/apic/apic.h"
-
-extern void apic_local_apic_init();
+#include "../exception/gate.h"
+#include "../common/cpu.h"
+#include "../mm/slab.h"
+#include "../process/process.h"
 
 static struct acpi_Processor_Local_APIC_Structure_t *proc_local_apic_structs[MAX_SUPPORTED_PROCESSOR_NUM];
 static uint32_t total_processor_num = 0;
+int current_starting_cpu = 0;
 
 void smp_init()
 {
@@ -17,31 +20,57 @@ void smp_init()
     for (int i = 0; i < total_processor_num; ++i)
         proc_local_apic_structs[i] = (struct acpi_Processor_Local_APIC_Structure_t *)(tmp_vaddr[i]);
 
-    for (int i = 0; i < total_processor_num; ++i)
-    {
-        kdebug("[core %d] acpi processor UID=%d, APIC ID=%d, flags=%#010lx", i, proc_local_apic_structs[i]->ACPI_Processor_UID, proc_local_apic_structs[i]->ACPI_ID, proc_local_apic_structs[i]->flags);
-    }
-
     //*(uchar *)0x20000 = 0xf4; // 在内存的0x20000处写入HLT指令(AP处理器会执行物理地址0x20000的代码)
     // 将引导程序复制到物理地址0x20000处
     memcpy((unsigned char *)0x20000, _apu_boot_start, (unsigned long)&_apu_boot_end - (unsigned long)&_apu_boot_start);
+    wrmsr(0x830, 0xc4500); // init IPI
+
+    struct INT_CMD_REG icr_entry;
+    icr_entry.dest_mode = DEST_PHYSICAL;
+    icr_entry.deliver_status = IDLE;
+    icr_entry.res_1 = 0;
+    icr_entry.level = ICR_LEVEL_DE_ASSERT;
+    icr_entry.trigger = EDGE_TRIGGER;
+    icr_entry.res_2 = 0;
+    icr_entry.res_3 = 0;
 
-    // 先init ipi, 然后连续发送两次start-up IPI
-    // x2APIC下,ICR寄存器地址为0x830
-    // xAPIC下则为0xfee00300(31-0) 0xfee00310 (63-32)
-    wrmsr(0x830, 0xc4500);  // init IPI
-    wrmsr(0x830, 0xc4620);  // start-up IPI
-    wrmsr(0x830, 0xc4620);  // start-up IPI
+    for (int i = 1; i < total_processor_num; ++i) // i从1开始,不初始化bsp
+    {
+        current_starting_cpu = i;
+        kdebug("[core %d] acpi processor UID=%d, APIC ID=%d, flags=%#010lx", i, proc_local_apic_structs[i]->ACPI_Processor_UID, proc_local_apic_structs[i]->ACPI_ID, proc_local_apic_structs[i]->flags);
+        // 为每个AP处理器分配栈空间、tss空间
+        cpu_core_info[i].stack_start = (uint64_t)kmalloc(STACK_SIZE, 0) + STACK_SIZE;
+        cpu_core_info[i].tss_vaddr = (uint64_t)kmalloc(128, 0);
+
+        set_tss_descriptor(10 + (i * 2), (void *)(cpu_core_info[i].tss_vaddr));
+        set_TSS64(cpu_core_info[i].tss_vaddr, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start, cpu_core_info[i].stack_start);
+        kdebug("GDT Table %#018lx, \t %#018lx", GDT_Table[10 + i * 2], GDT_Table[10 + i * 2 + 1]);
+
+        icr_entry.vector = 0x20;
+        icr_entry.deliver_mode = ICR_Start_up;
+        icr_entry.dest_shorthand = ICR_No_Shorthand;
+        icr_entry.destination.x2apic_destination = current_starting_cpu;
+
+        // 先init ipi, 然后连续发送两次start-up IPI
+        // x2APIC下,ICR寄存器地址为0x830
+        // xAPIC下则为0xfee00300(31-0) 0xfee00310 (63-32)
+
+        wrmsr(0x830, *(ul *)&icr_entry); // start-up IPI
+        wrmsr(0x830, *(ul *)&icr_entry); // start-up IPI
+    }
 }
 
 /**
  * @brief AP处理器启动后执行的第一个函数
- * 
+ *
  */
 void smp_ap_start()
 {
     ksuccess("AP core successfully started!");
-    kinfo("Initializing AP's local apic...");
-    apic_local_apic_init();
-    while(1);
+    kdebug("current=%d", current_starting_cpu);
+    load_TR(10 + current_starting_cpu * 2);
+    apic_init_ap_core_local_apic();
+    int a =1/0; // 在这儿会出现异常,cs fs gs ss寄存器会被改变
+    
+    hlt();
 }

+ 1 - 1
kernel/smp/smp.h

@@ -4,7 +4,7 @@
 #include "../driver/acpi/acpi.h"
 #include "../driver/interrupt/apic/apic.h"
 
-#define MAX_SUPPORTED_PROCESSOR_NUM 1024    // 操作系统支持的最大处理器数量
+#define MAX_SUPPORTED_PROCESSOR_NUM 1024    
 
 extern uchar _apu_boot_start[];
 extern uchar _apu_boot_end[];

+ 1 - 1
run.sh

@@ -93,7 +93,7 @@ if [ $flag_can_run -eq 1 ]; then
         bochs -q -f ${bochsrc} -rc ./tools/bochsinit
     else
         qemu-system-x86_64 -cdrom ${iso} -m 512M -smp 2,cores=2,threads=1,sockets=1 \
-        -monitor stdio -s -S -cpu IvyBridge --enable-kvm \
+        -monitor stdio -d cpu_reset,guest_errors -s -S -cpu IvyBridge --enable-kvm \
         -drive id=disk,file=bin/disk.img,if=none \
         -device ahci,id=ahci \
         -device ide-hd,drive=disk,bus=ahci.0    \