smp.c 2.7 KB

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