1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2025 Ant Group 4 * Author: Tiwei Bie <tiwei.btw@antgroup.com> 5 */ 6 7 #include <errno.h> 8 #include <pthread.h> 9 #include <signal.h> 10 #include <kern_util.h> 11 #include <um_malloc.h> 12 #include <init.h> 13 #include <os.h> 14 #include <smp.h> 15 #include "internal.h" 16 17 struct cpu_thread_data { 18 int cpu; 19 sigset_t sigset; 20 }; 21 22 static __thread int __curr_cpu; 23 24 int uml_curr_cpu(void) 25 { 26 return __curr_cpu; 27 } 28 29 static pthread_t cpu_threads[CONFIG_NR_CPUS]; 30 31 static void *cpu_thread(void *arg) 32 { 33 struct cpu_thread_data *data = arg; 34 35 __curr_cpu = data->cpu; 36 37 uml_start_secondary(data); 38 39 return NULL; 40 } 41 42 int os_start_cpu_thread(int cpu) 43 { 44 struct cpu_thread_data *data; 45 sigset_t sigset, oset; 46 int err; 47 48 data = uml_kmalloc(sizeof(*data), UM_GFP_ATOMIC); 49 if (!data) 50 return -ENOMEM; 51 52 sigfillset(&sigset); 53 if (sigprocmask(SIG_SETMASK, &sigset, &oset) < 0) { 54 err = errno; 55 goto err; 56 } 57 58 data->cpu = cpu; 59 data->sigset = oset; 60 61 err = pthread_create(&cpu_threads[cpu], NULL, cpu_thread, data); 62 if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) 63 panic("Failed to restore the signal mask, errno = %d", errno); 64 if (err != 0) 65 goto err; 66 67 return 0; 68 69 err: 70 kfree(data); 71 return -err; 72 } 73 74 void os_start_secondary(void *arg, jmp_buf *switch_buf) 75 { 76 struct cpu_thread_data *data = arg; 77 78 sigaddset(&data->sigset, IPI_SIGNAL); 79 sigaddset(&data->sigset, SIGIO); 80 81 if (sigprocmask(SIG_SETMASK, &data->sigset, NULL) < 0) 82 panic("Failed to restore the signal mask, errno = %d", errno); 83 84 kfree(data); 85 longjmp(*switch_buf, 1); 86 87 /* unreachable */ 88 printk(UM_KERN_ERR "impossible long jump!"); 89 fatal_sigsegv(); 90 } 91 92 int os_send_ipi(int cpu, int vector) 93 { 94 union sigval value = { .sival_int = vector }; 95 96 return pthread_sigqueue(cpu_threads[cpu], IPI_SIGNAL, value); 97 } 98 99 static void __local_ipi_set(int enable) 100 { 101 sigset_t sigset; 102 103 sigemptyset(&sigset); 104 sigaddset(&sigset, IPI_SIGNAL); 105 106 if (sigprocmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) 107 panic("%s: sigprocmask failed, errno = %d", __func__, errno); 108 } 109 110 void os_local_ipi_enable(void) 111 { 112 __local_ipi_set(1); 113 } 114 115 void os_local_ipi_disable(void) 116 { 117 __local_ipi_set(0); 118 } 119 120 static void ipi_sig_handler(int sig, siginfo_t *si, void *uc) 121 { 122 int save_errno = errno; 123 124 signals_enabled = 0; 125 um_trace_signals_off(); 126 127 uml_ipi_handler(si->si_value.sival_int); 128 129 um_trace_signals_on(); 130 signals_enabled = 1; 131 132 errno = save_errno; 133 } 134 135 void __init os_init_smp(void) 136 { 137 struct sigaction action = { 138 .sa_sigaction = ipi_sig_handler, 139 .sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART, 140 }; 141 142 sigfillset(&action.sa_mask); 143 144 if (sigaction(IPI_SIGNAL, &action, NULL) < 0) 145 panic("%s: sigaction failed, errno = %d", __func__, errno); 146 147 cpu_threads[0] = pthread_self(); 148 } 149