source: trunk/kernel/mm/page.c @ 407

Last change on this file since 407 was 407, checked in by alain, 4 years ago

First implementation of fork/exec.

File size: 6.1 KB
Line 
1/*
2 * page.c - physical page related operations implementation
3 *
4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *          Alain Greiner    (2016,2017)
6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#include <hal_types.h>
26#include <hal_special.h>
27#include <hal_atomic.h>
28#include <list.h>
29#include <xlist.h>
30#include <memcpy.h>
31#include <thread.h>
32#include <scheduler.h>
33#include <cluster.h>
34#include <ppm.h>
35#include <mapper.h>
36#include <printk.h>
37#include <vfs.h>
38#include <process.h>
39#include <page.h>
40
41////////////////////////////////////////
42inline void page_init( page_t   * page )
43{
44        page->flags    = 0;
45        page->order    = 0;
46        page->mapper   = NULL;
47        page->index    = 0;
48        page->refcount = 0;
49
50        spinlock_init( &page->lock );
51        list_entry_init( &page->list );
52    xlist_root_init( XPTR( local_cxy , &page->wait_root ) );
53}
54
55////////////////////////////////////////////
56inline void page_set_flag( page_t   * page,
57                           uint32_t   value )
58{
59        hal_atomic_or( (uint32_t *)&page->flags , (uint32_t)value );
60}
61
62//////////////////////////////////////////////
63inline void page_clear_flag( page_t   * page,
64                             uint32_t   value )
65{
66        hal_atomic_and( (uint32_t *)&page->flags , ~((uint32_t)value) );
67}
68
69//////////////////////////////////////////////
70inline bool_t page_is_flag( page_t   * page,
71                            uint32_t   value )
72{
73    return ( (page->flags & value) ? 1 : 0 );
74}
75
76//////////////////////////////////////
77bool_t page_do_dirty( page_t * page )
78{
79        bool_t done = false;
80
81        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
82
83        // lock the PPM dirty_list
84        spinlock_lock( &ppm->dirty_lock );
85
86        if( !page_is_flag( page , PG_DIRTY ) )
87        {
88                // set dirty flag in page descriptor
89                page_set_flag( page , PG_DIRTY );
90
91                // register page in PPM dirty list
92                list_add_first( &ppm->dirty_root , &page->list );
93                done = true;
94        }
95
96        // unlock the PPM dirty_list
97        spinlock_unlock( &ppm->dirty_lock );
98
99        return done;
100}
101
102////////////////////////////////////////
103bool_t page_undo_dirty( page_t * page )
104{
105        bool_t done = false;
106
107        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
108
109        // lock the dirty_list
110        spinlock_lock( &ppm->dirty_lock );
111
112        if( page_is_flag( page , PG_DIRTY) )
113        {
114                // clear dirty flag in page descriptor
115                page_clear_flag( page , PG_DIRTY );
116
117                // remove page from PPM dirty list
118                list_unlink( &page->list );
119                done = true;
120        }
121
122        // unlock the dirty_list
123        spinlock_unlock( &ppm->dirty_lock );
124
125        return done;
126}
127
128/////////////////////
129void sync_all_pages()
130{
131        page_t   * page;
132        ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
133
134        // lock the dirty_list
135        spinlock_lock( &ppm->dirty_lock );
136
137        while( !list_is_empty( &ppm->dirty_root ) )
138        {
139                page = LIST_FIRST( &ppm->dirty_root ,  page_t , list );
140
141                // unlock the dirty_list
142                spinlock_unlock( &ppm->dirty_lock );
143
144                // lock the page
145                page_lock( page );
146
147                // sync the page
148                vfs_mapper_move_page( page , false );  // from mapper
149
150                // unlock the page
151                page_unlock( page );
152
153                // lock the dirty_list
154                spinlock_lock( &ppm->dirty_lock );
155        }
156
157        // unlock the dirty_list
158        spinlock_unlock( &ppm->dirty_lock );
159
160}
161
162///////////////////////////////
163void page_lock( page_t * page )
164{
165        // take the spinlock protecting the PG_LOCKED flag
166        spinlock_lock( &page->lock );
167
168        if( page_is_flag( page , PG_LOCKED ) )  // page is already locked
169        {
170                // get pointer on calling thread
171                thread_t * thread = CURRENT_THREAD;
172
173                // register thread in the page waiting queue
174                xlist_add_last( XPTR( local_cxy , &page->wait_root ),
175                                XPTR( local_cxy , &thread->wait_list ) );
176
177                // release the spinlock
178                spinlock_unlock( &page->lock );
179
180                // deschedule the calling thread
181                thread_block( thread , THREAD_BLOCKED_PAGE );
182                sched_yield();
183        }
184        else                                    // page is not locked
185        {
186                // set the PG_LOCKED flag
187                page_set_flag( page , PG_LOCKED );
188
189                // release the spinlock
190                spinlock_unlock( &page->lock );
191        }
192}
193
194/////////////////////////////////
195void page_unlock( page_t * page )
196{
197        // take the spinlock protecting the PG_LOCKED flag
198        spinlock_lock( &page->lock );
199
200        // check the page waiting list
201        bool_t is_empty = xlist_is_empty( XPTR( local_cxy , &page->wait_root ) );
202
203        if( is_empty == false )    // at least one waiting thread => resume it
204        {
205                // get an extended pointer on the first waiting thread
206                xptr_t root_xp   = XPTR( local_cxy , &page->wait_root );
207                xptr_t thread_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );
208
209                // reactivate the first waiting thread
210                thread_unblock( thread_xp , THREAD_BLOCKED_PAGE );
211        }
212        else                      // no waiting thread => clear the PG_LOCKED flag
213        {
214                page_clear_flag( page , PG_LOCKED );
215        }
216
217        // release the spinlock
218        spinlock_unlock( &page->lock );
219}
220
221////////////////////////////////////////////
222inline void page_refcount_up( page_t *page )
223{
224    hal_atomic_add( &page->refcount , +1 );
225}
226
227//////////////////////////////////////////////
228inline void page_refcount_down( page_t *page )
229{
230    hal_atomic_add( &page->refcount , -1 );
231}
232
233///////////////////////////////
234void page_zero( page_t * page )
235{
236        uint32_t   size = (1 << page->order) * CONFIG_PPM_PAGE_SIZE;
237
238        xptr_t base_xp = ppm_page2base( XPTR( local_cxy , page ) );
239
240        memset( GET_PTR( base_xp ) , 0 , size );
241}
242
243////////////////////////////////
244void page_print( page_t * page )
245{
246        printk("*** Page %d : base = %x / flags = %x / order = %d / count = %d\n",
247                page->index,
248                GET_PTR( ppm_page2base( XPTR( local_cxy , page ) ) ),
249                page->flags,
250                page->order,
251                page->refcount );
252}
253
Note: See TracBrowser for help on using the repository browser.