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