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