Remove the frontend appserver code
[akaros.git] / kern / src / page_alloc.c
1 /* Copyright (c) 2009, 2010 The Regents of the University of California.
2  * Copyright (c) 2016 Google Inc
3  * See LICENSE for details.
4  *
5  * Barret Rhoden <brho@cs.berkeley.edu>
6  * Kevin Klues <klueska@cs.berkeley.edu> */
7
8 #include <page_alloc.h>
9 #include <pmap.h>
10 #include <kmalloc.h>
11 #include <arena.h>
12
13 /* Helper, allocates a free page. */
14 static struct page *get_a_free_page(void)
15 {
16         void *addr;
17
18         addr = kpages_alloc(PGSIZE, MEM_ATOMIC);
19         if (!addr)
20                 return NULL;
21         return kva2page(addr);
22 }
23
24 /**
25  * @brief Allocates a physical page from a pool of unused physical memory.
26  *
27  * Zeroes the page.
28  *
29  * @param[out] page  set to point to the Page struct
30  *                   of the newly allocated page
31  *
32  * @return ESUCCESS on success
33  * @return -ENOMEM  otherwise
34  */
35 error_t upage_alloc(struct proc *p, page_t **page, bool zero)
36 {
37         struct page *pg = get_a_free_page();
38
39         if (!pg)
40                 return -ENOMEM;
41         *page = pg;
42         if (zero)
43                 memset(page2kva(*page), 0, PGSIZE);
44         return 0;
45 }
46
47 error_t kpage_alloc(page_t **page)
48 {
49         struct page *pg = get_a_free_page();
50
51         if (!pg)
52                 return -ENOMEM;
53         *page = pg;
54         return 0;
55 }
56
57 /* Helper: allocates a refcounted page of memory for the kernel's use and
58  * returns the kernel address (kernbase), or 0 on error. */
59 void *kpage_alloc_addr(void)
60 {
61         struct page *pg = get_a_free_page();
62
63         if (!pg)
64                 return 0;
65         return page2kva(pg);
66 }
67
68 void *kpage_zalloc_addr(void)
69 {
70         void *retval = kpage_alloc_addr();
71         if (retval)
72                 memset(retval, 0, PGSIZE);
73         return retval;
74 }
75
76 /* Helper function for allocating from the kpages_arena.  This may be useful
77  * later since we might send the caller to a different NUMA domain. */
78 void *kpages_alloc(size_t size, int flags)
79 {
80         return arena_alloc(kpages_arena, size, flags);
81 }
82
83 void *kpages_zalloc(size_t size, int flags)
84 {
85         void *ret = arena_alloc(kpages_arena, size, flags);
86
87         if (!ret)
88                 return NULL;
89         memset(ret, 0, size);
90         return ret;
91 }
92
93 void kpages_free(void *addr, size_t size)
94 {
95         arena_free(kpages_arena, addr, size);
96 }
97
98 /* Returns naturally aligned, contiguous pages of amount PGSIZE << order.  Linux
99  * code might assume its allocations are aligned. (see dma_alloc_coherent and
100  * bnx2x). */
101 void *get_cont_pages(size_t order, int flags)
102 {
103         return arena_xalloc(kpages_arena, PGSIZE << order, PGSIZE << order,
104                             0, 0, NULL, NULL, flags);
105 }
106
107 void free_cont_pages(void *buf, size_t order)
108 {
109         arena_xfree(kpages_arena, buf, PGSIZE << order);
110 }
111
112 /* Frees the page */
113 void page_decref(page_t *page)
114 {
115         kpages_free(page2kva(page), PGSIZE);
116 }
117
118 /* Attempts to get a lock on the page for IO operations.  If it is already
119  * locked, it will block the kthread until it is unlocked.  Note that this is
120  * really a "sleep on some event", not necessarily the IO, but it is "the page
121  * is ready". */
122 void lock_page(struct page *page)
123 {
124         /* when this returns, we have are the ones to have locked the page */
125         sem_down(&page->pg_sem);
126         assert(!(atomic_read(&page->pg_flags) & PG_LOCKED));
127         atomic_or(&page->pg_flags, PG_LOCKED);
128 }
129
130 /* Unlocks the page, and wakes up whoever is waiting on the lock */
131 void unlock_page(struct page *page)
132 {
133         atomic_and(&page->pg_flags, ~PG_LOCKED);
134         sem_up(&page->pg_sem);
135 }