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

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

First implementation of fork/exec.

File size: 6.1 KB
RevLine 
[1]1/*
2 * page.c - physical page related operations implementation
3 *
4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
[23]5 *          Alain Greiner    (2016,2017)
[1]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;
[23]46        page->mapper   = NULL;
[1]47        page->index    = 0;
[22]48        page->refcount = 0;
[23]49
[1]50        spinlock_init( &page->lock );
51        list_entry_init( &page->list );
[23]52    xlist_root_init( XPTR( local_cxy , &page->wait_root ) );
[1]53}
54
55////////////////////////////////////////////
56inline void page_set_flag( page_t   * page,
[23]57                           uint32_t   value )
[1]58{
[22]59        hal_atomic_or( (uint32_t *)&page->flags , (uint32_t)value );
[1]60}
61
62//////////////////////////////////////////////
63inline void page_clear_flag( page_t   * page,
[23]64                             uint32_t   value )
[1]65{
[22]66        hal_atomic_and( (uint32_t *)&page->flags , ~((uint32_t)value) );
[1]67}
68
69//////////////////////////////////////////////
70inline bool_t page_is_flag( page_t   * page,
[23]71                            uint32_t   value )
[1]72{
[23]73    return ( (page->flags & value) ? 1 : 0 );
[1]74}
75
76//////////////////////////////////////
77bool_t page_do_dirty( page_t * page )
78{
79        bool_t done = false;
80
[22]81        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[1]82
[22]83        // lock the PPM dirty_list
[1]84        spinlock_lock( &ppm->dirty_lock );
85
86        if( !page_is_flag( page , PG_DIRTY ) )
87        {
[22]88                // set dirty flag in page descriptor
[1]89                page_set_flag( page , PG_DIRTY );
[18]90
[22]91                // register page in PPM dirty list
[1]92                list_add_first( &ppm->dirty_root , &page->list );
93                done = true;
94        }
95
[22]96        // unlock the PPM dirty_list
[1]97        spinlock_unlock( &ppm->dirty_lock );
[18]98
[1]99        return done;
100}
101
102////////////////////////////////////////
103bool_t page_undo_dirty( page_t * page )
104{
105        bool_t done = false;
106
[22]107        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[1]108
[22]109        // lock the dirty_list
[1]110        spinlock_lock( &ppm->dirty_lock );
111
112        if( page_is_flag( page , PG_DIRTY) )
113        {
[22]114                // clear dirty flag in page descriptor
[1]115                page_clear_flag( page , PG_DIRTY );
116
[22]117                // remove page from PPM dirty list
[1]118                list_unlink( &page->list );
119                done = true;
120        }
121
[22]122        // unlock the dirty_list
[1]123        spinlock_unlock( &ppm->dirty_lock );
124
125        return done;
126}
127
128/////////////////////
[18]129void sync_all_pages()
[1]130{
131        page_t   * page;
[22]132        ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
[1]133
[22]134        // lock the dirty_list
[1]135        spinlock_lock( &ppm->dirty_lock );
136
[18]137        while( !list_is_empty( &ppm->dirty_root ) )
[1]138        {
139                page = LIST_FIRST( &ppm->dirty_root ,  page_t , list );
140
[22]141                // unlock the dirty_list
142                spinlock_unlock( &ppm->dirty_lock );
[1]143
[22]144                // lock the page
[1]145                page_lock( page );
146
[22]147                // sync the page
[238]148                vfs_mapper_move_page( page , false );  // from mapper
[1]149
[22]150                // unlock the page
[1]151                page_unlock( page );
152
[22]153                // lock the dirty_list
154                spinlock_lock( &ppm->dirty_lock );
[1]155        }
156
[22]157        // unlock the dirty_list
[1]158        spinlock_unlock( &ppm->dirty_lock );
159
[22]160}
[1]161
162///////////////////////////////
163void page_lock( page_t * page )
164{
[22]165        // take the spinlock protecting the PG_LOCKED flag
[1]166        spinlock_lock( &page->lock );
167
168        if( page_is_flag( page , PG_LOCKED ) )  // page is already locked
169        {
[22]170                // get pointer on calling thread
171                thread_t * thread = CURRENT_THREAD;
[1]172
[22]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 ) );
[1]176
[22]177                // release the spinlock
[1]178                spinlock_unlock( &page->lock );
179
[22]180                // deschedule the calling thread
181                thread_block( thread , THREAD_BLOCKED_PAGE );
[407]182                sched_yield();
[1]183        }
184        else                                    // page is not locked
185        {
[22]186                // set the PG_LOCKED flag
[1]187                page_set_flag( page , PG_LOCKED );
188
[22]189                // release the spinlock
[1]190                spinlock_unlock( &page->lock );
191        }
192}
193
194/////////////////////////////////
195void page_unlock( page_t * page )
196{
[22]197        // take the spinlock protecting the PG_LOCKED flag
[1]198        spinlock_lock( &page->lock );
[18]199
[22]200        // check the page waiting list
[1]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
[22]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 );
[1]208
[22]209                // reactivate the first waiting thread
210                thread_unblock( thread_xp , THREAD_BLOCKED_PAGE );
211        }
[1]212        else                      // no waiting thread => clear the PG_LOCKED flag
213        {
[22]214                page_clear_flag( page , PG_LOCKED );
215        }
[1]216
[22]217        // release the spinlock
[1]218        spinlock_unlock( &page->lock );
219}
220
221////////////////////////////////////////////
222inline void page_refcount_up( page_t *page )
223{
[23]224    hal_atomic_add( &page->refcount , +1 );
[1]225}
226
227//////////////////////////////////////////////
228inline void page_refcount_down( page_t *page )
229{
[23]230    hal_atomic_add( &page->refcount , -1 );
[1]231}
232
233///////////////////////////////
234void page_zero( page_t * page )
235{
[315]236        uint32_t   size = (1 << page->order) * CONFIG_PPM_PAGE_SIZE;
[1]237
[315]238        xptr_t base_xp = ppm_page2base( XPTR( local_cxy , page ) );
[1]239
[315]240        memset( GET_PTR( base_xp ) , 0 , size );
[1]241}
242
243////////////////////////////////
244void page_print( page_t * page )
245{
246        printk("*** Page %d : base = %x / flags = %x / order = %d / count = %d\n",
[18]247                page->index,
[315]248                GET_PTR( ppm_page2base( XPTR( local_cxy , page ) ) ),
[18]249                page->flags,
250                page->order,
[1]251                page->refcount );
252}
253
Note: See TracBrowser for help on using the repository browser.