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