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 struct sos_kmem_range *kernel_range;
038
039
040 struct physical_page_descr *prev, *next;
041 };
042
043
044 extern char __b_kernel, __e_kernel;
045
046
047 #define PAGE_DESCR_ARRAY_ADDR \
048 SOS_PAGE_ALIGN_SUP((sos_paddr_t) (& __e_kernel))
049 static struct physical_page_descr * physical_page_descr_array;
050
051
052 static struct physical_page_descr *free_ppage;
053
054
055 static struct physical_page_descr *used_ppage;
056
057
058 static sos_paddr_t physmem_base, physmem_top;
059
060
061 static sos_count_t physmem_total_pages, physmem_used_pages;
062
063 sos_ret_t sos_physmem_subsystem_setup(sos_size_t ram_size,
064 sos_paddr_t *kernel_core_base,
065 sos_paddr_t *kernel_core_top)
066 {
067
068 struct physical_page_descr *ppage_descr;
069
070
071 sos_paddr_t ppage_addr;
072
073
074 ram_size = SOS_PAGE_ALIGN_INF(ram_size);
075
076
077 free_ppage = used_ppage = NULL;
078 physmem_total_pages = physmem_used_pages = 0;
079
080
081
082 *kernel_core_base = SOS_PAGE_ALIGN_INF((sos_paddr_t)(& __b_kernel));
083 *kernel_core_top
084 = PAGE_DESCR_ARRAY_ADDR
085 + SOS_PAGE_ALIGN_SUP( (ram_size >> SOS_PAGE_SHIFT)
086 * sizeof(struct physical_page_descr));
087 if (*kernel_core_top > ram_size)
088 return -SOS_ENOMEM;
089
090
091
092 physmem_base = SOS_PAGE_SIZE;
093 physmem_top = ram_size;
094
095
096 physical_page_descr_array
097 = (struct physical_page_descr*)PAGE_DESCR_ARRAY_ADDR;
098
099
100 for (ppage_addr = 0,
101 ppage_descr = physical_page_descr_array ;
102 ppage_addr < physmem_top ;
103 ppage_addr += SOS_PAGE_SIZE,
104 ppage_descr ++)
105 {
106 enum { PPAGE_MARK_RESERVED, PPAGE_MARK_FREE,
107 PPAGE_MARK_KERNEL, PPAGE_MARK_HWMAP } todo;
108
109 memset(ppage_descr, 0x0, sizeof(struct physical_page_descr));
110
111
112 ppage_descr->paddr = ppage_addr;
113
114
115 if (ppage_addr < physmem_base)
116 todo = PPAGE_MARK_RESERVED;
117
118
119 else if ((ppage_addr >= physmem_base)
120 && (ppage_addr < BIOS_N_VIDEO_START))
121 todo = PPAGE_MARK_FREE;
122
123
124 else if ((ppage_addr >= BIOS_N_VIDEO_START)
125 && (ppage_addr < BIOS_N_VIDEO_END))
126 todo = PPAGE_MARK_HWMAP;
127
128
129 else if ((ppage_addr >= BIOS_N_VIDEO_END)
130 && (ppage_addr < (sos_paddr_t) (& __b_kernel)))
131 todo = PPAGE_MARK_FREE;
132
133
134 else if ((ppage_addr >= *kernel_core_base)
135 && (ppage_addr < *kernel_core_top))
136 todo = PPAGE_MARK_KERNEL;
137
138
139 else
140 todo = PPAGE_MARK_FREE;
141
142
143 physmem_total_pages ++;
144 switch (todo)
145 {
146 case PPAGE_MARK_FREE:
147 ppage_descr->ref_cnt = 0;
148 list_add_head(free_ppage, ppage_descr);
149 break;
150
151 case PPAGE_MARK_KERNEL:
152 case PPAGE_MARK_HWMAP:
153 ppage_descr->ref_cnt = 1;
154 list_add_head(used_ppage, ppage_descr);
155 physmem_used_pages ++;
156 break;
157
158 default:
159
160 break;
161 }
162 }
163
164 return SOS_OK;
165 }
166
167
168 sos_paddr_t sos_physmem_ref_physpage_new(sos_bool_t can_block)
169 {
170 struct physical_page_descr *ppage_descr;
171
172 if (! free_ppage)
173 return (sos_paddr_t)NULL;
174
175
176 ppage_descr = list_pop_head(free_ppage);
177
178
179 SOS_ASSERT_FATAL(ppage_descr->ref_cnt == 0);
180
181
182 ppage_descr->ref_cnt ++;
183
184
185 ppage_descr->kernel_range = NULL;
186
187
188 list_add_tail(used_ppage, ppage_descr);
189 physmem_used_pages ++;
190
191 return ppage_descr->paddr;
192 }
193
194
195
196
197
198
199
200
201 inline static struct physical_page_descr *
202 get_page_descr_at_paddr(sos_paddr_t ppage_paddr)
203 {
204
205 if (ppage_paddr & SOS_PAGE_MASK)
206 return NULL;
207
208
209 if ((ppage_paddr < physmem_base) || (ppage_paddr >= physmem_top))
210 return NULL;
211
212 return physical_page_descr_array + (ppage_paddr >> SOS_PAGE_SHIFT);
213 }
214
215
216 sos_ret_t sos_physmem_ref_physpage_at(sos_paddr_t ppage_paddr)
217 {
218 struct physical_page_descr *ppage_descr
219 = get_page_descr_at_paddr(ppage_paddr);
220
221 if (! ppage_descr)
222 return -SOS_EINVAL;
223
224
225 ppage_descr->ref_cnt ++;
226
227
228
229 if (ppage_descr->ref_cnt == 1)
230 {
231 list_delete(free_ppage, ppage_descr);
232
233
234 ppage_descr->kernel_range = NULL;
235
236 list_add_tail(used_ppage, ppage_descr);
237 physmem_used_pages ++;
238
239
240 return FALSE;
241 }
242
243
244 return TRUE;
245 }
246
247
248 sos_ret_t
249 sos_physmem_unref_physpage(sos_paddr_t ppage_paddr)
250 {
251
252
253 sos_ret_t retval = FALSE;
254
255 struct physical_page_descr *ppage_descr
256 = get_page_descr_at_paddr(ppage_paddr);
257
258 if (! ppage_descr)
259 return -SOS_EINVAL;
260
261
262 if (ppage_descr->ref_cnt <= 0)
263 return -SOS_EINVAL;
264
265
266
267 ppage_descr->ref_cnt--;
268 if (ppage_descr->ref_cnt <= 0)
269 {
270
271 ppage_descr->kernel_range = NULL;
272
273
274 list_delete(used_ppage, ppage_descr);
275 physmem_used_pages --;
276 list_add_head(free_ppage, ppage_descr);
277
278
279 retval = TRUE;
280 }
281
282 return retval;
283 }
284
285
286 struct sos_kmem_range* sos_physmem_get_kmem_range(sos_paddr_t ppage_paddr)
287 {
288 struct physical_page_descr *ppage_descr
289 = get_page_descr_at_paddr(ppage_paddr);
290
291 if (! ppage_descr)
292 return NULL;
293
294 return ppage_descr->kernel_range;
295 }
296
297
298 sos_ret_t sos_physmem_set_kmem_range(sos_paddr_t ppage_paddr,
299 struct sos_kmem_range *range)
300 {
301 struct physical_page_descr *ppage_descr
302 = get_page_descr_at_paddr(ppage_paddr);
303
304 if (! ppage_descr)
305 return -SOS_EINVAL;
306
307 ppage_descr->kernel_range = range;
308 return SOS_OK;
309 }
310
311 sos_ret_t sos_physmem_get_state(sos_count_t *total_ppages,
312 sos_count_t *used_ppages)
313 {
314 if (total_ppages)
315 *total_ppages = physmem_total_pages;
316 if (used_ppages)
317 *used_ppages = physmem_used_pages;
318 return SOS_OK;
319 }