1 #include "smp.h"
2 #include <common/cpu.h>
3 #include <common/kprint.h>
4 #include <common/spinlock.h>
5 #include <driver/interrupt/apic/apic.h>
6 #include <exception/gate.h>
7 #include <mm/slab.h>
8 #include <process/process.h>
9 
10 #include <process/preempt.h>
11 #include <sched/sched.h>
12 #include <driver/acpi/acpi.h>
13 #include <driver/interrupt/apic/apic.h>
14 #include "ipi.h"
15 
16 static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs);
17 static void __smp__flush_tlb_ipi_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs);
18 
19 static spinlock_t multi_core_starting_lock = {1}; // 多核启动锁
20 
21 static struct acpi_Processor_Local_APIC_Structure_t *proc_local_apic_structs[MAX_SUPPORTED_PROCESSOR_NUM];
22 static uint32_t total_processor_num = 0;
23 static int current_starting_cpu = 0;
24 
25 static int num_cpu_started = 1;
26 extern void rs_smp_init_idle();
27 
28 // 在head.S中定义的,APU启动时,要加载的页表
29 // 由于内存管理模块初始化的时候,重置了页表,因此我们要把当前的页表传给APU
30 extern uint64_t __APU_START_CR3;
31 
32 // kick cpu 功能所使用的中断向量号
33 #define KICK_CPU_IRQ_NUM 0xc8
34 #define FLUSH_TLB_IRQ_NUM 0xc9
35 
smp_init()36 void smp_init()
37 {
38     spin_init(&multi_core_starting_lock); // 初始化多核启动锁
39     // 设置多核启动时,要加载的页表
40     __APU_START_CR3 = (uint64_t)get_CR3();
41 
42     ul tmp_vaddr[MAX_SUPPORTED_PROCESSOR_NUM] = {0};
43 
44     apic_get_ics(ACPI_ICS_TYPE_PROCESSOR_LOCAL_APIC, tmp_vaddr, &total_processor_num);
45 
46     // kdebug("processor num=%d", total_processor_num);
47     for (int i = 0; i < total_processor_num; ++i)
48     {
49         io_mfence();
50         proc_local_apic_structs[i] = (struct acpi_Processor_Local_APIC_Structure_t *)(tmp_vaddr[i]);
51     }
52 
53     // 将引导程序复制到物理地址0x20000处
54     memcpy((unsigned char *)phys_2_virt(0x20000), _apu_boot_start,
55            (unsigned long)&_apu_boot_end - (unsigned long)&_apu_boot_start);
56     io_mfence();
57     // 设置多核IPI中断门
58     for (int i = 200; i < 210; ++i)
59         set_intr_gate(i, 0, SMP_interrupt_table[i - 200]);
60     memset((void *)SMP_IPI_desc, 0, sizeof(irq_desc_t) * SMP_IRQ_NUM);
61 
62     io_mfence();
63 
64     io_mfence();
65     ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x00, ICR_INIT, ICR_ALL_EXCLUDE_Self, 0x00);
66 
67     kdebug("total_processor_num=%d", total_processor_num);
68     // 注册接收kick_cpu功能的处理函数。(向量号200)
69     ipi_regiserIPI(KICK_CPU_IRQ_NUM, NULL, &__smp_kick_cpu_handler, NULL, NULL, "IPI kick cpu");
70     ipi_regiserIPI(FLUSH_TLB_IRQ_NUM, NULL, &__smp__flush_tlb_ipi_handler, NULL, NULL, "IPI flush tlb");
71 
72     int core_to_start = 0;
73     // total_processor_num = 3;
74     for (int i = 0; i < total_processor_num; ++i) // i从1开始,不初始化bsp
75     {
76         io_mfence();
77 
78         // 跳过BSP
79         kdebug("[core %d] acpi processor UID=%d, APIC ID=%d, flags=%#010lx", i,
80                proc_local_apic_structs[i]->ACPI_Processor_UID, proc_local_apic_structs[i]->local_apic_id,
81                proc_local_apic_structs[i]->flags);
82         if (proc_local_apic_structs[i]->local_apic_id == 0)
83         {
84             // --total_processor_num;
85             continue;
86         }
87         if (!((proc_local_apic_structs[i]->flags & 0x1) || (proc_local_apic_structs[i]->flags & 0x2)))
88         {
89             // --total_processor_num;
90             kdebug("processor %d cannot be enabled.", proc_local_apic_structs[i]->ACPI_Processor_UID);
91             continue;
92         }
93         ++core_to_start;
94         // continue;
95         io_mfence();
96         spin_lock(&multi_core_starting_lock);
97         preempt_enable(); // 由于ap处理器的pcb与bsp的不同,因此ap处理器放锁时,bsp的自旋锁持有计数不会发生改变,需要手动恢复preempt
98                           // count
99         current_starting_cpu = proc_local_apic_structs[i]->ACPI_Processor_UID;
100         io_mfence();
101         // 为每个AP处理器分配栈空间
102         cpu_core_info[current_starting_cpu].stack_start = (uint64_t)kmalloc(STACK_SIZE, 0) + STACK_SIZE;
103         cpu_core_info[current_starting_cpu].ist_stack_start = (uint64_t)(kmalloc(STACK_SIZE, 0)) + STACK_SIZE;
104         io_mfence();
105         memset((void *)cpu_core_info[current_starting_cpu].stack_start - STACK_SIZE, 0, STACK_SIZE);
106         memset((void *)cpu_core_info[current_starting_cpu].ist_stack_start - STACK_SIZE, 0, STACK_SIZE);
107         io_mfence();
108 
109         // 设置ap处理器的中断栈及内核栈中的cpu_id
110         ((struct process_control_block *)(cpu_core_info[current_starting_cpu].stack_start - STACK_SIZE))->cpu_id =
111             proc_local_apic_structs[i]->local_apic_id;
112         ((struct process_control_block *)(cpu_core_info[current_starting_cpu].ist_stack_start - STACK_SIZE))->cpu_id =
113             proc_local_apic_structs[i]->local_apic_id;
114 
115         cpu_core_info[current_starting_cpu].tss_vaddr = (uint64_t)&initial_tss[current_starting_cpu];
116 
117         memset(&initial_tss[current_starting_cpu], 0, sizeof(struct tss_struct));
118         // kdebug("core %d, set tss", current_starting_cpu);
119         set_tss_descriptor(10 + (current_starting_cpu * 2), (void *)(cpu_core_info[current_starting_cpu].tss_vaddr));
120         io_mfence();
121         set_tss64(
122             (uint *)cpu_core_info[current_starting_cpu].tss_vaddr, cpu_core_info[current_starting_cpu].stack_start,
123             cpu_core_info[current_starting_cpu].stack_start, cpu_core_info[current_starting_cpu].stack_start,
124             cpu_core_info[current_starting_cpu].ist_stack_start, cpu_core_info[current_starting_cpu].ist_stack_start,
125             cpu_core_info[current_starting_cpu].ist_stack_start, cpu_core_info[current_starting_cpu].ist_stack_start,
126             cpu_core_info[current_starting_cpu].ist_stack_start, cpu_core_info[current_starting_cpu].ist_stack_start,
127             cpu_core_info[current_starting_cpu].ist_stack_start);
128         io_mfence();
129 
130         // kdebug("core %d, to send start up", current_starting_cpu);
131         // 连续发送两次start-up IPI
132         ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x20, ICR_Start_up, ICR_No_Shorthand,
133                      proc_local_apic_structs[i]->local_apic_id);
134         io_mfence();
135         ipi_send_IPI(DEST_PHYSICAL, IDLE, ICR_LEVEL_DE_ASSERT, EDGE_TRIGGER, 0x20, ICR_Start_up, ICR_No_Shorthand,
136                      proc_local_apic_structs[i]->local_apic_id);
137         // kdebug("core %d, send start up ok", current_starting_cpu);
138     }
139     io_mfence();
140     while (num_cpu_started != (core_to_start + 1))
141         pause();
142 
143     kinfo("Cleaning page table remapping...\n");
144 
145     // 由于ap处理器初始化过程需要用到0x00处的地址,因此初始化完毕后才取消内存地址的重映射
146     rs_unmap_at_low_addr();
147     kdebug("init proc's preempt_count=%ld", current_pcb->preempt_count);
148     kinfo("Successfully cleaned page table remapping!\n");
149 }
150 
151 /**
152  * @brief AP处理器启动后执行的第一个函数
153  *
154  */
smp_ap_start()155 void smp_ap_start()
156 {
157 
158     //  切换栈基地址
159     //  uint64_t stack_start = (uint64_t)kmalloc(STACK_SIZE, 0) + STACK_SIZE;
160     __asm__ __volatile__("movq %0, %%rbp \n\t" ::"m"(cpu_core_info[current_starting_cpu].stack_start)
161                          : "memory");
162     __asm__ __volatile__("movq %0, %%rsp \n\t" ::"m"(cpu_core_info[current_starting_cpu].stack_start)
163                          : "memory");
164 
165     ksuccess("AP core %d successfully started!", current_starting_cpu);
166     io_mfence();
167     ++num_cpu_started;
168 
169     apic_init_ap_core_local_apic();
170 
171     // ============ 为ap处理器初始化IDLE进程 =============
172     memset(current_pcb, 0, sizeof(struct process_control_block));
173 
174     barrier();
175     current_pcb->state = PROC_RUNNING;
176     current_pcb->flags = PF_KTHREAD;
177     current_pcb->address_space = NULL;
178     rs_smp_init_idle();
179 
180     list_init(&current_pcb->list);
181     current_pcb->addr_limit = KERNEL_BASE_LINEAR_ADDR;
182     current_pcb->priority = 2;
183     current_pcb->virtual_runtime = 0;
184 
185     current_pcb->thread = (struct thread_struct *)(current_pcb + 1); // 将线程结构体放置在pcb后方
186     current_pcb->thread->rbp = cpu_core_info[current_starting_cpu].stack_start;
187     current_pcb->thread->rsp = cpu_core_info[current_starting_cpu].stack_start;
188     current_pcb->thread->fs = KERNEL_DS;
189     current_pcb->thread->gs = KERNEL_DS;
190     current_pcb->cpu_id = current_starting_cpu;
191 
192     initial_proc[proc_current_cpu_id] = current_pcb;
193     barrier();
194     load_TR(10 + current_starting_cpu * 2);
195     current_pcb->preempt_count = 0;
196 
197     sched_set_cpu_idle(current_starting_cpu, current_pcb);
198 
199     io_mfence();
200     spin_unlock(&multi_core_starting_lock);
201     preempt_disable(); // 由于ap处理器的pcb与bsp的不同,因此ap处理器放锁时,需要手动恢复preempt count
202     io_mfence();
203     current_pcb->flags |= PF_NEED_SCHED;
204 
205     apic_timer_ap_core_init();
206     sti();
207     sched();
208 
209     while (1)
210     {
211         // kdebug("123");
212         hlt();
213     }
214 
215     while (1)
216     {
217         printk_color(BLACK, WHITE, "CPU:%d IDLE process.\n", proc_current_cpu_id);
218     }
219     while (1) // 这里要循环hlt,原因是当收到中断后,核心会被唤醒,处理完中断之后不会自动hlt
220         hlt();
221 }
222 
223 /**
224  * @brief kick_cpu 核心间通信的处理函数
225  *
226  * @param irq_num
227  * @param param
228  * @param regs
229  */
__smp_kick_cpu_handler(uint64_t irq_num,uint64_t param,struct pt_regs * regs)230 static void __smp_kick_cpu_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs)
231 {
232     if (user_mode(regs))
233         return;
234     sched();
235 }
236 
__smp__flush_tlb_ipi_handler(uint64_t irq_num,uint64_t param,struct pt_regs * regs)237 static void __smp__flush_tlb_ipi_handler(uint64_t irq_num, uint64_t param, struct pt_regs *regs)
238 {
239     if (user_mode(regs))
240         return;
241     flush_tlb();
242 }
243 
244 /**
245  * @brief 获取当前全部的cpu数目
246  *
247  * @return uint32_t
248  */
smp_get_total_cpu()249 uint32_t smp_get_total_cpu()
250 {
251     return num_cpu_started;
252 }