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