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