001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <sos/list.h>
020 #include <sos/macros.h>
021 #include <sos/assert.h>
022 #include <sos/klibc.h>
023
024 #include "physmem.h"
025
026
027 struct physical_page_descr
028 {
029
030 sos_paddr_t paddr;
031
032
033
034 sos_count_t ref_cnt;
035
036
037
038
039
040
041
042
043
044
045 sos_count_t occupation_cnt;
046
047
048
049 struct sos_kmem_range *kernel_range;
050
051
052 struct physical_page_descr *prev, *next;
053 };
054
055
056 extern char __b_kernel, __e_kernel;
057
058
059 #define PAGE_DESCR_ARRAY_ADDR \
060 SOS_PAGE_ALIGN_SUP((sos_paddr_t) (& __e_kernel))
061 static struct physical_page_descr * physical_page_descr_array;
062
063
064 static struct physical_page_descr *free_ppage;
065
066
067 static struct physical_page_descr *nonfree_ppage;
068
069
070 static sos_paddr_t physmem_base, physmem_top;
071
072
073 static sos_count_t physmem_total_pages, physmem_nonfree_pages;
074
075 sos_ret_t sos_physmem_subsystem_setup(sos_size_t ram_size,
076 sos_paddr_t *kernel_core_base,
077 sos_paddr_t *kernel_core_top)
078 {
079
080 struct physical_page_descr *ppage_descr;
081
082
083 sos_paddr_t ppage_addr;
084
085
086 ram_size = SOS_PAGE_ALIGN_INF(ram_size);
087
088
089 free_ppage = nonfree_ppage = NULL;
090 physmem_total_pages = physmem_nonfree_pages = 0;
091
092
093
094 *kernel_core_base = SOS_PAGE_ALIGN_INF((sos_paddr_t)(& __b_kernel));
095 *kernel_core_top
096 = PAGE_DESCR_ARRAY_ADDR
097 + SOS_PAGE_ALIGN_SUP( (ram_size >> SOS_PAGE_SHIFT)
098 * sizeof(struct physical_page_descr));
099 if (*kernel_core_top > ram_size)
100 return -SOS_ENOMEM;
101
102
103
104 physmem_base = SOS_PAGE_SIZE;
105 physmem_top = ram_size;
106
107
108 physical_page_descr_array
109 = (struct physical_page_descr*)PAGE_DESCR_ARRAY_ADDR;
110
111
112 for (ppage_addr = 0,
113 ppage_descr = physical_page_descr_array ;
114 ppage_addr < physmem_top ;
115 ppage_addr += SOS_PAGE_SIZE,
116 ppage_descr ++)
117 {
118 enum { PPAGE_MARK_RESERVED, PPAGE_MARK_FREE,
119 PPAGE_MARK_KERNEL, PPAGE_MARK_HWMAP } todo;
120
121 memset(ppage_descr, 0x0, sizeof(struct physical_page_descr));
122
123
124 ppage_descr->paddr = ppage_addr;
125
126
127 if (ppage_addr < physmem_base)
128 todo = PPAGE_MARK_RESERVED;
129
130
131 else if ((ppage_addr >= physmem_base)
132 && (ppage_addr < BIOS_N_VIDEO_START))
133 todo = PPAGE_MARK_FREE;
134
135
136 else if ((ppage_addr >= BIOS_N_VIDEO_START)
137 && (ppage_addr < BIOS_N_VIDEO_END))
138 todo = PPAGE_MARK_HWMAP;
139
140
141 else if ((ppage_addr >= BIOS_N_VIDEO_END)
142 && (ppage_addr < (sos_paddr_t) (& __b_kernel)))
143 todo = PPAGE_MARK_FREE;
144
145
146 else if ((ppage_addr >= *kernel_core_base)
147 && (ppage_addr < *kernel_core_top))
148 todo = PPAGE_MARK_KERNEL;
149
150
151 else
152 todo = PPAGE_MARK_FREE;
153
154
155 physmem_total_pages ++;
156 switch (todo)
157 {
158 case PPAGE_MARK_FREE:
159 ppage_descr->ref_cnt = 0;
160 list_add_head(free_ppage, ppage_descr);
161 break;
162
163 case PPAGE_MARK_KERNEL:
164 case PPAGE_MARK_HWMAP:
165 ppage_descr->ref_cnt = 1;
166 list_add_head(nonfree_ppage, ppage_descr);
167 physmem_nonfree_pages ++;
168 break;
169
170 default:
171
172 break;
173 }
174 }
175
176 return SOS_OK;
177 }
178
179
180 sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block)
181 {
182 struct physical_page_descr *ppage_descr;
183
184 if (! free_ppage)
185 return (sos_paddr_t)NULL;
186
187
188 ppage_descr = list_pop_head(free_ppage);
189
190
191 SOS_ASSERT_FATAL(ppage_descr->ref_cnt == 0);
192
193
194 ppage_descr->ref_cnt ++;
195
196
197
198
199 SOS_ASSERT_FATAL(ppage_descr->occupation_cnt == 0);
200 SOS_ASSERT_FATAL(ppage_descr->kernel_range == NULL);
201
202
203 list_add_tail(nonfree_ppage, ppage_descr);
204 physmem_nonfree_pages ++;
205
206 return ppage_descr->paddr;
207 }
208
209
210
211
212
213
214
215
216 inline static struct physical_page_descr *
217 get_page_descr_at_paddr(sos_paddr_t ppage_paddr)
218 {
219
220 if (ppage_paddr & SOS_PAGE_MASK)
221 return NULL;
222
223
224 if ((ppage_paddr < physmem_base) || (ppage_paddr >= physmem_top))
225 return NULL;
226
227 return physical_page_descr_array + (ppage_paddr >> SOS_PAGE_SHIFT);
228 }
229
230
231 sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr)
232 {
233 struct physical_page_descr *ppage_descr
234 = get_page_descr_at_paddr(ppage_paddr);
235
236 if (! ppage_descr)
237 return -SOS_EINVAL;
238
239
240 ppage_descr->ref_cnt ++;
241
242
243
244 if (ppage_descr->ref_cnt == 1)
245 {
246
247
248
249 SOS_ASSERT_FATAL(ppage_descr->occupation_cnt == 0);
250 SOS_ASSERT_FATAL(ppage_descr->kernel_range == NULL);
251
252 list_delete(free_ppage, ppage_descr);
253 list_add_tail(nonfree_ppage, ppage_descr);
254 physmem_nonfree_pages ++;
255
256
257 return FALSE;
258 }
259
260
261 return TRUE;
262 }
263
264
265 sos_ret_t
266 sos_physmem_unref_physpage(sos_paddr_t ppage_paddr)
267 {
268
269
270 sos_ret_t retval = FALSE;
271
272 struct physical_page_descr *ppage_descr
273 = get_page_descr_at_paddr(ppage_paddr);
274
275 if (! ppage_descr)
276 return -SOS_EINVAL;
277
278
279 if (ppage_descr->ref_cnt <= 0)
280 return -SOS_EINVAL;
281
282
283
284 ppage_descr->ref_cnt--;
285 if (ppage_descr->ref_cnt == 0)
286 {
287
288 SOS_ASSERT_FATAL(ppage_descr->occupation_cnt == 0);
289
290
291 ppage_descr->kernel_range = NULL;
292
293
294 list_delete(nonfree_ppage, ppage_descr);
295 physmem_nonfree_pages --;
296
297 list_add_head(free_ppage, ppage_descr);
298
299
300 retval = TRUE;
301 }
302
303
304 return retval;
305 }
306
307
308 sos_ret_t sos_physmem_get_physpage_refcount(sos_paddr_t ppage_paddr)
309 {
310 struct physical_page_descr *ppage_descr
311 = get_page_descr_at_paddr(ppage_paddr);
312
313 if (! ppage_descr)
314 return -SOS_EINVAL;
315
316 return ppage_descr->ref_cnt;
317 }
318
319
320 sos_ret_t sos_physmem_inc_physpage_occupation(sos_paddr_t ppage_paddr)
321 {
322 struct physical_page_descr *ppage_descr
323 = get_page_descr_at_paddr(ppage_paddr);
324
325 if (! ppage_descr)
326 return -SOS_EINVAL;
327
328
329 SOS_ASSERT_FATAL(ppage_descr->ref_cnt > 0);
330
331 ppage_descr->occupation_cnt ++;
332 return (ppage_descr->occupation_cnt > 1);
333 }
334
335
336 sos_ret_t sos_physmem_dec_physpage_occupation(sos_paddr_t ppage_paddr)
337 {
338 struct physical_page_descr *ppage_descr
339 = get_page_descr_at_paddr(ppage_paddr);
340
341 if (! ppage_descr)
342 return -SOS_EINVAL;
343
344
345 SOS_ASSERT_FATAL(ppage_descr->ref_cnt > 0);
346 SOS_ASSERT_FATAL(ppage_descr->occupation_cnt > 0);
347
348 ppage_descr->occupation_cnt --;
349 return (ppage_descr->occupation_cnt == 0);
350 }
351
352
353 struct sos_kmem_range* sos_physmem_get_kmem_range(sos_paddr_t ppage_paddr)
354 {
355 struct physical_page_descr *ppage_descr
356 = get_page_descr_at_paddr(ppage_paddr);
357
358 if (! ppage_descr)
359 return NULL;
360
361 return ppage_descr->kernel_range;
362 }
363
364
365 sos_ret_t sos_physmem_set_kmem_range(sos_paddr_t ppage_paddr,
366 struct sos_kmem_range *range)
367 {
368 struct physical_page_descr *ppage_descr
369 = get_page_descr_at_paddr(ppage_paddr);
370
371 if (! ppage_descr)
372 return -SOS_EINVAL;
373
374 ppage_descr->kernel_range = range;
375 return SOS_OK;
376 }
377
378 sos_ret_t sos_physmem_get_state(sos_count_t *total_ppages,
379 sos_count_t *nonfree_ppages)
380 {
381 if (total_ppages)
382 *total_ppages = physmem_total_pages;
383 if (nonfree_ppages)
384 *nonfree_ppages = physmem_nonfree_pages;
385 return SOS_OK;
386 }
387