kth: Remove irq_state from sem_.*irqsave's interface
[akaros.git] / kern / src / percpu.c
1 /* Copyright (c) 2015 Google Inc
2  * Davide Libenzi <dlibenzi@google.com>
3  * See LICENSE for details.
4  */
5
6 #include <sys/types.h>
7 #include <arch/topology.h>
8 #include <kmalloc.h>
9 #include <stdio.h>
10 #include <assert.h>
11 #include <string.h>
12 #include <percpu.h>
13 #include <arena.h>
14 #include <page_alloc.h>
15 #include <smp.h>
16
17 char *percpu_base;
18 static struct arena *pcpu_dyn_arena;
19
20 static void run_init_functions(void)
21 {
22         extern char __attribute__((weak)) PERCPU_INIT_START_VAR[];
23         extern char __attribute__((weak)) PERCPU_INIT_STOP_VAR[];
24
25         if (PERCPU_INIT_START_VAR) {
26                 void (**pfunc)(void) = (void (**)(void)) PERCPU_INIT_START_VAR;
27                 void (**pfunc_top)(void) = (void (**)(void)) PERCPU_INIT_STOP_VAR;
28
29                 for (; pfunc < pfunc_top; pfunc++)
30                         (*pfunc)();
31         }
32 }
33
34 void percpu_init(void)
35 {
36         assert(num_cores > 0);
37
38         percpu_base = kpages_alloc(num_cores * PERCPU_SIZE, MEM_WAIT);
39         if (PERCPU_START_VAR) {
40                 for (int i = 0; i < num_cores; i++)
41                         memcpy(percpu_base + i * PERCPU_SIZE, PERCPU_START_VAR,
42                                    PERCPU_STATIC_SIZE);
43         }
44         /* We hand out addresses starting right above the static section, which ends
45          * at PERCPU_STOP_VAR. */
46         pcpu_dyn_arena = arena_create("pcpu_dyn", PERCPU_STOP_VAR, PERCPU_DYN_SIZE,
47                                       1, NULL, NULL, NULL, 0, MEM_WAIT);
48         assert(pcpu_dyn_arena);
49         run_init_functions();
50 }
51
52 /* We return pointers, but our users need to dereference them when using any of
53  * the PERCPU_ helpers so that they are treated like the static vars. */
54 void *__percpu_alloc(size_t size, size_t align, int flags)
55 {
56         assert(pcpu_dyn_arena);
57         /* our alignment is limited to the alignment of percpu_base */
58         warn_on(align > PGSIZE);
59         return arena_xalloc(pcpu_dyn_arena, size, align, 0, 0, NULL, NULL,
60                             flags | ARENA_BESTFIT);
61 }
62
63 void *__percpu_zalloc(size_t size, size_t align, int flags)
64 {
65         /* Yikes! */
66         struct {
67                 uint8_t data[size];
68         } *ret;
69
70         ret = __percpu_alloc(size, align, flags);
71         if (!ret)
72                 return NULL;
73         for_each_core(i)
74                 memset(_PERCPU_VARPTR(*ret, i), 0, size);
75         return ret;
76 }
77
78 void __percpu_free(void *base, size_t size)
79 {
80         arena_free(pcpu_dyn_arena, base, size);
81 }