1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2025 Ant Group 4 * Author: Tiwei Bie <tiwei.btw@antgroup.com> 5 * 6 * Based on the previous implementation in TT mode 7 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 8 */ 9 10 #include <linux/sched.h> 11 #include <linux/sched/task.h> 12 #include <linux/sched/task_stack.h> 13 #include <linux/module.h> 14 #include <linux/processor.h> 15 #include <linux/threads.h> 16 #include <linux/cpu.h> 17 #include <linux/hardirq.h> 18 #include <linux/smp.h> 19 #include <linux/smp-internal.h> 20 #include <init.h> 21 #include <kern.h> 22 #include <os.h> 23 #include <skas.h> 24 #include <smp.h> 25 26 enum { 27 UML_IPI_RES = 0, 28 UML_IPI_CALL_SINGLE, 29 UML_IPI_CALL, 30 UML_IPI_STOP, 31 }; 32 33 void arch_smp_send_reschedule(int cpu) 34 { 35 os_send_ipi(cpu, UML_IPI_RES); 36 } 37 38 void arch_send_call_function_single_ipi(int cpu) 39 { 40 os_send_ipi(cpu, UML_IPI_CALL_SINGLE); 41 } 42 43 void arch_send_call_function_ipi_mask(const struct cpumask *mask) 44 { 45 int cpu; 46 47 for_each_cpu(cpu, mask) 48 os_send_ipi(cpu, UML_IPI_CALL); 49 } 50 51 void smp_send_stop(void) 52 { 53 int cpu, me = smp_processor_id(); 54 55 for_each_online_cpu(cpu) { 56 if (cpu == me) 57 continue; 58 os_send_ipi(cpu, UML_IPI_STOP); 59 } 60 } 61 62 static void ipi_handler(int vector, struct uml_pt_regs *regs) 63 { 64 struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs); 65 int cpu = raw_smp_processor_id(); 66 67 irq_enter(); 68 69 if (current->mm) 70 os_alarm_process(current_mm_id()->pid); 71 72 switch (vector) { 73 case UML_IPI_RES: 74 inc_irq_stat(irq_resched_count); 75 scheduler_ipi(); 76 break; 77 78 case UML_IPI_CALL_SINGLE: 79 inc_irq_stat(irq_call_count); 80 generic_smp_call_function_single_interrupt(); 81 break; 82 83 case UML_IPI_CALL: 84 inc_irq_stat(irq_call_count); 85 generic_smp_call_function_interrupt(); 86 break; 87 88 case UML_IPI_STOP: 89 set_cpu_online(cpu, false); 90 while (1) 91 pause(); 92 break; 93 94 default: 95 pr_err("CPU#%d received unknown IPI (vector=%d)!\n", cpu, vector); 96 break; 97 } 98 99 irq_exit(); 100 set_irq_regs(old_regs); 101 } 102 103 void uml_ipi_handler(int vector) 104 { 105 struct uml_pt_regs r = { .is_user = 0 }; 106 107 preempt_disable(); 108 ipi_handler(vector, &r); 109 preempt_enable(); 110 } 111 112 /* AP states used only during CPU startup */ 113 enum { 114 UML_CPU_PAUSED = 0, 115 UML_CPU_RUNNING, 116 }; 117 118 static int cpu_states[NR_CPUS]; 119 120 static int start_secondary(void *unused) 121 { 122 int err, cpu = raw_smp_processor_id(); 123 124 notify_cpu_starting(cpu); 125 set_cpu_online(cpu, true); 126 127 err = um_setup_timer(); 128 if (err) 129 panic("CPU#%d failed to setup timer, err = %d", cpu, err); 130 131 local_irq_enable(); 132 133 cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 134 135 return 0; 136 } 137 138 void uml_start_secondary(void *opaque) 139 { 140 int cpu = raw_smp_processor_id(); 141 struct mm_struct *mm = &init_mm; 142 struct task_struct *idle; 143 144 stack_protections((unsigned long) &cpu_irqstacks[cpu]); 145 set_sigstack(&cpu_irqstacks[cpu], THREAD_SIZE); 146 147 set_cpu_present(cpu, true); 148 os_futex_wait(&cpu_states[cpu], UML_CPU_PAUSED); 149 150 smp_rmb(); /* paired with smp_wmb() in __cpu_up() */ 151 152 idle = cpu_tasks[cpu]; 153 idle->thread_info.cpu = cpu; 154 155 mmgrab(mm); 156 idle->active_mm = mm; 157 158 idle->thread.request.thread.proc = start_secondary; 159 idle->thread.request.thread.arg = NULL; 160 161 new_thread(task_stack_page(idle), &idle->thread.switch_buf, 162 new_thread_handler); 163 os_start_secondary(opaque, &idle->thread.switch_buf); 164 } 165 166 void __init smp_prepare_cpus(unsigned int max_cpus) 167 { 168 int err, cpu, me = smp_processor_id(); 169 unsigned long deadline; 170 171 os_init_smp(); 172 173 for_each_possible_cpu(cpu) { 174 if (cpu == me) 175 continue; 176 177 pr_debug("Booting processor %d...\n", cpu); 178 err = os_start_cpu_thread(cpu); 179 if (err) { 180 pr_crit("CPU#%d failed to start cpu thread, err = %d", 181 cpu, err); 182 continue; 183 } 184 185 deadline = jiffies + msecs_to_jiffies(1000); 186 spin_until_cond(cpu_present(cpu) || 187 time_is_before_jiffies(deadline)); 188 189 if (!cpu_present(cpu)) 190 pr_crit("CPU#%d failed to boot\n", cpu); 191 } 192 } 193 194 int __cpu_up(unsigned int cpu, struct task_struct *tidle) 195 { 196 cpu_tasks[cpu] = tidle; 197 smp_wmb(); /* paired with smp_rmb() in uml_start_secondary() */ 198 cpu_states[cpu] = UML_CPU_RUNNING; 199 os_futex_wake(&cpu_states[cpu]); 200 spin_until_cond(cpu_online(cpu)); 201 202 return 0; 203 } 204 205 void __init smp_cpus_done(unsigned int max_cpus) 206 { 207 } 208 209 /* Set in uml_ncpus_setup */ 210 int uml_ncpus = 1; 211 212 void __init prefill_possible_map(void) 213 { 214 int cpu; 215 216 for (cpu = 0; cpu < uml_ncpus; cpu++) 217 set_cpu_possible(cpu, true); 218 for (; cpu < NR_CPUS; cpu++) 219 set_cpu_possible(cpu, false); 220 } 221 222 static int __init uml_ncpus_setup(char *line, int *add) 223 { 224 *add = 0; 225 226 if (kstrtoint(line, 10, ¨_ncpus)) { 227 os_warn("%s: Couldn't parse '%s'\n", __func__, line); 228 return -1; 229 } 230 231 uml_ncpus = clamp(uml_ncpus, 1, NR_CPUS); 232 233 return 0; 234 } 235 236 __uml_setup("ncpus=", uml_ncpus_setup, 237 "ncpus=<# of desired CPUs>\n" 238 " This tells UML how many virtual processors to start. The maximum\n" 239 " number of supported virtual processors can be obtained by querying\n" 240 " the CONFIG_NR_CPUS option using --showconfig.\n\n" 241 ); 242 243 EXPORT_SYMBOL(uml_curr_cpu); 244