From 32b8a163bbddb6779af7eef5c800aa1c6f62d4bd Mon Sep 17 00:00:00 2001 From: fslongjin Date: Tue, 5 Apr 2022 14:40:26 +0800 Subject: [PATCH] =?UTF-8?q?bug:=20AP=E5=A4=84=E7=90=86=E5=99=A8=E5=8F=91?= =?UTF-8?q?=E7=94=9F=E5=BC=82=E5=B8=B8=E6=97=B6=E6=97=A0=E6=B3=95=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/common/cpu.h | 8 +++- kernel/common/glib.h | 1 + kernel/driver/acpi/acpi.c | 2 +- kernel/driver/interrupt/apic/apic.c | 55 +++++++++++++++++++++---- kernel/driver/interrupt/apic/apic.h | 7 ++++ kernel/exception/gate.h | 33 +++++++-------- kernel/head.S | 4 +- kernel/main.c | 13 ++++-- kernel/process/process.h | 4 +- kernel/smp/smp.c | 63 +++++++++++++++++++++-------- kernel/smp/smp.h | 2 +- run.sh | 2 +- 12 files changed, 143 insertions(+), 51 deletions(-) diff --git a/kernel/common/cpu.h b/kernel/common/cpu.h index 60e369df..bfe5b7d7 100644 --- a/kernel/common/cpu.h +++ b/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]; \ No newline at end of file diff --git a/kernel/common/glib.h b/kernel/common/glib.h index c7a59bd6..ff7a4b73 100644 --- a/kernel/common/glib.h +++ b/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" :: \ diff --git a/kernel/driver/acpi/acpi.c b/kernel/driver/acpi/acpi.c index 9fe5c0ba..f1764eba 100644 --- a/kernel/driver/acpi/acpi.c +++ b/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; } diff --git a/kernel/driver/interrupt/apic/apic.c b/kernel/driver/interrupt/apic/apic.c index dd66c094..920176c8 100644 --- a/kernel/driver/interrupt/apic/apic.c +++ b/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 diff --git a/kernel/driver/interrupt/apic/apic.h b/kernel/driver/interrupt/apic/apic.h index 1949348d..b622b7c1 100644 --- a/kernel/driver/interrupt/apic/apic.h +++ b/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控制器 * diff --git a/kernel/exception/gate.h b/kernel/exception/gate.h index 76353fe1..8deb8778 100644 --- a/kernel/exception/gate.h +++ b/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) { diff --git a/kernel/head.S b/kernel/head.S index 1b434c01..0c0dbdf7 100644 --- a/kernel/head.S +++ b/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: diff --git a/kernel/main.c b/kernel/main.c index af5657fd..329c22ea 100644 --- a/kernel/main.c +++ b/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(); + } //操作系统内核从这里开始执行 diff --git a/kernel/process/process.h b/kernel/process/process.h index 20f8a757..7a388d39 100644 --- a/kernel/process/process.h +++ b/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() diff --git a/kernel/smp/smp.c b/kernel/smp/smp.c index 7f734b11..5937a260 100644 --- a/kernel/smp/smp.c +++ b/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 - // 先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 + 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; + + 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(); } \ No newline at end of file diff --git a/kernel/smp/smp.h b/kernel/smp/smp.h index 0ce8dd3c..8240f334 100644 --- a/kernel/smp/smp.h +++ b/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[]; diff --git a/run.sh b/run.sh index 449465c7..edab4197 100644 --- a/run.sh +++ b/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 \