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 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
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 /** A descriptor for a physical page in SOS */
026 struct physical_page_descr
027 {
028   /** The physical base address for the page */
029   sos_paddr_t paddr;
030 
031   /** The reference count for this physical page. > 0 means that the
032      page is in the used list. */
033   sos_count_t ref_cnt;
034 
035   /** The other pages on the list (used, free) */
036   struct physical_page_descr *prev, *next;
037 };
038 
039 /** These are some markers present in the executable file (see sos.lds) */
040 extern char __b_kernel, __e_kernel;
041 
042 /** The array of ppage descriptors will be located at this address */
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 /** The list of physical pages currently available */
048 static struct physical_page_descr *free_ppage;
049 
050 /** The list of physical pages currently in use */
051 static struct physical_page_descr *used_ppage;
052 
053 /** We will store here the interval of valid physical addresses */
054 static sos_paddr_t physmem_base, physmem_top;
055 
056 /** We store the number of pages used/free */
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                             /* out */sos_paddr_t *kernel_core_base,
061                             /* out */sos_paddr_t *kernel_core_top)
062 {
063   /* The iterator over the page descriptors */
064   struct physical_page_descr *ppage_descr;
065 
066   /* The iterator over the physical addresses */
067   sos_paddr_t ppage_addr;
068 
069   /* Make sure ram size is aligned on a page boundary */
070   ram_size = SOS_PAGE_ALIGN_INF(ram_size);/* Yes, we may lose at most a page */
071 
072   /* Reset the used/free page lists before building them */
073   free_ppage = used_ppage = NULL;
074   physmem_total_pages = physmem_used_pages = 0;
075 
076   /* Make sure that there is enough memory to store the array of page
077      descriptors */
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   /* Page 0-4kB is not available in order to return address 0 as a
087      means to signal "no page available" */
088   physmem_base = SOS_PAGE_SIZE;
089   physmem_top  = ram_size;
090 
091   /* Setup the page descriptor arrray */
092   physical_page_descr_array
093     = (struct physical_page_descr*)PAGE_DESCR_ARRAY_ADDR;
094 
095   /* Scan the list of physical pages */
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       /* Init the page descriptor for this page */
108       ppage_descr->paddr = ppage_addr;
109 
110       /* Reserved : 0 ... base */
111       if (ppage_addr < physmem_base)
112         todo = PPAGE_MARK_RESERVED;
113 
114       /* Free : base ... BIOS */
115       else if ((ppage_addr >= physmem_base)
116                && (ppage_addr < BIOS_N_VIDEO_START))
117         todo = PPAGE_MARK_FREE;
118 
119       /* Used : BIOS */
120       else if ((ppage_addr >= BIOS_N_VIDEO_START)
121                && (ppage_addr < BIOS_N_VIDEO_END))
122         todo = PPAGE_MARK_HWMAP;
123 
124       /* Free : BIOS ... kernel */
125       else if ((ppage_addr >= BIOS_N_VIDEO_END)
126                && (ppage_addr < (sos_paddr_t) (& __b_kernel)))
127         todo = PPAGE_MARK_FREE;
128 
129       /* Used : Kernel code/data/bss + physcal page descr array */
130       else if ((ppage_addr >= *kernel_core_base)
131                 && (ppage_addr < *kernel_core_top))
132         todo = PPAGE_MARK_KERNEL;
133 
134       /* Free : first page of descr ... end of RAM */
135       else
136         todo = PPAGE_MARK_FREE;
137 
138       /* Actually does the insertion in the used/free page lists */
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           /* Reserved page: nop */
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   /* Retrieve a page in the free list */
172   ppage_descr = list_pop_head(free_ppage);
173 
174   /* The page is assumed not to be already used */
175   SOS_ASSERT_FATAL(ppage_descr->ref_cnt == 0);
176 
177   /* Mark the page as used (this of course sets the ref count to 1) */
178   ppage_descr->ref_cnt ++;
179 
180   /* Put the page in the used list */
181   list_add_tail(used_ppage, ppage_descr);
182   physmem_used_pages ++;
183 
184   return ppage_descr->paddr;
185 }
186 
187 
188 /**
189  * Helper function to get the physical page descriptor for the given
190  * physical page address.
191  *
192  * @return NULL when out-of-bounds or non-page-aligned
193  */
194 inline static struct physical_page_descr *
195 get_page_descr_at_paddr(sos_paddr_t ppage_paddr)
196 {
197   /* Don't handle non-page-aligned addresses */
198   if (ppage_paddr & SOS_PAGE_MASK)
199     return NULL;
200   
201   /* Don't support out-of-bounds requests */
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   /* Increment the reference count for the page */
218   ppage_descr->ref_cnt ++;
219 
220   /* If the page is newly referenced (ie we are the only owners of the
221      page => ref cnt == 1), transfer it in the used pages list */
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       /* The page is newly referenced */
229       return FALSE;
230     }
231 
232   /* The page was already referenced by someone */
233   return TRUE;
234 }
235 
236 
237 sos_ret_t
238 sos_physmem_unref_physpage(sos_paddr_t ppage_paddr)
239 {
240   /* By default the return value indicates that the page is still
241      used */
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   /* Don't do anything if the page is not in the used list */
251   if (ppage_descr->ref_cnt <= 0)
252     return -SOS_EINVAL;
253 
254   /* Unreference the page, and, when no mapping is active anymore, put
255      the page in the free list */
256   ppage_descr->ref_cnt--;
257   if (ppage_descr->ref_cnt <= 0)
258     {
259       /* Transfer the page, considered USED, to the free list */
260       list_delete(used_ppage, ppage_descr);
261       physmem_used_pages --;
262       list_add_head(free_ppage, ppage_descr);
263 
264       /* Indicate that the page is now unreferenced */
265       retval = TRUE;
266     }
267 
268   return retval;
269 }

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