SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2004  David Decotigny
002    Copyright (C) 2000  The KOS Team
003 
004    This program is free software; you can redistribute it and/or
005    modify it under the terms of the GNU General Public License
006    as published by the Free Software Foundation; either version 2
007    of the License, or (at your option) any later version.
008    
009    This program is distributed in the hope that it will be useful,
010    but WITHOUT ANY WARRANTY; without even the implied warranty of
011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012    GNU General Public License for more details.
013    
014    You should have received a copy of the GNU General Public License
015    along with this program; if not, write to the Free Software
016    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
017    USA. 
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 /** A descriptor for a physical page in SOS */
027 struct physical_page_descr
028 {
029   /** The physical base address for the page */
030   sos_paddr_t paddr;
031 
032   /** The reference count for this physical page. > 0 means that the
033      page is in the nonfree list. */
034   sos_count_t ref_cnt;
035 
036   /**
037    * An additional counter for user-defined use. The management of this
038    * counter is up to the user, however a simple set of rules applies:
039    *   - it can only be incremented/decremented if the page is referenced
040    *   - when it reaches 0, no automatic action is taken
041    * The first rule means in particular that a page whose reference
042    * count reaches 0 (=> will be freed) cannot have a custom_count
043    * value > 0 ! The system will be HALTED if this ever happens
044    */
045   sos_count_t occupation_cnt;
046 
047 
048   /** Some data associated with the page when it is mapped in kernel space */
049   struct sos_kmem_range *kernel_range;
050 
051   /** The other pages on the list (nonfree, free) */
052   struct physical_page_descr *prev, *next;
053 };
054 
055 /** These are some markers present in the executable file (see sos.lds) */
056 extern char __b_kernel, __e_kernel;
057 
058 /** The array of ppage descriptors will be located at this address */
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 /** The list of physical pages currently available */
064 static struct physical_page_descr *free_ppage;
065 
066 /** The list of physical pages currently allocated */
067 static struct physical_page_descr *nonfree_ppage;
068 
069 /** We will store here the interval of valid physical addresses */
070 static sos_paddr_t physmem_base, physmem_top;
071 
072 /** We store the number of pages nonfree/free */
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                                       /* out */sos_paddr_t *kernel_core_base,
077                                       /* out */sos_paddr_t *kernel_core_top)
078 {
079   /* The iterator over the page descriptors */
080   struct physical_page_descr *ppage_descr;
081 
082   /* The iterator over the physical addresses */
083   sos_paddr_t ppage_addr;
084 
085   /* Make sure ram size is aligned on a page boundary */
086   ram_size = SOS_PAGE_ALIGN_INF(ram_size);/* Yes, we may lose at most a page */
087 
088   /* Reset the nonfree/free page lists before building them */
089   free_ppage = nonfree_ppage = NULL;
090   physmem_total_pages = physmem_nonfree_pages = 0;
091 
092   /* Make sure that there is enough memory to store the array of page
093      descriptors */
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   /* Page 0-4kB is not available in order to return address 0 as a
103      means to signal "no page available" */
104   physmem_base = SOS_PAGE_SIZE;
105   physmem_top  = ram_size;
106 
107   /* Setup the page descriptor arrray */
108   physical_page_descr_array
109     = (struct physical_page_descr*)PAGE_DESCR_ARRAY_ADDR;
110 
111   /* Scan the list of physical pages */
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       /* Init the page descriptor for this page */
124       ppage_descr->paddr = ppage_addr;
125 
126       /* Reserved : 0 ... base */
127       if (ppage_addr < physmem_base)
128         todo = PPAGE_MARK_RESERVED;
129 
130       /* Free : base ... BIOS */
131       else if ((ppage_addr >= physmem_base)
132                && (ppage_addr < BIOS_N_VIDEO_START))
133         todo = PPAGE_MARK_FREE;
134 
135       /* Used : BIOS */
136       else if ((ppage_addr >= BIOS_N_VIDEO_START)
137                && (ppage_addr < BIOS_N_VIDEO_END))
138         todo = PPAGE_MARK_HWMAP;
139 
140       /* Free : BIOS ... kernel */
141       else if ((ppage_addr >= BIOS_N_VIDEO_END)
142                && (ppage_addr < (sos_paddr_t) (& __b_kernel)))
143         todo = PPAGE_MARK_FREE;
144 
145       /* Used : Kernel code/data/bss + physcal page descr array */
146       else if ((ppage_addr >= *kernel_core_base)
147                 && (ppage_addr < *kernel_core_top))
148         todo = PPAGE_MARK_KERNEL;
149 
150       /* Free : first page of descr ... end of RAM */
151       else
152         todo = PPAGE_MARK_FREE;
153 
154       /* Actually does the insertion in the nonfree/free page lists */
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           /* Reserved page: nop */
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   /* Retrieve a page in the free list */
188   ppage_descr = list_pop_head(free_ppage);
189 
190   /* The page is assumed not to be already in the nonfree list */
191   SOS_ASSERT_FATAL(ppage_descr->ref_cnt == 0);
192 
193   /* Mark the page as nonfree (this of course sets the ref count to 1) */
194   ppage_descr->ref_cnt ++;
195 
196   /* The page descriptor should be unmodified since previous
197      deallocation. Otherwise this means that something unauthorized
198      overwrote the page descriptor table contents ! */
199   SOS_ASSERT_FATAL(ppage_descr->occupation_cnt == 0);
200   SOS_ASSERT_FATAL(ppage_descr->kernel_range == NULL);
201   
202   /* Put the page in the nonfree list */
203   list_add_tail(nonfree_ppage, ppage_descr);
204   physmem_nonfree_pages ++;
205 
206   return ppage_descr->paddr;
207 }
208 
209 
210 /**
211  * Helper function to get the physical page descriptor for the given
212  * physical page address.
213  *
214  * @return NULL when out-of-bounds or non-page-aligned
215  */
216 inline static struct physical_page_descr *
217 get_page_descr_at_paddr(sos_paddr_t ppage_paddr)
218 {
219   /* Don't handle non-page-aligned addresses */
220   if (ppage_paddr & SOS_PAGE_MASK)
221     return NULL;
222   
223   /* Don't support out-of-bounds requests */
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   /* Increment the reference count for the page */
240   ppage_descr->ref_cnt ++;
241 
242   /* If the page is newly referenced (ie we are the only owners of the
243      page => ref cnt == 1), transfer it in the nonfree pages list */
244   if (ppage_descr->ref_cnt == 1)
245     {
246       /* The page descriptor should be unmodified since previous
247          deallocation. Otherwise this means that something unauthorized
248          overwrote the page descriptor table contents ! */
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       /* The page is newly referenced */
257       return FALSE;
258     }
259   
260   /* The page was already referenced by someone */
261   return TRUE;
262 }
263 
264 
265 sos_ret_t
266 sos_physmem_unref_physpage(sos_paddr_t ppage_paddr)
267 {
268   /* By default the return value indicates that the page is still
269      used */
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   /* Don't do anything if the page is not in the nonfree list */
279   if (ppage_descr->ref_cnt <= 0)
280     return -SOS_EINVAL;
281 
282   /* Unreference the page, and, when no mapping is active anymore, put
283      the page in the free list */
284   ppage_descr->ref_cnt--;
285   if (ppage_descr->ref_cnt == 0)
286     {
287       /* Make sure that the occupation counter is set to 0 */
288       SOS_ASSERT_FATAL(ppage_descr->occupation_cnt == 0);
289 
290       /* Reset associated kernel range */
291       ppage_descr->kernel_range = NULL;
292   
293       /* Transfer the page, considered NON-FREE, to the free list */
294       list_delete(nonfree_ppage, ppage_descr);
295       physmem_nonfree_pages --;
296       
297       list_add_head(free_ppage, ppage_descr);
298 
299       /* Indicate that the page is now unreferenced */
300       retval = TRUE;
301     }
302 
303   /* The page was already referenced by someone */
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   /* Don't do anything if the page is not in the nonfree list */
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   /* Don't do anything if the page is not in the nonfree list */
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(/* out */sos_count_t *total_ppages,
379                                 /* out */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 

source navigation ] diff markup ] identifier search ] general search ]