nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
page_frame.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <stdio.h>
3 #include <errno.h>
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <pthread.h>
10 
11 #include <debug.h>
12 
13 #include <list.h>
14 #include <cpu_node.h>
15 #include <zone.h>
16 #include <page_frame.h>
17 #include <page_allocator.h>
18 
20 
21 static inline struct page_frame *find_frame(void *page, struct zone **_zone)
22 {
23  struct zone *zone;
24  struct list_head *pos;
25  struct list_head *n;
26  struct page_frame *frame;
27 
28  zone = find_zone_by_addr(page);
29  if (!zone) {
30  return NULL;
31  }
32 
33  frame = NULL;
34  list_for_each_safe(pos, n, &zone->page_list) {
35  frame = list_entry(pos, struct page_frame, page_head);
36  if (frame->pma == page) {
37  break;
38  }
39 
40  frame = NULL;
41  }
42 
43  if (_zone) {
44  *_zone = zone;
45  }
46 
47  return frame;
48 }
49 
50 int page_frame_init(struct zone *zone, void *base, size_t size)
51 {
52  void *info;
53 
54  info = malloc(page_allocator_info_size(size));
55  if (!info) {
56  return -ENOMEM;
57  }
58 
59  zone->handle = page_allocator_init(info, base, size);
60  if (!zone->handle) {
61  free(info);
62  return -EFAULT;
63  }
64 
65  return 0;
66 }
67 
68 int page_frame_fini(struct zone *zone)
69 {
70  struct list_head *pos;
71  struct list_head *n;
72  struct page_frame *frame;
73 
74  list_for_each_safe(pos, n, &zone->page_list) {
75  frame = list_entry(pos, struct page_frame, page_head);
76  page_allocator_free(zone->handle, frame->pma);
77  }
78 
79  list_for_each_safe(pos, n, &zone->managed_page_list) {
80  frame = list_entry(pos, struct page_frame, page_head);
81  list_del(&frame->page_head);
82  free(frame);
83  }
84 
85  return 0;
86 }
87 
92 void *page_frame_alloc(enum zone_type zone_type, size_t nr_of_pages)
93 {
94  struct page_frame *frame;
95  struct zone *zone;
96  void *ret = NULL;
97 
98  pthread_mutex_lock(&s_lock);
100 
101  zone = find_zone(zone_type);
102  if (!zone) {
103  dbg_printf("Failed to find a zone\n");
104  goto out;
105  }
106 
107  frame = malloc(sizeof(*frame));
108  if (!frame) {
109  dbg_printf("Failed to allocate frame\n");
110  goto out;
111  }
112 
113  frame->pma = page_allocator_alloc(zone->handle, nr_of_pages);
114  if (frame->pma == (void *)-1) {
115  free(frame);
116  dbg_printf("Failed to allocate a page\n");
117  goto out;
118  }
119 
120  frame->refcnt = 1;
121  list_add_tail(&frame->page_head, &zone->page_list);
122 
123  ret = frame->pma;
124 
125 out:
127  pthread_mutex_unlock(&s_lock);
128  return ret;
129 }
130 
131 int page_frame_free(void *page)
132 {
133  struct page_frame *frame;
134  struct zone *zone;
135  int ret = 0;
136 
137  pthread_mutex_lock(&s_lock);
139 
140  frame = find_frame(page, &zone);
141  if (!frame) {
142  ret = -EINVAL;
143  goto out;
144  }
145 
146  frame->refcnt--;
147  if (frame->refcnt > 0) {
148  goto out;
149  }
150 
151  page_allocator_free(zone->handle, frame->pma);
152  list_del(&frame->page_head);
153  free(frame);
154 
155 out:
157  pthread_mutex_unlock(&s_lock);
158  return ret;
159 }
160 
161 int page_frame_ref(void *page)
162 {
163  struct page_frame *frame;
164  int ret = 0;
165 
166  pthread_mutex_lock(&s_lock);
168 
169  frame = find_frame(page, NULL);
170  if (!frame) {
171  ret = -ENOENT;
172  goto out;
173  }
174 
175  frame->refcnt++;
176 
177 out:
179  pthread_mutex_unlock(&s_lock);
180  return ret;
181 }
182 
183 int page_frame_refcnt(void *page)
184 {
185  struct page_frame *frame;
186  int refcnt;
187 
188  pthread_mutex_lock(&s_lock);
190 
191  frame = find_frame(page, NULL);
192  if (!frame) {
193  refcnt = -ENOENT;
194  goto out;
195  }
196 
197  refcnt = frame->refcnt;
198 
199 out:
201  pthread_mutex_unlock(&s_lock);
202  return refcnt;
203 }
204 
205 int page_frame_manage(enum zone_type type, void *page, int nr_of_pages)
206 {
207  struct page_frame *frame;
208  struct zone *zone;
209  int ret = 0;
210 
211  pthread_mutex_lock(&s_lock);
213 
214  frame = find_frame(page, NULL);
215  if (frame) {
216  ret = -EEXIST;
217  goto out;
218  }
219 
220  zone = find_zone(type);
221  if (!zone) {
222  ret = -EINVAL;
223  goto out;
224  }
225 
226  frame = malloc(sizeof(*frame));
227  if (!frame) {
228  ret = -ENOMEM;
229  goto out;
230  }
231 
232  frame->pma = page;
233  frame->refcnt = 1;
234 
235  list_add_tail(&frame->page_head, &zone->managed_page_list);
236 
237 out:
239  pthread_mutex_unlock(&s_lock);
240  return ret;
241 }
242 
243 /* @} End of a file */