akaros/kern/arch/riscv/smp.c
<<
>>
Prefs
   1#include <arch/arch.h>
   2#include <arch/smp.h>
   3#include <assert.h>
   4#include <atomic.h>
   5#include <error.h>
   6#include <pmap.h>
   7#include <smp.h>
   8#include <stdio.h>
   9#include <string.h>
  10
  11volatile uint32_t num_cores_booted = 0;
  12
  13void smp_boot(void)
  14{
  15        smp_percpu_init();
  16        num_cores_booted = 1;
  17        while (num_cores_booted < num_cores)
  18                ;
  19        printd("%d cores reporting!\n", num_cores);
  20}
  21
  22void smp_init(void)
  23{
  24        smp_percpu_init();
  25
  26        __sync_fetch_and_add(&num_cores_booted, 1);
  27        printd("Good morning, Vietnam! (core id = %d)\n", core_id());
  28
  29        smp_idle();
  30}
  31
  32handler_wrapper_t *smp_make_wrapper(void)
  33{
  34        static handler_wrapper_t wrapper_pool[MAX_NUM_CORES * 8] = {
  35            {{0}, SPINLOCK_INITIALIZER}};
  36
  37        size_t i;
  38        for (i = 0; i < sizeof(wrapper_pool) / sizeof(wrapper_pool[0]); i++)
  39                if (spin_trylock(&wrapper_pool[i].lock) == 0)
  40                        return &wrapper_pool[i];
  41        return NULL;
  42}
  43
  44void smp_call_wrapper(uint32_t src, isr_t handler, handler_wrapper_t *wrapper,
  45                      void *data)
  46{
  47        if (wrapper)
  48                wrapper->wait_list[core_id()] = 0;
  49        handler(0, data);
  50}
  51
  52int smp_call_function_self(isr_t handler, void *data,
  53                           handler_wrapper_t **wait_wrapper)
  54{
  55        return smp_call_function_single(core_id(), handler, data, wait_wrapper);
  56}
  57
  58int smp_call_function_all(isr_t handler, void *data,
  59                          handler_wrapper_t **wait_wrapper)
  60{
  61        int8_t state = 0;
  62        int i, me;
  63        handler_wrapper_t *wrapper = 0;
  64
  65        if (wait_wrapper) {
  66                wrapper = *wait_wrapper = smp_make_wrapper();
  67                if (!wrapper)
  68                        return -ENOMEM;
  69
  70                for (i = 0; i < num_cores; i++)
  71                        wrapper->wait_list[i] = 1;
  72        }
  73
  74        enable_irqsave(&state);
  75
  76        // send to others
  77        for (i = 0, me = core_id(); i < num_cores; i++) {
  78                if (i == me)
  79                        continue;
  80
  81                send_kernel_message(i, (amr_t)smp_call_wrapper, (long)handler,
  82                                    (long)wrapper, (long)data, KMSG_IMMEDIATE);
  83        }
  84
  85        // send to me
  86        send_kernel_message(me, (amr_t)smp_call_wrapper, (long)handler,
  87                            (long)wrapper, (long)data, KMSG_IMMEDIATE);
  88
  89        cpu_relax(); // wait to get the interrupt
  90
  91        disable_irqsave(&state);
  92
  93        return 0;
  94}
  95
  96int smp_call_function_single(uint32_t dest, isr_t handler, void *data,
  97                             handler_wrapper_t **wait_wrapper)
  98{
  99        int8_t state = 0;
 100        handler_wrapper_t *wrapper = 0;
 101
 102        if (wait_wrapper) {
 103                wrapper = *wait_wrapper = smp_make_wrapper();
 104                if (!wrapper)
 105                        return -ENOMEM;
 106                wrapper->wait_list[dest] = 1;
 107        }
 108
 109        enable_irqsave(&state);
 110
 111        send_kernel_message(dest, (amr_t)smp_call_wrapper, (long)handler,
 112                            (long)wrapper, (long)data, KMSG_IMMEDIATE);
 113
 114        cpu_relax(); // wait to get the interrupt, if it's to this core
 115
 116        disable_irqsave(&state);
 117
 118        return 0;
 119}
 120
 121int smp_call_wait(handler_wrapper_t *wrapper)
 122{
 123        int i;
 124
 125        for (i = 0; i < num_cores; i++)
 126                while (wrapper->wait_list[i])
 127                        ;
 128
 129        spin_unlock(&wrapper->lock);
 130        return 0;
 131}
 132
 133/* Perform any initialization needed by per_cpu_info.  Right now, this just
 134 * inits the amsg list.  Make sure every core calls this at some point in the
 135 * smp_boot process. */
 136void __arch_pcpu_init(uint32_t coreid)
 137{
 138        // Switch to the real L1 page table, rather than the boot page table
 139        // which has the [0,KERNSIZE-1] identity mapping.
 140        extern pte_t l1pt[NPTENTRIES];
 141        lcr3(PADDR(l1pt));
 142
 143        register uintptr_t sp asm("sp");
 144        set_stack_top(ROUNDUP(sp, PGSIZE));
 145}
 146